qcdata 0.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qcdata/__init__.py +78 -0
- qcdata/helper_types.py +21 -0
- qcdata/models/__init__.py +5 -0
- qcdata/models/base_models.py +402 -0
- qcdata/models/data.py +387 -0
- qcdata/models/inputs.py +224 -0
- qcdata/models/outputs.py +220 -0
- qcdata/models/results.py +4 -0
- qcdata/models/structure.py +665 -0
- qcdata/models/utils.py +98 -0
- qcdata/py.typed +0 -0
- qcdata/qcel.py +91 -0
- qcdata/utils.py +49 -0
- qcdata/view.py +773 -0
- qcdata-0.17.0.dist-info/METADATA +263 -0
- qcdata-0.17.0.dist-info/RECORD +18 -0
- qcdata-0.17.0.dist-info/WHEEL +4 -0
- qcdata-0.17.0.dist-info/licenses/LICENSE +21 -0
qcdata/__init__.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import warnings
|
|
3
|
+
from importlib import metadata
|
|
4
|
+
from types import ModuleType
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from .models import * # noqa: F403
|
|
8
|
+
from .models.utils import to_multi_xyz
|
|
9
|
+
from .utils import json_dumps
|
|
10
|
+
|
|
11
|
+
__version__ = metadata.version(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [ # noqa: F405
|
|
15
|
+
# Core Models
|
|
16
|
+
"CalcType",
|
|
17
|
+
"Model",
|
|
18
|
+
"Provenance",
|
|
19
|
+
"Structure",
|
|
20
|
+
"Molecule",
|
|
21
|
+
"Files",
|
|
22
|
+
"FileInput",
|
|
23
|
+
"ProgramInput",
|
|
24
|
+
"ProgramOutput",
|
|
25
|
+
"Results",
|
|
26
|
+
"DualProgramInput",
|
|
27
|
+
"SinglePointData",
|
|
28
|
+
"OptimizationData",
|
|
29
|
+
"ConformerSearchData",
|
|
30
|
+
"SinglePointResults",
|
|
31
|
+
"OptimizationResults",
|
|
32
|
+
"ConformerSearchResults",
|
|
33
|
+
"Wavefunction",
|
|
34
|
+
"ProgramArgs",
|
|
35
|
+
"ProgramArgsSub",
|
|
36
|
+
"json_dumps",
|
|
37
|
+
"to_multi_xyz",
|
|
38
|
+
"LengthUnit",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
# Map of deprecated symbols → new fully-qualified path
|
|
42
|
+
_DEPRECATED: dict[str, str] = {
|
|
43
|
+
"rmsd": "qcinf.rmsd",
|
|
44
|
+
"align": "qcinf.align",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def __getattr__(name: str) -> Any: # PEP 562
|
|
49
|
+
"""Redirect old qcdata symbols to qcinf (with helpful message)."""
|
|
50
|
+
if name not in _DEPRECATED:
|
|
51
|
+
raise AttributeError(f"module 'qcdata' has no attribute '{name}'")
|
|
52
|
+
|
|
53
|
+
new_path = _DEPRECATED[name]
|
|
54
|
+
mod_path, func_name = new_path.rsplit(".", 1)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
module: ModuleType = importlib.import_module(mod_path)
|
|
58
|
+
except ModuleNotFoundError as exc:
|
|
59
|
+
raise ModuleNotFoundError(
|
|
60
|
+
f"`qcinf` is not installed, so `qcdata.{name}` can no longer be "
|
|
61
|
+
"used. Install the dependency with either:\n\n"
|
|
62
|
+
" python -m pip install qcinf\n"
|
|
63
|
+
"or\n"
|
|
64
|
+
" python -m pip install 'qcinf[all]'\n\n"
|
|
65
|
+
"and then import the new function location:\n\n"
|
|
66
|
+
f" from {mod_path} import {func_name}",
|
|
67
|
+
) from exc
|
|
68
|
+
|
|
69
|
+
else:
|
|
70
|
+
# Emit a FutureWarning so it's shown by default
|
|
71
|
+
warnings.warn(
|
|
72
|
+
f"`qcdata.{name}` has moved to `{new_path}`.\n"
|
|
73
|
+
"Please update your import to:\n\n"
|
|
74
|
+
f" from qcinf import {name}",
|
|
75
|
+
FutureWarning,
|
|
76
|
+
stacklevel=2,
|
|
77
|
+
)
|
|
78
|
+
return getattr(module, func_name)
|
qcdata/helper_types.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from pydantic import BeforeValidator, GetPydanticSchema, PlainSerializer, SkipValidation
|
|
6
|
+
from pydantic_core import core_schema
|
|
7
|
+
|
|
8
|
+
StrOrPath = Annotated[str | Path, PlainSerializer(lambda x: str(x))]
|
|
9
|
+
|
|
10
|
+
# Create the annotated type for numpy array
|
|
11
|
+
SerializableNDArray = Annotated[
|
|
12
|
+
SkipValidation[np.ndarray],
|
|
13
|
+
# Coerce values to float64 numpy array. Not required. Creates consistency.
|
|
14
|
+
BeforeValidator(lambda x: np.array(x, dtype=np.float64)),
|
|
15
|
+
# Serializes the numpy array to a list
|
|
16
|
+
PlainSerializer(lambda x: np.array(x).tolist()),
|
|
17
|
+
# Describe json schema as a list of floats (numbers). Required for ChemCloud docs.
|
|
18
|
+
GetPydanticSchema(
|
|
19
|
+
lambda tp, handler: core_schema.with_default_schema(handler(list[float]))
|
|
20
|
+
),
|
|
21
|
+
]
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
"""The base model from which all QCData model objects inherit."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from abc import ABC
|
|
5
|
+
from base64 import b64decode, b64encode
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import toml
|
|
12
|
+
import yaml
|
|
13
|
+
from pydantic import BaseModel, field_serializer, field_validator
|
|
14
|
+
from typing_extensions import Self
|
|
15
|
+
|
|
16
|
+
from ..helper_types import StrOrPath
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
19
|
+
from pydantic.typing import ReprArgs
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__all__ = ["Files", "Provenance", "Model", "CalcType", "LengthUnit"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class LengthUnit(str, Enum):
|
|
26
|
+
"""The unit of length.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
BOHR (str): Bohr.
|
|
30
|
+
ANGSTROM (str): Angstroms.
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
BOHR = "bohr"
|
|
35
|
+
ANGSTROM = "angstrom"
|
|
36
|
+
|
|
37
|
+
def __repr__(self) -> str:
|
|
38
|
+
"""Custom repr for LengthUnit"""
|
|
39
|
+
return f"'{self.name}'" # pragma: no cover
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class QCDataBaseModel(BaseModel, ABC):
|
|
43
|
+
"""Base model for all QCData objects.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
version: The version of the schema.
|
|
47
|
+
extras: Additional information to bundle with the object. Use for schema
|
|
48
|
+
development and scratch space.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# NOTE: No version for now until we have a stable schema
|
|
52
|
+
# Or maybe have version be version of qcdata that generated the object?
|
|
53
|
+
# version: ClassVar[Literal["v1"]] = "v1"
|
|
54
|
+
extras: dict[str, Any] = {}
|
|
55
|
+
|
|
56
|
+
model_config = {
|
|
57
|
+
# Raises an error if extra fields are passed to model.
|
|
58
|
+
"extra": "forbid",
|
|
59
|
+
# Allow numpy types in models. Pydantic will no longer raise an exception for
|
|
60
|
+
# types it doesn't recognize.
|
|
61
|
+
# https://docs.pydantic.dev/latest/usage/types/#arbitrary-types-allowed
|
|
62
|
+
"arbitrary_types_allowed": True,
|
|
63
|
+
# Don't allow mutation of objects
|
|
64
|
+
# https://docs.pydantic.dev/2.3/api/config/#pydantic.config.ConfigDict.frozen
|
|
65
|
+
"frozen": True,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def open(cls, filepath: Path | str) -> Self:
|
|
70
|
+
"""Instantiate an object from data saved to disk.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
filepath: The path to the object on disk.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
The instantiated object.
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
```python
|
|
80
|
+
my_obj = MyModel.open("path/to/file.json")
|
|
81
|
+
```
|
|
82
|
+
"""
|
|
83
|
+
filepath = Path(filepath)
|
|
84
|
+
data = filepath.read_text()
|
|
85
|
+
|
|
86
|
+
if filepath.suffix in [".yaml", ".yml"]:
|
|
87
|
+
return cls.model_validate(yaml.safe_load(data))
|
|
88
|
+
elif filepath.suffix == ".toml":
|
|
89
|
+
return cls.model_validate(toml.loads(data))
|
|
90
|
+
|
|
91
|
+
# Assume json for all other file extensions
|
|
92
|
+
return cls.model_validate_json(data)
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def open_multi(cls, filepath: Path | str) -> list[Self]:
|
|
96
|
+
"""Instantiate a list of objects from data saved to disk.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
filepath: The path to the object on disk. Must be a list of objects.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
A list of instantiated objects.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
```python
|
|
106
|
+
my_objs = MyModel().open_multi("path/to/file.json")
|
|
107
|
+
```
|
|
108
|
+
"""
|
|
109
|
+
filepath = Path(filepath)
|
|
110
|
+
data = filepath.read_text()
|
|
111
|
+
|
|
112
|
+
if filepath.suffix in [".yaml", ".yml"]:
|
|
113
|
+
return [cls.model_validate(d) for d in yaml.safe_load(data)]
|
|
114
|
+
elif filepath.suffix == ".toml":
|
|
115
|
+
return [cls.model_validate(d) for d in toml.loads(data)]
|
|
116
|
+
|
|
117
|
+
# Assume json for all other file extensions
|
|
118
|
+
return [cls.model_validate(d) for d in json.loads(data)]
|
|
119
|
+
|
|
120
|
+
def save(
|
|
121
|
+
self,
|
|
122
|
+
filepath: Path | str,
|
|
123
|
+
exclude_none: bool = True,
|
|
124
|
+
exclude_unset: bool = True,
|
|
125
|
+
indent: int = 4,
|
|
126
|
+
**kwargs,
|
|
127
|
+
) -> None:
|
|
128
|
+
"""
|
|
129
|
+
Save an object to disk as `json`, `yaml`, or `toml`. Objects such as `Structure`
|
|
130
|
+
and `OptimizationResults` can additionally be saved as `xyz` files.
|
|
131
|
+
|
|
132
|
+
Note:
|
|
133
|
+
By default the object will be saved as a `json` file. If the file extension
|
|
134
|
+
is `.yaml` or `.yml`, the object will be saved as a `yaml` file. If the file
|
|
135
|
+
extension is `.toml`, the object will be saved as a `toml` file. If the file
|
|
136
|
+
extension is `.xyz`, the object will be saved as an `xyz` file (for objects
|
|
137
|
+
that support this format such as a `Structure` or an `OptimizationResults`
|
|
138
|
+
which contains `.trajectory: list[Structure]`).
|
|
139
|
+
|
|
140
|
+
Additionally, padding will be added to the file by default to make it more
|
|
141
|
+
human-readable. You can adjust the amount of padding added by changing the
|
|
142
|
+
`indent` parameter. Pass `indent=None` to create a more compact file.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
filepath: The path to write the object to.
|
|
146
|
+
exclude_none: If True, attributes with a value of None will not be written.
|
|
147
|
+
Changing default behavior from pydantic.model_dump() to True.
|
|
148
|
+
exclude_unset: If True, attributes that have not been set will not be
|
|
149
|
+
written (i.e., values set to their default value).
|
|
150
|
+
indent: The number of spaces to use for indentation in the JSON file. 0
|
|
151
|
+
creates a more compact JSON file, 4 is more human-readable.
|
|
152
|
+
**kwargs: Additional keyword arguments to pass to the serialization method.
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
```python
|
|
156
|
+
my_obj.save("path/to/file.json")
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
my_obj.save("path/to/file.yaml")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
my_obj.save("path/to/file.toml")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
my_obj.save("path/to/file.xyz")
|
|
169
|
+
```
|
|
170
|
+
"""
|
|
171
|
+
filepath = Path(filepath)
|
|
172
|
+
filepath.parent.mkdir(exist_ok=True, parents=True)
|
|
173
|
+
|
|
174
|
+
if self.extras:
|
|
175
|
+
# Ensure pydantic knows the field has been set
|
|
176
|
+
self.__pydantic_fields_set__.add("extras")
|
|
177
|
+
|
|
178
|
+
model_dict = self.model_dump(
|
|
179
|
+
mode="json",
|
|
180
|
+
exclude_none=exclude_none,
|
|
181
|
+
exclude_unset=exclude_unset,
|
|
182
|
+
**kwargs,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
if filepath.suffix in [".yaml", ".yml"]:
|
|
186
|
+
data = yaml.dump(model_dict, indent=indent)
|
|
187
|
+
|
|
188
|
+
elif filepath.suffix == ".toml":
|
|
189
|
+
data = toml.dumps(model_dict)
|
|
190
|
+
|
|
191
|
+
else:
|
|
192
|
+
# Write data to json regardless of file extension
|
|
193
|
+
data = json.dumps(model_dict, indent=indent)
|
|
194
|
+
|
|
195
|
+
filepath.write_text(data)
|
|
196
|
+
|
|
197
|
+
def __repr_args__(self) -> "ReprArgs":
|
|
198
|
+
"""Only show non empty fields in repr but always show success even if false."""
|
|
199
|
+
|
|
200
|
+
def exists(value):
|
|
201
|
+
if isinstance(value, np.ndarray):
|
|
202
|
+
return value.size > 0
|
|
203
|
+
return bool(value)
|
|
204
|
+
|
|
205
|
+
return [ # pragma: no cover
|
|
206
|
+
(name, value)
|
|
207
|
+
for name, value in self.__dict__.items()
|
|
208
|
+
if name == "success" or exists(value)
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
def __eq__(self, other: Any) -> bool:
|
|
212
|
+
"""Check equality of two objects.
|
|
213
|
+
|
|
214
|
+
Necessary because BaseModel.__eq__ does not compare numpy arrays.
|
|
215
|
+
"""
|
|
216
|
+
if isinstance(other, self.__class__):
|
|
217
|
+
return self.model_dump() == other.model_dump()
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class Files(QCDataBaseModel):
|
|
222
|
+
"""File model for handling string and binary data.
|
|
223
|
+
|
|
224
|
+
Binary data is encoded as base64 strings during serialization.
|
|
225
|
+
|
|
226
|
+
Attributes:
|
|
227
|
+
files: A dict mapping filename to str or bytes data.
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
files: dict[str, str | bytes] = {}
|
|
231
|
+
|
|
232
|
+
@field_validator("files")
|
|
233
|
+
def _convert_base64_to_bytes(cls, value):
|
|
234
|
+
"""Convert base64 encoded data to bytes."""
|
|
235
|
+
for filename, data in value.items():
|
|
236
|
+
if isinstance(data, str) and data.startswith("base64:"):
|
|
237
|
+
value[filename] = b64decode(data[7:])
|
|
238
|
+
return value
|
|
239
|
+
|
|
240
|
+
@field_serializer("files")
|
|
241
|
+
def _serialize_files(self, files, _info) -> dict[str, str]:
|
|
242
|
+
"""Serialize files to a dict of filename to base64 encoded string."""
|
|
243
|
+
return {
|
|
244
|
+
filename: (
|
|
245
|
+
f"base64:{b64encode(data).decode('utf-8')}"
|
|
246
|
+
if isinstance(data, bytes)
|
|
247
|
+
else data
|
|
248
|
+
)
|
|
249
|
+
for filename, data in files.items()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
def add_file(
|
|
253
|
+
self, filepath: Path | str, relative_dir: Path | None = None
|
|
254
|
+
) -> None:
|
|
255
|
+
"""Add a file to the object. The file will be added at to the `files` attribute
|
|
256
|
+
with the filename as the key and the file data as the value.
|
|
257
|
+
|
|
258
|
+
Args:
|
|
259
|
+
filepath: The path to the file.
|
|
260
|
+
relative_dir: The directory to make the file relative to. Helpful when
|
|
261
|
+
adding files from a subdirectory.
|
|
262
|
+
|
|
263
|
+
Example:
|
|
264
|
+
```python
|
|
265
|
+
my_obj.add_file("path/to/file.txt")
|
|
266
|
+
print(my_obj.files)
|
|
267
|
+
# Output: {"file.txt": "file data"}
|
|
268
|
+
```
|
|
269
|
+
"""
|
|
270
|
+
filepath = Path(filepath)
|
|
271
|
+
raw_bytes = filepath.read_bytes()
|
|
272
|
+
try:
|
|
273
|
+
data: str | bytes = raw_bytes.decode("utf-8") # str
|
|
274
|
+
except UnicodeDecodeError:
|
|
275
|
+
data = raw_bytes # bytes
|
|
276
|
+
|
|
277
|
+
# Set filename relative to relative_dir
|
|
278
|
+
if relative_dir:
|
|
279
|
+
filename = str(filepath.relative_to(relative_dir))
|
|
280
|
+
else:
|
|
281
|
+
filename = filepath.name
|
|
282
|
+
|
|
283
|
+
self.files[filename] = data
|
|
284
|
+
# Add files to __pydantic_fields_set__ to ensure they are included in .save()
|
|
285
|
+
self.__pydantic_fields_set__.add("files")
|
|
286
|
+
|
|
287
|
+
def add_files(
|
|
288
|
+
self,
|
|
289
|
+
directory: StrOrPath,
|
|
290
|
+
recursive: bool = False,
|
|
291
|
+
exclude: list[str] | None = None,
|
|
292
|
+
) -> None:
|
|
293
|
+
"""Add all files in a directory to the object.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
directory: The directory to add files from.
|
|
297
|
+
recursive: Whether to recursively add files from subdirectories.
|
|
298
|
+
exclude: A list of filenames to exclude from the directory.
|
|
299
|
+
"""
|
|
300
|
+
directory = Path(directory)
|
|
301
|
+
if exclude is None:
|
|
302
|
+
exclude = []
|
|
303
|
+
if recursive:
|
|
304
|
+
files = directory.rglob("*")
|
|
305
|
+
else:
|
|
306
|
+
files = directory.glob("*")
|
|
307
|
+
for filepath in files:
|
|
308
|
+
if filepath.is_file() and filepath.name not in exclude:
|
|
309
|
+
self.add_file(filepath, directory)
|
|
310
|
+
|
|
311
|
+
def save_files(self, directory: StrOrPath = Path(".")) -> None:
|
|
312
|
+
"""Write all files to the specified directory"""
|
|
313
|
+
directory = Path(directory)
|
|
314
|
+
directory.mkdir(exist_ok=True)
|
|
315
|
+
for filename, data in self.files.items():
|
|
316
|
+
mode = "w" if isinstance(data, str) else "wb"
|
|
317
|
+
filepath = directory / filename
|
|
318
|
+
# In case filename is a relative path, create the parent directories
|
|
319
|
+
filepath.parent.mkdir(exist_ok=True, parents=True)
|
|
320
|
+
filepath.open(mode).write(data)
|
|
321
|
+
|
|
322
|
+
def __repr_args__(self) -> "ReprArgs":
|
|
323
|
+
"""Replace file data with '<bytes>' or '<str>' in __repr__."""
|
|
324
|
+
rargs = super().__repr_args__()
|
|
325
|
+
return [
|
|
326
|
+
(
|
|
327
|
+
(k, v)
|
|
328
|
+
if k != "files"
|
|
329
|
+
else (
|
|
330
|
+
k,
|
|
331
|
+
{
|
|
332
|
+
name: bytes if isinstance(data, bytes) else str
|
|
333
|
+
for name, data in v.items()
|
|
334
|
+
},
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
for k, v in rargs
|
|
338
|
+
]
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class Provenance(QCDataBaseModel):
|
|
342
|
+
"""Provenance information for a QC program.
|
|
343
|
+
|
|
344
|
+
Attributes:
|
|
345
|
+
program: The name of the program that created the output.
|
|
346
|
+
version: The version of the program that created the output.
|
|
347
|
+
scratch_dir: The working directory used by the program.
|
|
348
|
+
wall_time: The wall time used by the program.
|
|
349
|
+
hostname: The hostname of the machine the program was run on.
|
|
350
|
+
hostcpus: The number of logical CPUs on the host machine where the program ran.
|
|
351
|
+
hostmem: The amount of memory on the host machine where the program ran in GiB.
|
|
352
|
+
extras: Additional information to bundle with the object. Use for schema
|
|
353
|
+
development and scratch space.
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
program: str
|
|
358
|
+
program_version: str | None = None
|
|
359
|
+
scratch_dir: Path | None = None
|
|
360
|
+
wall_time: float | None = None
|
|
361
|
+
hostname: str | None = None
|
|
362
|
+
hostcpus: int | None = None
|
|
363
|
+
hostmem: int | None = None
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class CalcType(str, Enum):
|
|
367
|
+
"""The Calculation type.
|
|
368
|
+
|
|
369
|
+
Attributes:
|
|
370
|
+
energy: Energy calculation.
|
|
371
|
+
gradient: Gradient calculation.
|
|
372
|
+
hessian: Hessian calculation.
|
|
373
|
+
optimization: Geometry optimization (to a minima).
|
|
374
|
+
transition_state: Transition state optimization (to a saddle point).
|
|
375
|
+
conformer_search: Conformer search.
|
|
376
|
+
"""
|
|
377
|
+
|
|
378
|
+
energy = "energy"
|
|
379
|
+
gradient = "gradient"
|
|
380
|
+
hessian = "hessian"
|
|
381
|
+
optimization = "optimization"
|
|
382
|
+
transition_state = "transition_state"
|
|
383
|
+
conformer_search = "conformer_search"
|
|
384
|
+
|
|
385
|
+
def __repr__(self) -> str:
|
|
386
|
+
"""Custom repr for CalcType"""
|
|
387
|
+
return f"'{self.name}'" # pragma: no cover
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class Model(QCDataBaseModel):
|
|
391
|
+
"""The model for the quantum chemistry calculation.
|
|
392
|
+
|
|
393
|
+
Attributes:
|
|
394
|
+
method: The name of the method to be used in the calculation. Named according to
|
|
395
|
+
the convention of the program being called. If an MM calculation then the
|
|
396
|
+
name of the force field.
|
|
397
|
+
basis: The name of the basis set to be used in the calculation. Named according
|
|
398
|
+
to the convention of the program being called.
|
|
399
|
+
"""
|
|
400
|
+
|
|
401
|
+
method: str
|
|
402
|
+
basis: str | None = None
|