Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
125f439
add from_string method for simple keywords
nakul680 Feb 25, 2026
665e5d3
registry
nakul680 Mar 2, 2026
aa9d68f
task params class, simple keyword lookup
nakul680 Mar 16, 2026
1796784
minimal implementation of Simple Tasks
nakul680 Mar 25, 2026
9fa47b5
flesh out structure of base Task classes
nakul680 Mar 25, 2026
dac75a2
added field validator for assignment and overloaded getters and sette…
nakul680 Mar 27, 2026
038e98c
added restart function, optimized duplicate code
nakul680 Mar 30, 2026
e1cb6ab
added docstrings , renamed TaskParams to Settings, added TaskSettings…
nakul680 Apr 1, 2026
0adf343
changes from todays meeting
nakul680 Apr 13, 2026
c009bfc
flesh out the different tasks
nakul680 Apr 15, 2026
5a8a881
example for simple task
nakul680 Apr 22, 2026
525af5f
api changes
nakul680 Apr 22, 2026
ebf38ea
fixed nox errors
nakul680 Apr 24, 2026
196c3c1
correct run() method for OptTask
nakul680 Apr 29, 2026
569b2b6
alternate API for initializing method settings
nakul680 Apr 27, 2026
6a4cbd5
added possibility to switch methods between families, dicct now allow…
nakul680 Apr 29, 2026
022dac6
add goat task, flesh out sqmsettings and add dlpnoccsettings
nakul680 May 6, 2026
8887d46
added documentation
nakul680 May 11, 2026
5cb47e1
add unit tests
nakul680 May 13, 2026
d741c80
added examples for simple tasks
nakul680 May 18, 2026
6e75dac
add from_string() method
nakul680 May 18, 2026
812d290
add unit tests for SimpleTask.from_string()
nakul680 May 20, 2026
eabdb09
fix:allow users to freely edit SimpleTask.input_object
nakul680 Jun 1, 2026
810ff7c
fix: add final_energy property to case TaskResults class
nakul680 Jun 1, 2026
234e99b
fix: renamed simple tasks folder
nakul680 Jun 1, 2026
6852399
fix: reorder simple tasks examples on complexity
nakul680 Jun 1, 2026
858d094
fix: separate tasks into their own folders
nakul680 Jun 1, 2026
fb9f758
fix: edit __init__ file of simple tasks subfolders to allow for easy …
nakul680 Jun 1, 2026
87b40aa
docs: add documentation to SimpleKeyword
nakul680 Jun 1, 2026
a40f634
fix: fix code formatting and extra imports
nakul680 Jun 1, 2026
e8c2c1f
fix: move all implemented simple tasks to task folder
nakul680 Jun 3, 2026
f0c1d7f
fix:changed __add__() to __or__() for merging of Block objects.
nakul680 Jun 3, 2026
ef37088
fix: remove registries from SimpleKeywordBox classes.
nakul680 Jun 3, 2026
d0d96d9
fix: remove dead attribute `name` from `SimpleKeyword` and store alia…
nakul680 Jun 3, 2026
4971a00
docs: add documentation for get_subclass_by_name() in `Block`
nakul680 Jun 3, 2026
3abe614
fix:add example for user modification of input_object in SimpleTask o…
nakul680 Jun 3, 2026
63a8ab7
fix:add input_object init to SimpleTask init
nakul680 Jun 3, 2026
7723a91
fix: give preference to user input settings over data that exists in …
nakul680 Jun 17, 2026
c21e797
fix:refactor variables in `Block.get_subclasses_by_name()`
nakul680 Jun 17, 2026
66cf5af
fix: refactor variables and correct docstrings in `SimpleKeywordBox` …
nakul680 Jun 17, 2026
1b84e1d
fix: add documentation to improve code clarity
nakul680 Jun 22, 2026
1736aa7
fix: change type annotation in DlpnoCcSettings
nakul680 Jun 22, 2026
b833ff0
fix: edit examples to take into account new examples
nakul680 Jun 22, 2026
abac0c2
fix: add __init__() of OptTask that was mistakenly removed
nakul680 Jun 22, 2026
fe4d015
fix:add input_object init to SimpleTask init
nakul680 Jun 3, 2026
71ce3d4
fix:remove overridden constructors in SimpleTasks and allow init of S…
nakul680 Jun 17, 2026
92a1c81
fix: remove unused imports
nakul680 Jun 24, 2026
6bbbca1
fix: change leftoover cached properties into properties and update co…
nakul680 Jun 24, 2026
c66d29c
fix: add documentation to functions in `SimpleTask` class
nakul680 Jun 24, 2026
8e568b9
fix: add documentation for task settings type getter
nakul680 Jun 24, 2026
fc201cb
fix: rename `input_object` to `input` and `calc_object` to `calculator`
nakul680 Jul 7, 2026
a8a52fe
fix: change working_dir type annotations to include strings
nakul680 Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ python3 job.py
- exmp016_autoci: Use AUTO-CI to run CISD/def2-SVP single-point
- exmp017_roci: Perform a ROCIS calculation
- exmp018_cipsi: Perform a ICE-CI calculation
- exmp019_engrad: Perfrom an energy & gradient calculation with r²SCAN-3c
- exmp019_engrad: Perform an energy & gradient calculation with r²SCAN-3c
- exmp020_smd: Run a r²SCAN-3c+SMD(Water) calculation
- exmp021_basis: Run a BP86/def2-SVP energy calculation with additional diffuse function for oxygen
- exmp022_scf_block: Run a PBE0/def2-SVP energy calculation and rotate the initial SCF guess
Expand All @@ -59,7 +59,7 @@ python3 job.py
- exmp036_solvator: Run ORCAs autosolvation workflow (solvator)
- exmp037_s2: Get the S² expectation value from an unrestricted calculation
- exmp038_integrals: Get integrals from a calculation
- exmp039_neb: Perfrom a transition state search with NEB
- exmp039_neb: Perform a transition state search with NEB
- exmp040_xzyfraglib: Assign fragments with external fragment library (frag_lib.xyz)
- exmp041_graph: How to print overview of the available results in output
- exmp042_element: Access cardinal numbers of a structure
Expand All @@ -73,5 +73,9 @@ python3 job.py
- exmp050_docker: Use DOCKER to dock water with water
- exmp051_libxc: Shows modification of DFT LibXC parameters via the method block
- exmp052_densities: Perform UHF calculation and obtain density and spin-density in AO-basis
- exmp053_opencosmors: Run OpenCOSMO-RS task

- exmp053_opencosmors: Run OpenCOSMO-RS task
- exmp057_singlepoint_simpletask: B3LYP/def2-SVP single-point with CPCM(water) using the `SinglePointTask` functionality
- exmp058_engrad_simpletask: r²SCAN-3c energy & gradient calculation using the `EngradTask` functionality
- exmp059_opt_simpletask: B3LYP/def2-SVP geometry optimization with CPCM(water) using the `OptTask` functionality
- exmp060_freq_simpletask: TPSS/def2-SVP frequency calculation using the `FreqTask` functionality
- exmp061_goat_simpletask: GFN2-xTB GOAT conformer search using the `GoatTask` functionality
5 changes: 5 additions & 0 deletions examples/exmp057_singlepoint_simpletask/inp.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3

O -3.56626 1.77639 0.00000
H -2.59626 1.77639 0.00000
H -3.88959 1.36040 -0.81444
43 changes: 43 additions & 0 deletions examples/exmp057_singlepoint_simpletask/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env python3
import sys
from pathlib import Path

from opi.input.simple_keywords import AtomicCharge
from opi.input.structures import Structure
from opi.simple_tasks import SinglePointResults, SinglePointTask


def run_exmp057(
structure: Structure | None = None, working_dir: Path = Path("RUN")
) -> SinglePointResults:
# > if no structure is given read structure from inp.xyz
if structure is None:
structure = Structure.from_xyz("inp.xyz")

# > set up the task
simple_task = SinglePointTask(
method="b3lyp", basis_set="def2-svp", solvation_model="cpcm", solvent="water"
)
# > there are task and method-specific settings, these can be set through kwargs

# > It is possible to modify the input object associated with the task object for more specific settings
simple_task.input.add_simple_keywords(AtomicCharge.HIRSHFELD)

# > run the calculation with given data
singlepoint_result = simple_task.run("job", structure, working_dir=working_dir)

# > check if the ORCA calculation terminated normally
if not singlepoint_result.status:
print("SinglePoint task failed")
sys.exit(1)

# > extract primary property from the `TaskResults` object. For a single point calculation, it is the final energy.
final_energy = singlepoint_result.final_energy
Comment thread
nakul680 marked this conversation as resolved.

print(f"Final single point energy: {final_energy: 10f} Eh")

return singlepoint_result


if __name__ == "__main__":
run_exmp057()
5 changes: 5 additions & 0 deletions examples/exmp058_engrad_simpletask/inp.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3

O -3.56626 1.77639 0.00000
H -2.59626 1.77639 0.00000
H -3.88959 1.36040 -0.81444
32 changes: 32 additions & 0 deletions examples/exmp058_engrad_simpletask/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
import sys
from pathlib import Path

from opi.input.structures import Structure
from opi.simple_tasks import EngradResults, EngradTask


def run_exmp058(
structure: Structure | None = None, working_dir: Path = Path("RUN")
) -> EngradResults:
# > if no structure is given read structure from inp.xyz
if structure is None:
structure = Structure.from_xyz("inp.xyz")

engrad_task = EngradTask(method="r2scan-3c")
engrad_result = engrad_task.run("job", structure, working_dir=working_dir)

if not engrad_result.status:
print(f"Engrad task failed, see output file: {engrad_result.output.get_outfile()}")
sys.exit(1)

print("FINAL SINGLE POINT ENERGY")
print(engrad_result.final_energy)
print("SCF ENERGY")
print(engrad_result.output.get_energies()["SCF"])

return engrad_result


if __name__ == "__main__":
run_exmp058()
10 changes: 10 additions & 0 deletions examples/exmp059_opt_simpletask/inp.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
8
Coordinates from ORCA-job job E -79.174339553991
C -0.07696488620844 0.00264225043565 0.01503449747601
C 1.42297403167085 0.00026730705255 0.00170779972564
H -0.52956432516482 0.16759451146808 0.99517342002418
H -0.47206799721260 0.78060586812661 -0.64348212080303
H -0.47202276565405 -0.94827280862626 -0.35199393102178
H 1.83370076026311 0.95190889480824 0.34680814012902
H 1.83362978930886 -0.78232192510389 0.64382744884855
H 1.80356539299709 -0.17242409816099 -1.00707525437860
44 changes: 44 additions & 0 deletions examples/exmp059_opt_simpletask/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
import sys
from pathlib import Path

from opi.input.structures import Structure
from opi.simple_tasks import OptResults, OptSettings, OptTask
from opi.simple_tasks.method_settings import DftSettings


def run_exmp059(structure: Structure | None = None, working_dir: Path = Path("RUN")) -> OptResults:
# > if no structure is given read structure from inp.xyz
if structure is None:
structure = Structure.from_xyz("../exmp057_singlepoint_simpletask/inp.xyz")

# > set up the task
simple_task = OptTask(
Comment thread
haneug marked this conversation as resolved.
method="b3lyp",
basis_set="def2-svp",
solvation_model="cpcm",
solvent="water",
method_settings=DftSettings(scf_maxiter=150),
task_settings=OptSettings(opt_threshold="tight"),
)
# > there are task and method-specific settings, these can be set through kwargs

# > run the calculation with given data
opt_result = simple_task.run("job", structure, working_dir=working_dir)

# > check if the ORCA calculation terminated normally
if not opt_result.status:
print("Opt task failed")
sys.exit(1)

# > extract optimized structure from the `OptResults` object
structure = opt_result.structure

print("Optimized Structure:")
print(structure.format_orca())

return opt_result


if __name__ == "__main__":
run_exmp059()
5 changes: 5 additions & 0 deletions examples/exmp060_freq_simpletask/inp.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
3

O -3.56626 1.77639 0.00000
H -2.59626 1.77639 0.00000
H -3.88959 1.36040 -0.81444
51 changes: 51 additions & 0 deletions examples/exmp060_freq_simpletask/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
import sys
from pathlib import Path

from opi.input.structures import Structure
from opi.output.ir_mode import IrMode
from opi.simple_tasks import FreqResults, FreqTask


def run_exmp060(structure: Structure | None = None, working_dir: Path = Path("RUN")) -> FreqResults:
# > if no structure is given read structure from inp.xyz
if structure is None:
structure = Structure.from_xyz("inp.xyz")

freq_task = FreqTask(method="tpss", basis_set="def2-svp")
freq_result = freq_task.run("job", structure, working_dir=working_dir)

if not freq_result.status:
print(f"Freq task failed, see output file: {freq_result.output.get_outfile()}")
sys.exit(1)

output = freq_result.output

ir_dict = output.get_ir()
print(IrMode.header())
for ir_mode in ir_dict.values():
print(ir_mode)

ngeoms = len(output.results_properties.geometries)
print("N GEOMETRIES")
print(ngeoms)
print("FINAL SINGLE POINT ENERGY")
print(output.get_final_energy())
print("Temperature [K]")
print(output.results_properties.geometries[0].thermochemistry_energies[0].temperature)
print("Final Gibbs free energy")
print(output.get_free_energy())
print("Zero-point energy")
print(output.get_zpe())
print("Final enthalpy H")
print(output.get_enthalpy())
print("Final entropy S")
print(output.get_entropy())
print("G-E(el)")
print(freq_result.free_energy_delta)

return freq_result


if __name__ == "__main__":
run_exmp060()
10 changes: 10 additions & 0 deletions examples/exmp061_goat_simpletask/inp.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
8
Coordinates from ORCA-job job E -79.174339553991
C -0.07696488620844 0.00264225043565 0.01503449747601
C 1.42297403167085 0.00026730705255 0.00170779972564
H -0.52956432516482 0.16759451146808 0.99517342002418
H -0.47206799721260 0.78060586812661 -0.64348212080303
H -0.47202276565405 -0.94827280862626 -0.35199393102178
H 1.83370076026311 0.95190889480824 0.34680814012902
H 1.83362978930886 -0.78232192510389 0.64382744884855
H 1.80356539299709 -0.17242409816099 -1.00707525437860
39 changes: 39 additions & 0 deletions examples/exmp061_goat_simpletask/job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
#!/usr/bin/env python3
import sys
from pathlib import Path

from opi.input.structures import Properties, Structure
from opi.simple_tasks import GoatSettings, GoatTask


def run_exmp061(
structure: Structure | None = None, working_dir: Path = Path("RUN")
) -> tuple[list[Structure], list[Properties]]:

# > if no structure is given read structure from inp.xyz
if structure is None:
structure = Structure.from_xyz("inp.xyz")

goat_settings = GoatSettings(goat_maxiter=128, goat_explore=True)
goat_task = GoatTask("gfn2-xtb", task_settings=goat_settings)

goat_result = goat_task.run("job", structure, working_dir=working_dir, ncores=4)

# > check if the ORCA calculation terminated normally
if not goat_result.status:
print("GOAT task failed")
sys.exit(1)

structures, properties_list = goat_result.primary_property

# > Print structures that were read
for structure, properties in zip(structures, properties_list):
print(f"FINAL ENERGY: {properties.energy_total}")
print(structure.to_xyz_block())

return structures, properties_list


if __name__ == "__main__":
run_exmp061()
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ markers = [
"input: input side unit tests",
"unit: unit tests",
"json_files: Export JSON files with --update-json-files",
"simpletasks: simpletasks unit tests",
]


Expand Down
60 changes: 60 additions & 0 deletions src/opi/input/blocks/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,25 @@ def format_orca(self) -> str:

return s

def __or__(self, other: "Block") -> "Block":
"""
Merges two instances of `Block`. If a common attribute exists in both `self` and `other`, the value in `other` will be given precedence.
Parameters
----------
other: Block
Instance of `Block` to be merged into `self`

Returns
-------
Block
New instance of `Block` with attributes of `self` and `other`.

"""
new_block = self.__class__.model_validate(
Comment thread
nakul680 marked this conversation as resolved.
{**self.model_dump(exclude_none=True), **other.model_dump(exclude_none=True)}
)
return new_block

@property
def name(self) -> str:
return self._name
Expand All @@ -189,3 +208,44 @@ def init_inputpath(cls, inp: Any) -> Any:
return InputFilePath(file=inp)
else:
return inp

@classmethod
def get_subclass_by_name(cls, name: str) -> type["Block"]:
"""
Look up a ``Block`` subclass by its class name or ORCA block name.

Matching is case-insensitive and checks both the Python class name
(e.g. ``"BlockScf"``) and the ORCA block name returned by the
subclass's ``name`` property (e.g. ``"scf"``).

Parameters
----------
name : str
Class name or ORCA block name of the desired subclass.

Returns
-------
type[Block]
The matching subclass.

Raises
------
ValueError
If no subclass matches ``name``.
"""
# Search for `Block` class by OPI name
opi_block_name_matches = {sub.__name__.lower(): sub for sub in cls.__subclasses__()}
# Search for `Block` class by ORCA block name
orca_block_name_matches = {sub().name.lower(): sub for sub in cls.__subclasses__()}
# Collect matches across both criteria
all_matches = opi_block_name_matches.get(name.lower()) or orca_block_name_matches.get(
name.lower()
)

# If no match is found, raise ValueError
if all_matches is None:
raise ValueError(
f"No Block subclass found with name {name!r}. Available: {list(opi_block_name_matches.keys())}"
)

return all_matches
2 changes: 1 addition & 1 deletion src/opi/input/blocks/block_ice.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ class BlockIce(Block):
etol: float | None = None
icetype: Literal["CFGs", "CSFs", "DETs"] | None = None
# > algorithm details
integrals: Literal["exact", "ri"] | None
integrals: Literal["exact", "ri"] | None = None
Loading