Skip to content

TeraChem

qccompute.adapters.terachem.TeraChemAdapter

Adapter for TeraChem.

supported_calctypes = [CalcType.energy, CalcType.gradient, CalcType.hessian, CalcType.optimization] class-attribute instance-attribute

Supported calculation types.

program_version(stdout: str | None = None) -> str

Get the program version.

Parameters:

Name Type Description Default
stdout str | None

The stdout from the program.

None

Returns:

Type Description
str

The program version.

Source code in src/qccompute/adapters/terachem.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
def program_version(self, stdout: str | None = None) -> str:
    """Get the program version.

    Args:
        stdout: The stdout from the program.

    Returns:
        The program version.
    """
    if stdout:
        try:
            return parse_version(stdout)
        except qccodec_exceptions.ParserError:
            # If the version string is not found. Happens when libcuda.so is not
            # found and TeraChem fails to start. terachem --version will fail too.
            return "Could not parse version"
    else:
        try:
            return execute_subprocess(self.program, ["--version"])[17:]
        except ExternalProgramError:
            return "Could not determine version"

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

Execute TeraChem on the given input.

Parameters:

Name Type Description Default
input_data ProgramInput

The qcdata ProgramInput object for a computation.

required
update_func Callable | None

A callback function to call as the program executes.

None
update_interval float | None

The minimum time in seconds between calls to the update_func.

None

Returns:

Type Description
tuple[SinglePointData, str]

A tuple of SinglePointData and the stdout str.

Source code in src/qccompute/adapters/terachem.py
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 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
def compute_data(
    self,
    input_data: ProgramInput,
    update_func: Callable | None = None,
    update_interval: float | None = None,
    **kwargs,
) -> tuple[SinglePointData, str]:
    """Execute TeraChem on the given input.

    Args:
        input_data: The qcdata ProgramInput object for a computation.
        update_func: A callback function to call as the program executes.
        update_interval: The minimum time in seconds between calls to the
            update_func.

    Returns:
        A tuple of SinglePointData and the stdout str.
    """
    # Construct TeraChem native input files
    try:
        native_input = qccodec.encode(input_data, self.program)
    except qccodec.exceptions.EncoderError as e:
        raise AdapterInputError(program=self.program) from e

    # Write the input files to disk
    input_filename = "tc.in"
    Path(input_filename).write_text(native_input.input_file)
    Path(native_input.geometry_filename).write_text(native_input.geometry_file)

    # Execute TeraChem
    stdout = execute_subprocess(
        self.program, [input_filename], update_func, update_interval
    )

    # Get the scratch output directory
    parent = Path.cwd()
    # TeraChem creates a directory named scr<xyz_filename> in the current working
    scr_dir = next(parent.glob("scr*"), None)
    if scr_dir is None:
        raise ExternalProgramError(
            self.program, f"TeraChem did not create a 'scr' directory in {parent}."
        )

    # Parse output
    try:
        results = qccodec.decode(
            self.program,
            input_data.calctype,
            stdout=stdout,
            directory=scr_dir,
            input_data=input_data,
        )
    except qccodec_exceptions.ParserError as e:
        raise ExternalProgramError(
            program="qccodec",
            message="Failed to parse TeraChem output.",
            logs=stdout,
            original_exception=e,
        ) from e
    return results, stdout

collect_wfn() -> dict[str, str | bytes]

Append wavefunction data to the output.

Source code in src/qccompute/adapters/terachem.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
def collect_wfn(self) -> dict[str, str | bytes]:
    """Append wavefunction data to the output."""

    # Naming conventions from TeraChem uses xyz filename as scratch dir postfix
    scr_dir = next(Path().glob("scr*"), None)
    if not scr_dir:
        raise AdapterError(
            "No scratch directory found for wavefunction collection."
        )
    # Wavefunction filenames
    wfn_filenames = ("c0", "ca0", "cb0")
    wfn_paths = [scr_dir / fn for fn in wfn_filenames]
    if not any(wfn_path.exists() for wfn_path in wfn_paths):
        raise AdapterError(f"No wavefunction files found in {Path.cwd()}")

    wfns: dict[str, str | bytes] = {}
    for wfn_path in wfn_paths:
        if wfn_path.exists():
            wfns[str(wfn_path)] = wfn_path.read_bytes()
    return wfns

propagate_wfn(output: ProgramOutput[ProgramInput, SinglePointData], program_input: ProgramInput) -> None

Propagate the wavefunction from the previous calculation.

Parameters:

Name Type Description Default
output ProgramOutput[ProgramInput, SinglePointData]

The output from a previous calculation containing wavefunction data.

required
program_input ProgramInput

The ProgramInput object on which to place the wavefunction data.

required

Returns:

Type Description
None

None. Modifies the program_input object in place.

Source code in src/qccompute/adapters/terachem.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
def propagate_wfn(
    self,
    output: ProgramOutput[ProgramInput, SinglePointData],
    program_input: ProgramInput,
) -> None:
    """Propagate the wavefunction from the previous calculation.

    Args:
        output: The output from a previous calculation containing wavefunction data.
        program_input: The ProgramInput object on which to place the wavefunction data.

    Returns:
        None. Modifies the program_input object in place.
    """

    # Wavefunction filenames
    suffixes = ("c0", "ca0", "cb0")
    matches = {}
    for k, v in output.data.files.items():
        for suffix in suffixes:
            if k.endswith(suffix):
                matches[suffix] = v

    if not "c0" in matches and not ("ca0" in matches and "cb0" in matches):
        raise AdapterInputError(
            program=self.program,
            message="Could not find c0 or ca/b0 files in output.",
        )

    # Load wavefunction data onto ProgramInput object

    if "c0" in matches:
        program_input.files["c0"] = matches["c0"]
        program_input.keywords["guess"] = "c0"

    else:  # ca0_bytes and cb0_bytes
        assert "ca0" in matches and "cb0" in matches  # for mypy
        program_input.files["ca0"] = matches["ca0"]
        program_input.files["cb0"] = matches["cb0"]
        program_input.keywords["guess"] = "ca0 cb0"

qccompute.adapters.terachem_fe.TeraChemFEAdapter()

Adapter for TeraChem's Protocol Buffer Server and Frontend file server.

Source code in src/qccompute/adapters/terachem_fe.py
18
19
20
21
22
def __init__(self):
    super().__init__()
    # Check that xtb-python is installed.
    self.tcpb = self._ensure_tcpb()
    self.client = self.tcpb.TCFrontEndClient

supported_calctypes = [CalcType.energy, CalcType.gradient] class-attribute instance-attribute

Supported calculation types.

program_version(stdout: str | None = None) -> str

Program version is not available via the PB server.

Source code in src/qccompute/adapters/terachem_fe.py
38
39
40
def program_version(self, stdout: str | None = None) -> str:
    """Program version is not available via the PB server."""
    return ""

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

Execute TeraChem on the given input.

Parameters:

Name Type Description Default
input_data ProgramInput

The qcdata ProgramInput object for a computation.

required
update_func Callable | None

A callback function to call as the program executes.

None
update_interval float | None

The minimum time in seconds between calls to the update_func.

None

Returns:

Type Description
tuple[SinglePointData, str]

A tuple of SinglePointData and the stdout str.

Source code in src/qccompute/adapters/terachem_fe.py
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def compute_data(
    self,
    input_data: ProgramInput,
    update_func: Callable | None = None,
    update_interval: float | None = None,
    **kwargs,
) -> tuple[SinglePointData, str]:
    """Execute TeraChem on the given input.

    Args:
        input_data: The qcdata ProgramInput object for a computation.
        update_func: A callback function to call as the program executes.
        update_interval: The minimum time in seconds between calls to the
            update_func.

    Returns:
        A tuple of SinglePointData and the stdout str.
    """
    try:
        with self.client() as client:
            prog_output = client.compute(input_data)
    except self.tcpb.exceptions.TCPBError as e:
        exc = ExternalProgramError(
            program=self.program,
            # Pass logs to .compute() via the exception
            # Will only exist for TeraChemFrontendAdapter
            logs=e.prog_output.logs,
        )

        raise exc

    else:
        # Write files to disk to be collected by BaseAdapter.compute()
        # Used only for TeraChemFrontendAdapter
        prog_output.data.save_files()

    return prog_output.data, prog_output.logs

qccompute.adapters.terachem_pbs.TeraChemPBSAdapter()

Adapter for TeraChem's Protocol Buffer Server.

Source code in src/qccompute/adapters/terachem_pbs.py
 9
10
11
12
13
def __init__(self):
    super().__init__()
    # Check that tcpb is installed.
    self.tcpb = self._ensure_tcpb()
    self.client = self.tcpb.TCProtobufClient