Skip to content

geomeTRIC

qccompute.adapters.geometric.GeometricAdapter()

Adapter for geomeTRIC.

Source code in src/qccompute/adapters/geometric.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
def __init__(self):
    super().__init__()
    # Check that geomeTRIC is installed
    self.geometric = self._ensure_geometric_installed()
    # Dictionary from geometric.run_json; copying QCSchema workflow
    self.coordsys_params = {
        "cart": (self.geometric.internal.CartesianCoordinates, False, False),
        "prim": (self.geometric.internal.PrimitiveInternalCoordinates, True, False),
        "dlc": (
            self.geometric.internal.DelocalizedInternalCoordinates,
            True,
            False,
        ),
        "hdlc": (
            self.geometric.internal.DelocalizedInternalCoordinates,
            False,
            True,
        ),
        "tric": (
            self.geometric.internal.DelocalizedInternalCoordinates,
            False,
            False,
        ),
    }

supported_calctypes = [CalcType.optimization, CalcType.transition_state] class-attribute instance-attribute

Supported calculation types.

program_version(*args) -> str

Get the program version.

Source code in src/qccompute/adapters/geometric.py
72
73
74
def program_version(self, *args) -> str:
    """Get the program version."""
    return self.geometric.__version__

compute_data(input_data: ProgramInput, update_func: Callable | None = None, update_interval: float | None = None, propagate_wfn: bool = True, **kwargs) -> tuple[OptimizationData, str]

Compute the requested calculation.

Parameters:

Name Type Description Default
input_data ProgramInput

The qcdata ProgramInput object for a computation.

required
propagate_wfn bool

Whether to propagate the wavefunction between steps of the optimization.

True
Source code in src/qccompute/adapters/geometric.py
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
def compute_data(
    self,
    input_data: ProgramInput,
    update_func: Callable | None = None,
    update_interval: float | None = None,
    propagate_wfn: bool = True,
    **kwargs,
) -> tuple[OptimizationData, str]:
    """Compute the requested calculation.

    Args:
        input_data: The qcdata ProgramInput object for a computation.
        propagate_wfn: Whether to propagate the wavefunction between steps of the
            optimization.
    """
    # geomeTRIC setup mutates keywords (for example by removing constraints), so
    # operate on an internal copy and preserve the caller's original input object.
    input_data = input_data.model_copy(deep=True)

    try:
        gradient_spec = input_data.get_subprogram(CalcType.gradient)
    except ValueError as exc:
        raise AdapterInputError(self.program, str(exc)) from exc

    # Update the input object based on its calctype
    self._update_input_data(input_data)
    geometric_molecule = self._create_geometric_molecule(input_data.structure)
    internal_coords_sys = self._setup_coords(input_data, geometric_molecule)
    qcdata_adapter = get_adapter(gradient_spec.program, qcng_fallback=True)
    optimizer = self._construct_optimizer(
        input_data,
        geometric_molecule,
        internal_coords_sys,
        qcdata_adapter,
        propagate_wfn=propagate_wfn,
        update_func=update_func,
        update_interval=update_interval,
        **kwargs,
    )

    # Haven't update DualOutputHandler to send logs using arbitrary update funcs.
    with capture_logs("geometric", update_func, update_interval) as (_, log_string):
        try:
            optimizer.optimizeGeometry()
        except QCComputeBaseError as exc:
            raise ExternalProgramError(
                program=self.program,
                message="A child calculation failed during geomeTRIC optimization.",
                logs=log_string.getvalue(),
                data=exc.data,
                original_exception=exc,
            ) from exc
        except self.geometric.errors.Error as e:
            raise ExternalProgramError(
                program=self.program,
                message="geomeTRIC optimization failed. See the traceback above for details.",
                logs=log_string.getvalue(),
                data=OptimizationData(
                    provenance=Provenance(
                        program=self.program, program_version=self.program_version()
                    ),
                    trajectory=optimizer.engine.qcdata_trajectory,
                ),
            ) from e

    return (
        OptimizationData(
            provenance=Provenance(
                program=self.program, program_version=self.program_version()
            ),
            trajectory=optimizer.engine.qcdata_trajectory,
        ),
        log_string.getvalue(),
    )

Recursive program input

from qcdata import ProgramInput, ProgramSpec, Structure
from qccompute import compute

structure = Structure.open("molecule.xyz")
input_data = ProgramInput(
    program="geometric",
    calctype="optimization",
    structure=structure,
    keywords={"maxiter": 250},
    subprograms=[
        ProgramSpec(
            program="terachem",
            calctype="gradient",
            model={"method": "wb97x-d3", "basis": "def2-svp"},
        ),
    ],
)
output = compute(input_data)
output.results.final_structure
output.results.trajectory[0].results.provenance  # Gradient producer
output.execution.wall_time  # Optimizer execution time

Each child has its own model, keywords, native files, command-line arguments, and metadata. Additional role-named structures are passed to child calculations.