Skip to content

Inputs

Data structures for specifying quantum chemistry calculations. The most commonly used structure is a ProgramInput which defines a single calculation.

The hierarchy is Files → FileInput → ProgramSpec → ProgramInput. Every input requires program, the requested executor; ProgramOutput.results.provenance.program records the program that actually produced the result.

ProgramSpec describes a calculation without structures. It has its own program, calctype, optional model, keywords, files, cmdline_args, extras, and recursive subprograms. Model remains a distinct scientific concept with method and basis. A program without a meaningful model, such as an optimizer, can leave model=None.

from qcdata import CalcType, ProgramInput, ProgramSpec, Structure

input_data = ProgramInput(
    program="geometric",
    calctype="optimization",
    structure=Structure.open("structure.xyz"),
    keywords={"maxiter": 250},
    subprograms=[
        ProgramSpec(
            program="terachem",
            calctype="gradient",
            model={"method": "wb97x-d3", "basis": "def2-svp"},
            keywords={"convthre": 1e-6},
        ),
    ],
)
gradient_spec = input_data.get_subprogram(CalcType.gradient)

Children can contain further subprograms to arbitrary depth. Each immediate child must have a unique CalcType among its siblings. get_subprogram(calctype) accepts a CalcType or its string value (for example, CalcType.gradient or "gradient"), searches immediate children only, and raises ValueError if missing.

Inputs is FileInput | ProgramInput. Use ProgramInput directly for structured inputs. A ProgramSpec alone is not a top-level input because it lacks structures. Use structure for the constructor argument and attribute; the former molecule API has been removed.

This replaces ProgramArgs, ProgramArgsSub, and DualProgramInput without compatibility aliases. Migrate subprogram and subprogram_args to a subprograms list with an explicit program and calctype on each child. Existing serialized inputs also need these fields. QCSchema AtomicInput conversion requires a non-None model and raises ValueError otherwise.

ProgramInput.structure is always the primary/start/reference structure for the calculation. Calculations that require additional complete structures can provide them by role name with ProgramInput.structures, for example structures={"product": product_structure} for a nudged elastic band calculation where structure is the reactant endpoint. Calculation-specific tools should validate which structure names are required.

FileInput.from_directory("inputs", program="psi4") collects native input files with the required executor identity.

A FileInput is an escape hatch that allows you to run any calculation in any QC program (or any program for that matter), even if it isn't a supported CalcType in qcdata yet. You can use a FileInput to store the native input files (text and binary) for a QC program along with the relevant command line args. Using qcop you can submit a FileInput to a QC program and all output files and logs produced by that program will be collected and returned in a user-friendly ProgramOutput object. FileInput allows you to continue to use qcdata even for calculations that haven't yet been standardized.

qcdata.Inputs module-attribute

qcdata.ProgramInput

A program specification bound to structures.

Attributes:

Name Type Description
structure Structure

The required primary/start/reference structure.

structures dict[str, Structure]

Additional complete structures identified by role, such as the product endpoint of a nudged elastic band calculation.

Example
from qcdata import ProgramInput, ProgramSpec, Structure

prog_input = ProgramInput(
    program="geometric",
    calctype="optimization",
    structure=Structure.open("structure.xyz"),
    keywords={"maxiter": 250},
    subprograms=[
        ProgramSpec(
            program="terachem",
            calctype="gradient",
            model={"method": "wb97x-d3", "basis": "def2-svp"},
        ),
    ],
)

get_subprogram

get_subprogram(calctype: CalcType | str) -> ProgramSpec

Return an immediate child by CalcType or string value.

Raises ValueError if no matching immediate child exists.

Source code in src/qcdata/models/inputs.py
86
87
88
89
90
91
92
93
94
95
96
97
def get_subprogram(self, calctype: CalcType | str) -> "ProgramSpec":
    """Return an immediate child by CalcType or string value.

    Raises ValueError if no matching immediate child exists.
    """
    for child in self.subprograms:
        if child.calctype == calctype:
            return child
    raise ValueError(
        f"No immediate subprogram with calculation type {calctype!r} "
        f"for program '{self.program}'."
    )

add_file

add_file(
    filepath: Path | str, relative_dir: Path | None = None
) -> None

Add a file to the object. The file will be added at to the files attribute with the filename as the key and the file data as the value.

Parameters:

Name Type Description Default
filepath Path | str

The path to the file.

required
relative_dir Path | None

The directory to make the file relative to. Helpful when adding files from a subdirectory.

None
Example
    my_obj.add_file("path/to/file.txt")
    print(my_obj.files)
    # Output: {"file.txt": "file data"}
Source code in src/qcdata/models/base_models.py
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def add_file(self, filepath: Path | str, relative_dir: Path | None = None) -> None:
    """Add a file to the object. The file will be added at to the `files` attribute
        with the filename as the key and the file data as the value.

    Args:
        filepath: The path to the file.
        relative_dir: The directory to make the file relative to. Helpful when
            adding files from a subdirectory.

    Example:
        ```python
            my_obj.add_file("path/to/file.txt")
            print(my_obj.files)
            # Output: {"file.txt": "file data"}
        ```
    """
    filepath = Path(filepath)
    raw_bytes = filepath.read_bytes()
    try:
        data: str | bytes = raw_bytes.decode("utf-8")  # str
    except UnicodeDecodeError:
        data = raw_bytes  # bytes

    # Set filename relative to relative_dir
    if relative_dir:
        filename = str(filepath.relative_to(relative_dir))
    else:
        filename = filepath.name

    self.files[filename] = data
    # Add files to __pydantic_fields_set__ to ensure they are included in .save()
    self.__pydantic_fields_set__.add("files")

add_files

add_files(
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None

Add all files in a directory to the object.

Parameters:

Name Type Description Default
directory StrOrPath

The directory to add files from.

required
recursive bool

Whether to recursively add files from subdirectories.

False
exclude list[str] | None

A list of filenames to exclude from the directory.

None
Source code in src/qcdata/models/base_models.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def add_files(
    self,
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None:
    """Add all files in a directory to the object.

    Args:
        directory: The directory to add files from.
        recursive: Whether to recursively add files from subdirectories.
        exclude: A list of filenames to exclude from the directory.
    """
    directory = Path(directory)
    if exclude is None:
        exclude = []
    if recursive:
        files = directory.rglob("*")
    else:
        files = directory.glob("*")
    for filepath in files:
        if filepath.is_file() and filepath.name not in exclude:
            self.add_file(filepath, directory)

save_files

save_files(directory: StrOrPath = Path('.')) -> None

Write all files to the specified directory

Source code in src/qcdata/models/base_models.py
327
328
329
330
331
332
333
334
335
336
def save_files(self, directory: StrOrPath = Path(".")) -> None:
    """Write all files to the specified directory"""
    directory = Path(directory)
    directory.mkdir(exist_ok=True)
    for filename, data in self.files.items():
        mode = "w" if isinstance(data, str) else "wb"
        filepath = directory / filename
        # In case filename is a relative path, create the parent directories
        filepath.parent.mkdir(exist_ok=True, parents=True)
        filepath.open(mode).write(data)

qcdata.ProgramSpec

A recursive program specification, independent of structures.

Each child describes its own calculation. Siblings must have distinct calculation types; the same calculation type may appear at different levels of the tree.

Attributes:

Name Type Description
program str

The requested executor (distinct from result data provenance).

calctype CalcType

The type of calculation to perform.

model Model | None

The scientific model, or None for programs without one.

keywords dict[str, Any]

Program keywords, excluding model and calculation type.

subprograms list[ProgramSpec]

Child specifications, with one child per calculation type.

files dict[str, str | bytes]

Native input files for this program.

cmdline_args list[str]

Command line arguments for this program.

extras dict[str, Any]

Additional information to bundle with this specification.

get_subprogram

get_subprogram(calctype: CalcType | str) -> ProgramSpec

Return an immediate child by CalcType or string value.

Raises ValueError if no matching immediate child exists.

Source code in src/qcdata/models/inputs.py
86
87
88
89
90
91
92
93
94
95
96
97
def get_subprogram(self, calctype: CalcType | str) -> "ProgramSpec":
    """Return an immediate child by CalcType or string value.

    Raises ValueError if no matching immediate child exists.
    """
    for child in self.subprograms:
        if child.calctype == calctype:
            return child
    raise ValueError(
        f"No immediate subprogram with calculation type {calctype!r} "
        f"for program '{self.program}'."
    )

add_file

add_file(
    filepath: Path | str, relative_dir: Path | None = None
) -> None

Add a file to the object. The file will be added at to the files attribute with the filename as the key and the file data as the value.

Parameters:

Name Type Description Default
filepath Path | str

The path to the file.

required
relative_dir Path | None

The directory to make the file relative to. Helpful when adding files from a subdirectory.

None
Example
    my_obj.add_file("path/to/file.txt")
    print(my_obj.files)
    # Output: {"file.txt": "file data"}
Source code in src/qcdata/models/base_models.py
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def add_file(self, filepath: Path | str, relative_dir: Path | None = None) -> None:
    """Add a file to the object. The file will be added at to the `files` attribute
        with the filename as the key and the file data as the value.

    Args:
        filepath: The path to the file.
        relative_dir: The directory to make the file relative to. Helpful when
            adding files from a subdirectory.

    Example:
        ```python
            my_obj.add_file("path/to/file.txt")
            print(my_obj.files)
            # Output: {"file.txt": "file data"}
        ```
    """
    filepath = Path(filepath)
    raw_bytes = filepath.read_bytes()
    try:
        data: str | bytes = raw_bytes.decode("utf-8")  # str
    except UnicodeDecodeError:
        data = raw_bytes  # bytes

    # Set filename relative to relative_dir
    if relative_dir:
        filename = str(filepath.relative_to(relative_dir))
    else:
        filename = filepath.name

    self.files[filename] = data
    # Add files to __pydantic_fields_set__ to ensure they are included in .save()
    self.__pydantic_fields_set__.add("files")

add_files

add_files(
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None

Add all files in a directory to the object.

Parameters:

Name Type Description Default
directory StrOrPath

The directory to add files from.

required
recursive bool

Whether to recursively add files from subdirectories.

False
exclude list[str] | None

A list of filenames to exclude from the directory.

None
Source code in src/qcdata/models/base_models.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def add_files(
    self,
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None:
    """Add all files in a directory to the object.

    Args:
        directory: The directory to add files from.
        recursive: Whether to recursively add files from subdirectories.
        exclude: A list of filenames to exclude from the directory.
    """
    directory = Path(directory)
    if exclude is None:
        exclude = []
    if recursive:
        files = directory.rglob("*")
    else:
        files = directory.glob("*")
    for filepath in files:
        if filepath.is_file() and filepath.name not in exclude:
            self.add_file(filepath, directory)

save_files

save_files(directory: StrOrPath = Path('.')) -> None

Write all files to the specified directory

Source code in src/qcdata/models/base_models.py
327
328
329
330
331
332
333
334
335
336
def save_files(self, directory: StrOrPath = Path(".")) -> None:
    """Write all files to the specified directory"""
    directory = Path(directory)
    directory.mkdir(exist_ok=True)
    for filename, data in self.files.items():
        mode = "w" if isinstance(data, str) else "wb"
        filepath = directory / filename
        # In case filename is a relative path, create the parent directories
        filepath.parent.mkdir(exist_ok=True, parents=True)
        filepath.open(mode).write(data)

qcdata.FileInput

File and command line argument inputs for a calculation.

Attributes:

Name Type Description
program str

The requested executor for the calculation.

files Files

A dict mapping filename to str or bytes data.

cmdline_args list[str]

A list of command line arguments to be passed to the program.

extras Dict[str, Any]

Additional information to bundle with the object. Use for schema development and scratch space.

add_file

add_file(
    filepath: Path | str, relative_dir: Path | None = None
) -> None

Add a file to the object. The file will be added at to the files attribute with the filename as the key and the file data as the value.

Parameters:

Name Type Description Default
filepath Path | str

The path to the file.

required
relative_dir Path | None

The directory to make the file relative to. Helpful when adding files from a subdirectory.

None
Example
    my_obj.add_file("path/to/file.txt")
    print(my_obj.files)
    # Output: {"file.txt": "file data"}
Source code in src/qcdata/models/base_models.py
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def add_file(self, filepath: Path | str, relative_dir: Path | None = None) -> None:
    """Add a file to the object. The file will be added at to the `files` attribute
        with the filename as the key and the file data as the value.

    Args:
        filepath: The path to the file.
        relative_dir: The directory to make the file relative to. Helpful when
            adding files from a subdirectory.

    Example:
        ```python
            my_obj.add_file("path/to/file.txt")
            print(my_obj.files)
            # Output: {"file.txt": "file data"}
        ```
    """
    filepath = Path(filepath)
    raw_bytes = filepath.read_bytes()
    try:
        data: str | bytes = raw_bytes.decode("utf-8")  # str
    except UnicodeDecodeError:
        data = raw_bytes  # bytes

    # Set filename relative to relative_dir
    if relative_dir:
        filename = str(filepath.relative_to(relative_dir))
    else:
        filename = filepath.name

    self.files[filename] = data
    # Add files to __pydantic_fields_set__ to ensure they are included in .save()
    self.__pydantic_fields_set__.add("files")

add_files

add_files(
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None

Add all files in a directory to the object.

Parameters:

Name Type Description Default
directory StrOrPath

The directory to add files from.

required
recursive bool

Whether to recursively add files from subdirectories.

False
exclude list[str] | None

A list of filenames to exclude from the directory.

None
Source code in src/qcdata/models/base_models.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
def add_files(
    self,
    directory: StrOrPath,
    recursive: bool = False,
    exclude: list[str] | None = None,
) -> None:
    """Add all files in a directory to the object.

    Args:
        directory: The directory to add files from.
        recursive: Whether to recursively add files from subdirectories.
        exclude: A list of filenames to exclude from the directory.
    """
    directory = Path(directory)
    if exclude is None:
        exclude = []
    if recursive:
        files = directory.rglob("*")
    else:
        files = directory.glob("*")
    for filepath in files:
        if filepath.is_file() and filepath.name not in exclude:
            self.add_file(filepath, directory)

save_files

save_files(directory: StrOrPath = Path('.')) -> None

Write all files to the specified directory

Source code in src/qcdata/models/base_models.py
327
328
329
330
331
332
333
334
335
336
def save_files(self, directory: StrOrPath = Path(".")) -> None:
    """Write all files to the specified directory"""
    directory = Path(directory)
    directory.mkdir(exist_ok=True)
    for filename, data in self.files.items():
        mode = "w" if isinstance(data, str) else "wb"
        filepath = directory / filename
        # In case filename is a relative path, create the parent directories
        filepath.parent.mkdir(exist_ok=True, parents=True)
        filepath.open(mode).write(data)

from_directory classmethod

from_directory(directory: Path | str, **kwargs) -> Self

Collect directory files, passing required program and other fields as kwargs.

Source code in src/qcdata/models/inputs.py
35
36
37
38
39
40
41
@classmethod
def from_directory(cls, directory: Path | str, **kwargs) -> Self:
    """Collect directory files, passing required `program` and other fields as kwargs."""
    obj = cls(**kwargs)
    directory = Path(directory)
    obj.add_files(directory)
    return obj

Binding a specification to structures

input_data = ProgramInput.from_spec(
    spec, structure, structures={"reference": reference_structure}
)

This validates a new input while preserving all specification fields and recursive children. The original specification is unchanged. Additional structures are optional and are supplied explicitly when binding.