././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0612903 emmet-core-0.84.2/0000755000175100001770000000000014673360566013267 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0612903 emmet-core-0.84.2/PKG-INFO0000644000175100001770000000156514673360566014373 0ustar00runnerdockerMetadata-Version: 2.1 Name: emmet-core Version: 0.84.2 Summary: Core Emmet Library Home-page: https://github.com/materialsproject/emmet Author: The Materials Project Author-email: feedback@materialsproject.org License: modified BSD Platform: UNKNOWN Requires-Python: >=3.9 Description-Content-Type: text/markdown Provides-Extra: all Provides-Extra: ml Provides-Extra: test Provides-Extra: docs # ![Emmet](docs/images/logo_w_text.svg) [![Pytest Status](https://github.com/materialsproject/emmet/workflows/testing/badge.svg)](https://github.com/materialsproject/emmet/actions?query=workflow%3Atesting) [![Code Coverage](https://codecov.io/gh/materialsproject/emmet/branch/main/graph/badge.svg)](https://codecov.io/gh/materialsproject/emmet) The Materials API Toolkit for the Materials Project. Emmet defines the core models, data pipelines, the API server, and the convenience CLI. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0382903 emmet-core-0.84.2/dev_scripts/0000755000175100001770000000000014673360566015614 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/dev_scripts/generate_enums.py0000644000175100001770000001554714673360562021177 0ustar00runnerdocker"""Module to define various calculation types as Enums for VASP.""" from __future__ import annotations from importlib.resources import files as import_resource_files from itertools import product from ruamel.yaml import YAML _BASE_ENUM_PATH = { "vasp": import_resource_files("emmet.core.vasp"), "qchem": import_resource_files("emmet.core.qchem"), } for code_base in _BASE_ENUM_PATH: _BASE_ENUM_PATH[code_base] /= "calc_types" def get_enum_source( enum_name: str, doc: str, members: dict, enum_class: str = "ValueEnum" ) -> str: """Write python-format enum from a dict of members and metadata. Parameters ----------- enum_name : str Name of the enum. doc : str Enum docstr members : dict The key-value pair indexed members of the enum. enum_class : str = "ValueEnum" The name of the enum class. Returns -------- str """ items = [f"class {enum_name}({enum_class}):", f' """ {doc} """\n'] items += [f' {const} = "{val}"' for const, val in members.items()] return "\n".join(items) def string_bulk_replace(string: str, rules: dict[str, str]) -> str: """Perform multiple string replacements subject to a set of rules. Parameters ----------- string : str input string rules : dict[str,str] A dict of string replacements, with the characters to replace as keys, and their replacements as values. Returns -------- str """ for targ_char, rep_char in rules.items(): string = string.replace(targ_char, rep_char) return string def generate_vasp_enums_file(enum_file_name: str | None = None) -> None: """ Generate VASP enum members from reference yaml data. Parameters ----------- enum_file_name : str Name of the file to write the enums to. Defaults to _BASE_ENUM_PATH / vasp_enums.json.gz """ with open(_BASE_ENUM_PATH["vasp"] / "calc_types.yaml", "r") as config: _RUN_TASK_TYPE_DATA = YAML().load(config) _TASK_TYPES = _RUN_TASK_TYPE_DATA.get("TASK_TYPES") _RUN_TYPES = set( rt for functionals in _RUN_TASK_TYPE_DATA.get("RUN_TYPES", {}).values() for rt in functionals ) _RUN_TYPES.update(set(f"{rt}+U" for rt in _RUN_TYPES)) _ENUMS = { "RunType": { "_".join(rt.split()).replace("+", "_").replace("-", "_"): rt for rt in _RUN_TYPES }, "TaskType": {"_".join(tt.split()): tt for tt in _TASK_TYPES}, "CalcType": { f"{'_'.join(rt.split()).replace('+','_').replace('-','_')}" f"_{'_'.join(tt.split())}": f"{rt} {tt}" for rt, tt in product(_RUN_TYPES, _TASK_TYPES) }, } docstr = {} for enum_name in _ENUMS: rtc_type = enum_name.split("Calc")[-1].split("Type")[0].lower() if len(rtc_type) > 0: rtc_type += " " docstr[enum_name] = f"VASP calculation {rtc_type}types." enum_file_name = enum_file_name or str(_BASE_ENUM_PATH["vasp"] / "enums.py") with open(enum_file_name, "w+") as f: f.write( """\"\"\" Autogenerated Enums for VASP RunType, TaskType, and CalcType. Do not edit this by hand to add or remove enums. Instead, edit dev_scripts/generate_enums.py and/or emmet/core/vasp/calc_types/calc_types.yaml \"\"\" from emmet.core.utils import ValueEnum, IgnoreCaseEnum """ ) enum_order = ( "RunType", "TaskType", "CalcType", ) for ienum, enum_name in enumerate(enum_order): sorted_enums = {k: _ENUMS[enum_name][k] for k in sorted(_ENUMS[enum_name])} f.write( get_enum_source( enum_name, docstr[enum_name], sorted_enums, enum_class=( "IgnoreCase" if enum_name in ["RunType", "CalcType"] else "Value" ) + "Enum", ) ) f.write("\n\n" if ienum < (len(enum_order) - 1) else "\n") def generate_qchem_enum_file(enum_file_name: str | None = None) -> None: """ Generate QChem enum members from reference yaml data. Original author, Evan Spotte-Smith Parameters ----------- enum_file_name : str Name of the file to write the enums to. Defaults to _BASE_ENUM_PATH / qchem_enums.json.gz """ with open(_BASE_ENUM_PATH["qchem"] / "calc_types.yaml", "r") as config: _calc_type_meta = YAML().load(config) _calc_type_meta["FUNCTIONALS"] = [ rt for functionals in _calc_type_meta["FUNCTIONAL_CLASSES"].values() for rt in functionals ] _LOTS = list() for funct in _calc_type_meta["FUNCTIONALS"]: for basis in _calc_type_meta["BASIS_SETS"]: for solv_model in _calc_type_meta["SOLVENT_MODELS"]: _LOTS.append(f"{funct}/{basis}/{solv_model}") _lot_str_replacements = { "+": "_", "-": "_", "(": "_", ")": "_", "/": "_", "*": "_d", } _ENUMS = { "LevelOfTheory": { "_".join(string_bulk_replace(lot, _lot_str_replacements).split()): lot for lot in _LOTS }, "TaskType": { "_".join(tt.split()).replace("-", "_"): tt for tt in _calc_type_meta["TASK_TYPES"] }, "CalcType": { ( "_".join(string_bulk_replace(lot, _lot_str_replacements).split()) + f"_{'_'.join(tt.split()).replace('-', '_')}" ): f"{lot} {tt}" for lot, tt in product(_LOTS, _calc_type_meta["TASK_TYPES"]) }, } docstr = { "LevelOfTheory": "Levels of theory for calculations in Q-Chem.", "TaskType": "Calculation task types for Q-Chem.", "CalcType": "Calculation types (LOT + task type) for Q-Chem.", } enum_file_name = enum_file_name or str(_BASE_ENUM_PATH["qchem"] / "enums.py") with open(enum_file_name, "w+") as f: f.write( """\"\"\" Autogenerated Enums for Q-Chem LevelOfTheory, TaskType, and CalcType. Do not edit this by hand to add or remove enums. Instead, edit dev_scripts/generate_enums.py and/or emmet/core/qchem/calc_types/calc_types.yaml \"\"\" from emmet.core.utils import ValueEnum """ ) enum_order = ( "LevelOfTheory", "TaskType", "CalcType", ) for ienum, enum_name in enumerate(enum_order): sorted_enums = {k: _ENUMS[enum_name][k] for k in sorted(_ENUMS[enum_name])} f.write(get_enum_source(enum_name, docstr[enum_name], sorted_enums)) f.write("\n\n" if ienum < (len(enum_order) - 1) else "\n") if __name__ == "__main__": generate_vasp_enums_file() generate_qchem_enum_file() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0352902 emmet-core-0.84.2/emmet/0000755000175100001770000000000014673360566014376 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0462902 emmet-core-0.84.2/emmet/core/0000755000175100001770000000000014673360566015326 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/__init__.py0000644000175100001770000000050714673360562017435 0ustar00runnerdocker""" Core module exposes the document interfaces These will be ingested via Drones, built by Builders, and served via the API. """ from importlib.metadata import PackageNotFoundError, version try: __version__ = version("emmet-core") except PackageNotFoundError: # pragma: no cover # package is not installed pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/_general_store.py0000644000175100001770000000135014673360562020663 0ustar00runnerdockerfrom pydantic import BaseModel, Field from typing import Dict try: from typing import Literal, Optional # type: ignore except ImportError: from typing_extensions import Literal, Optional # type: ignore from datetime import datetime class GeneralStoreDoc(BaseModel): """ Defines general store data """ kind: Optional[Literal["newsfeed", "seminar", "banner"]] = Field( None, description="Type of the data." ) markdown: Optional[str] = Field(None, description="Markdown data.") meta: Optional[Dict] = Field(None, description="Metadata.") last_updated: datetime = Field( description="Timestamp for when this document was last updated", default_factory=datetime.utcnow, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/_messages.py0000644000175100001770000000177314673360562017652 0ustar00runnerdockerfrom typing import List, Optional from datetime import datetime from pydantic import BaseModel, Field from enum import Enum class MessageType(Enum): generic = "generic" warning = "warning" class MessagesDoc(BaseModel): """ Defines data for user messages """ title: Optional[str] = Field( None, title="Title", description="Generic title or short summary for the message.", ) body: Optional[str] = Field( None, title="Body", description="Main text body of message." ) authors: Optional[List[str]] = Field( None, title="Title", description="Generic title or short summary for the message.", ) type: MessageType = Field( MessageType.generic, title="Type", description="The type of the message.", ) last_updated: datetime = Field( default_factory=datetime.utcnow, title="Last Updated", description="The last updated UTC timestamp for the message.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/_user_settings.py0000644000175100001770000000067014673360562020734 0ustar00runnerdockerfrom pydantic import BaseModel, Field from typing import Optional class UserSettingsDoc(BaseModel): """ Defines data for user settings """ consumer_id: Optional[str] = Field( None, title="Consumer ID", description="Consumer ID for a specific user." ) settings: Optional[dict] = Field( None, title="Consumer ID settings", description="Settings defined for a specific user.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/absorption.py0000644000175100001770000000517414673360562020063 0ustar00runnerdockerfrom typing import List, Optional from pydantic import Field from emmet.core.material_property import PropertyDoc import numpy as np from emmet.core.mpid import MPID from pymatgen.core import Structure class AbsorptionDoc(PropertyDoc): """Absorption spectrum based on frequency dependent dielectric function calculations.""" property_name: str = "Optical absorption spectrum" task_id: str = Field(..., description="Calculation id") energies: List[float] = Field( ..., description="Absorption energy in eV starting from 0" ) energy_max: float = Field(..., description="Maximum energy") absorption_coefficient: List[float] = Field( ..., description="Absorption coefficient in cm^-1" ) average_imaginary_dielectric: List[float] = Field( ..., description="Imaginary part of the dielectric function corresponding to the " "energies", ) average_real_dielectric: List[float] = Field( ..., description="Real part of the dielectric function corresponding to the energies", ) bandgap: Optional[float] = Field(None, description="The electronic band gap") nkpoints: Optional[float] = Field( None, description="The number of kpoints used in the calculation" ) @classmethod def _convert_list_to_tensor(cls, l): l = np.array(l) a = np.array([[l[0], l[3], l[4]], [l[3], l[1], l[5]], [l[4], l[5], l[2]]]) return a @classmethod def from_structure( cls, material_id: MPID, energies: List, task_id: str, real_d: List[np.ndarray], imag_d: List[np.ndarray], absorption_co: List, bandgap: float, structure: Structure, nkpoints: float, **kwargs, ): real_d_average = [ np.average(np.diagonal(cls._convert_list_to_tensor(t))) for t in real_d ] imag_d_average = [ np.average(np.diagonal(cls._convert_list_to_tensor(t))) for t in imag_d ] absorption_co = list(np.array(absorption_co)) energy_max = np.array(energies).max() return super().from_structure( meta_structure=structure, material_id=material_id, **{ "energies": energies, "energy_max": energy_max, "absorption_coefficient": absorption_co, "average_imaginary_dielectric": imag_d_average, "average_real_dielectric": real_d_average, "bandgap": bandgap, "nkpoints": nkpoints, "task_id": task_id, }, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/alloys.py0000644000175100001770000000166214673360562017204 0ustar00runnerdockerfrom emmet.core.base import EmmetBaseModel from typing import Dict try: from pymatgen.analysis.alloys.core import ( AlloyPair, AlloySystem, ) except ImportError: raise ImportError( "Install pymatgen-analysis-alloys to use AlloyPairDoc or AlloySystemDoc" ) class AlloyPairDoc(EmmetBaseModel): alloy_pair: AlloyPair pair_id: str # fields useful for building search indices _search: Dict @classmethod def from_pair(cls, pair: AlloyPair): return cls(alloy_pair=pair, pair_id=pair.pair_id, _search=pair.search_dict()) class AlloySystemDoc(EmmetBaseModel): alloy_system: AlloySystem alloy_id: str @classmethod def from_pair(cls, alloy_system: AlloySystem): # Too large to duplicate alloy pairs here. alloy_system.alloy_pairs = None # type: ignore[assignment] return cls(alloy_system=alloy_system, alloy_id=alloy_system.alloy_id) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/base.py0000644000175100001770000000314314673360562016607 0ustar00runnerdocker# mypy: ignore-errors """Base emmet model to add default metadata.""" from datetime import datetime from typing import Literal, Optional, TypeVar from pydantic import BaseModel, Field, field_validator from pymatgen.core import __version__ as pmg_version from emmet.core import __version__ from emmet.core.common import convert_datetime from emmet.core.utils import utcnow T = TypeVar("T", bound="EmmetBaseModel") class EmmetMeta(BaseModel): """Default emmet metadata.""" emmet_version: Optional[str] = Field( __version__, description="The version of emmet this document was built with." ) pymatgen_version: Optional[str] = Field( pmg_version, description="The version of pymatgen this document was built with." ) run_id: Optional[str] = Field( None, description="The run id associated with this data build." ) database_version: Optional[str] = Field( None, description="The database version for the built data." ) build_date: Optional[datetime] = Field( # type: ignore default_factory=utcnow, description="The build date for this document.", ) license: Optional[Literal["BY-C", "BY-NC"]] = Field( None, description="License for the data entry." ) @field_validator("build_date", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) class EmmetBaseModel(BaseModel): """Base Model for default emmet data.""" builder_meta: Optional[EmmetMeta] = Field( default_factory=EmmetMeta, # type: ignore description="Builder metadata.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/bonds.py0000644000175100001770000000740514673360562017007 0ustar00runnerdockerimport logging from typing import Dict, List, Any import numpy as np from pydantic import Field from pymatgen.analysis.graphs import StructureGraph from pymatgen.analysis.local_env import NearNeighbors from emmet.core.material_property import PropertyDoc AVAILABLE_METHODS = {nn.__name__: nn for nn in NearNeighbors.__subclasses__()} class BondingDoc(PropertyDoc): """Structure graphs representing chemical bonds calculated from structure using near neighbor strategies as defined in pymatgen.""" property_name: str = "bonding" structure_graph: StructureGraph = Field( description="Structure graph", ) method: str = Field(description="Method used to compute structure graph.") bond_types: Dict[str, List[float]] = Field( description="Dictionary of bond types to their length, e.g. a Fe-O to " "a list of the lengths of Fe-O bonds in Angstrom." ) bond_length_stats: Dict[str, Any] = Field( description="Dictionary of statistics of bonds in structure " "with keys all_weights, min, max, mean and variance." ) coordination_envs: List[str] = Field( description="List of co-ordination environments, e.g. ['Mo-S(6)', 'S-Mo(3)']." ) coordination_envs_anonymous: List[str] = Field( description="List of co-ordination environments without elements " "present, e.g. ['A-B(6)', 'A-B(3)']." ) @classmethod def from_structure( cls, structure, material_id, preferred_methods=( "CrystalNN", "MinimumDistanceNN", ), **kwargs ): """ Calculate :param structure: ideally an oxidation state-decorated structure :param material_id: mpid :param preferred_methods: list of strings of NearNeighbor classes or NearNeighbor instances :param deprecated: whether source material is or is not deprecated :param kwargs: to pass to PropertyDoc :return: """ bonding_info = None preferred_methods = [ # type: ignore AVAILABLE_METHODS[method]() if isinstance(method, str) else method for method in preferred_methods ] for method in preferred_methods: try: sg = StructureGraph.with_local_env_strategy(structure, method) # ensure edge weights are specifically bond lengths edge_weights = [] for u, v, d in sg.graph.edges(data=True): jimage = np.array(d["to_jimage"]) dist = sg.structure.get_distance(u, v, jimage=jimage) edge_weights.append((u, v, d["to_jimage"], dist)) for u, v, to_jimage, dist in edge_weights: sg.alter_edge(u, v, to_jimage=to_jimage, new_weight=dist) bonding_info = { "method": method.__class__.__name__, "structure_graph": sg, "bond_types": sg.types_and_weights_of_connections, "bond_length_stats": sg.weight_statistics, "coordination_envs": sg.types_of_coordination_environments(), "coordination_envs_anonymous": sg.types_of_coordination_environments( anonymous=True ), } break except Exception as e: logging.warning( "Failed to calculate bonding: {} {} {}".format( material_id, method, e ) ) if bonding_info: return super().from_structure( meta_structure=structure, material_id=material_id, **bonding_info, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/charge_density.py0000644000175100001770000000152714673360562020671 0ustar00runnerdockerfrom pydantic import ConfigDict, BaseModel, Field from datetime import datetime from typing import Optional class VolumetricDataDoc(BaseModel): """ Volumetric data metadata for selected materials. """ fs_id: Optional[str] = Field( None, description="Unique object ID for the charge density data." ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent update to the charge density data.", ) task_id: Optional[str] = Field( None, description="The Materials Project ID of the calculation producing the charge density data. " "This comes in the form: mp-******.", ) model_config = ConfigDict(extra="allow") class ChgcarDataDoc(VolumetricDataDoc): """ Electron charge density metadata for selected materials. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/chemenv.py0000644000175100001770000004370314673360562017330 0ustar00runnerdockerfrom typing import Literal, List, Union, Optional from pydantic import Field from pymatgen.analysis.chemenv.coordination_environments.chemenv_strategies import ( SimplestChemenvStrategy, ) from pymatgen.analysis.chemenv.coordination_environments.coordination_geometries import ( AllCoordinationGeometries, ) from pymatgen.analysis.chemenv.coordination_environments.coordination_geometry_finder import ( LocalGeometryFinder, ) from pymatgen.analysis.chemenv.coordination_environments.structure_environments import ( LightStructureEnvironments, ) from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.core.structure import Molecule from pymatgen.core.structure import Structure from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID DEFAULT_DISTANCE_CUTOFF = 1.4 DEFAULT_ANGLE_CUTOFF = 0.3 AVAILABLE_METHODS = { "DefaultSimplestChemenvStrategy": SimplestChemenvStrategy(), # "DefaultSimplestChemenvStrategy_all_bonds": SimplestChemenvStrategy(additional_condition=0), } DEFAULTSIMPLESTCHEMENVSTRATEGY = "Simplest ChemenvStrategy using fixed angle and distance parameters for the definition of neighbors in the Voronoi approach. The coordination environment is then given as the one with the lowest continuous symmetry measure. Options: distance_cutoff=1.4 angle_cutoff=0.3 additional_condition=1 continuous_symmetry_measure_cutoff=10.0" # noqa: E501 # SIMPLESTCHEMENVSTRATEGY_ALL_BONDS = "Simplest ChemenvStrategy using fixed angle and distance parameters for the definition of neighbors in the Voronoi approach. The coordination environment is then given as the one with the lowest continuous symmetry measure. Options: distance_cutoff=1.4 angle_cutoff=0.3 additional_condition=0 continuous_symmetry_measure_cutoff=10.0" # noqa: E501 METHODS_DESCRIPTION = { "DefaultSimplestChemenvStrategy": DEFAULTSIMPLESTCHEMENVSTRATEGY, # "DefaultSimplestChemenvStrategy_all_bonds": SIMPLESTCHEMENVSTRATEGY_ALL_BONDS, } COORDINATION_GEOMETRIES = Literal[ "S:1", "L:2", "A:2", "TL:3", "TY:3", "TS:3", "T:4", "S:4", "SY:4", "SS:4", "PP:5", "S:5", "T:5", "O:6", "T:6", "PP:6", "PB:7", "ST:7", "ET:7", "FO:7", "C:8", "SA:8", "SBT:8", "TBT:8", "DD:8", "DDPN:8", "HB:8", "BO_1:8", "BO_2:8", "BO_3:8", "TC:9", "TT_1:9", "TT_2:9", "TT_3:9", "HD:9", "TI:9", "SMA:9", "SS:9", "TO_1:9", "TO_2:9", "TO_3:9", "PP:10", "PA:10", "SBSA:10", "MI:10", "BS_1:10", "BS_2:10", "TBSA:10", "PCPA:11", "H:11", "DI:11", "I:12", "PBP:12", "TT:12", "C:12", "AC:12", "SC:12", "HP:12", "HA:12", "SH:13", "DD:20", "None", ] COORDINATION_GEOMETRIES_IUPAC = Literal[ "TOCT-9", "CUS-10", "PPR-10", "PPRP-11", "OCF-7", "SAPRT-10", "T-4", "PAPR-10", "DD-20", "TPR-6", "OCT-8", "PP-5", "SPY-4", "HBPY-9", "A-2", "TPRT-8", "TS-3", "SS-4", "None", "SAPR-8", "SPY-5", "SAPRS-10", "HPR-12", "L-2", "PPY-6", "SP-4", "IC-12", "HBPY-8", "TPY-3", "CUS-9", "TPRS-8", "DD-8", "TBPY-5", "TP-3", "TCA-9", "PPRP-12", "SAPRS-9", "OC-6", "PBPY-7", "TPRS-7", "TPRS-9", "CU-8", "HAPR-12", "TPRT-7", ] COORDINATION_GEOMETRIES_IUCR = Literal[ "[8do]", "[3n]", "[6p]", "[8cb]", "[5by]", "[12p]", "[6p2c]", "[8acb]", "[7by]", "[3l]", "[6p1c]", "[12aco]", "[2l]", "None", "[12i]", "[6o]", "[6p3c]", "[4n]", "[12co]", "[1l]", "[5y]", "[5l]", "[4l]", "[2n]", "[8by]", "[4t]", "[12tt]", ] COORDINATION_GEOMETRIES_NAMES = Literal[ "Pentagonal pyramid", "Metabidiminished icosahedron", "Square-face bicapped trigonal prism", "Pentagonal plane", "Cube", "Triangular cupola", "Heptagonal dipyramid", "Pentagonal prism", "T-shaped", "Square-face capped trigonal prism", "Single neighbor", "Triangular-face bicapped trigonal prism", "Pentagonal-face capped pentagonal antiprism", "Trigonal prism", "Square cupola", "See-saw", "Square non-coplanar", "Hexagonal bipyramid", "Triangular non-coplanar", "Tetrahedron", "Tricapped triangular prism (one square-face cap and two triangular-face caps)", "Square-face monocapped antiprism", "Hexagonal antiprism", "Linear", "Octahedron", "Truncated tetrahedron", "Square-face capped hexagonal prism", "Tricapped octahedron (all 3 cap faces share one atom)", "Bicapped square prism (opposite faces)", "Bicapped octahedron (cap faces with one edge in common)", "Tridiminished icosahedron", "Cuboctahedron", "Dodecahedron", "Dodecahedron with triangular faces - p2345 plane normalized", "Square-face capped square prism", "Icosahedron", "Dodecahedron with triangular faces", "Pentagonal bipyramid", "Tricapped octahedron (cap faces are aligned)", "Square pyramid", "Tricapped triangular prism (three square-face caps)", "Trigonal bipyramid", "Tricapped triangular prism (two square-face caps and one triangular-face cap)", "Pentagonal antiprism", "Diminished icosahedron", "Anticuboctahedron", "Trigonal-face bicapped square antiprism", "Bicapped octahedron (cap faces with one atom in common)", "Hexagonal prism", "Angular", "Trigonal plane", "Square plane", "Bicapped octahedron (opposed cap faces)", "Bicapped square prism (adjacent faces)", "Square antiprism", "Pentagonal-face bicapped pentagonal prism", "Square-face bicapped square antiprism", "Hendecahedron", "End-trigonal-face capped trigonal prism", "Face-capped octahedron", "Tricapped octahedron (all 3 cap faces are sharingone edge of a face)", ] COORDINATION_GEOMETRIES_NAMES_WITH_ALTERNATIVES = Literal[ "Anticuboctahedron (also known as Triangular bicupola)", "Trigonal bipyramid (also known as Trigonal dipyramid, Triangular dipyramid)", "Octahedron (also known as Square dipyramid, Square bipyramid, Triangular antiprism, Trigonal antiprism)", "Diminished icosahedron", "Square antiprism (also known as Tetragonal antiprism, Anticube)", "Square cupola", "Hexagonal bipyramid (also known as Hexagonal dipyramid)", "Square-face capped hexagonal prism", "Bicapped square prism (opposite faces) (also known as Bicapped cube)", "Square-face bicapped trigonal prism", "Square non-coplanar", "Triangular-face bicapped trigonal prism", "Square plane", "Trigonal prism (also known as Triangular prism)", "Bicapped octahedron (opposed cap faces)", "Tricapped octahedron (all 3 cap faces share one atom)", "Pentagonal prism", "Triangular cupola", "Bicapped square prism (adjacent faces) (also known as Bicapped cube)", "Cuboctahedron", "Tricapped triangular prism (two square-face caps and one triangular-face cap) (also known as Triaugmented trigonal prism)", # noqa: E501 "Square-face capped trigonal prism (also known as Augmented triangular prism)", "Tetrahedron (also known as Triangular pyramid, Trigonal pyramid)", "Cube (also known as Square prism, Tetragonal prism)", "Bicapped octahedron (cap faces with one edge in common)", "Bicapped octahedron (cap faces with one atom in common)", "Pentagonal pyramid", "Dodecahedron with triangular faces (also known as Snub disphenoid, Siamese dodecahedron)", "Pentagonal antiprism (also known as Paradiminished icosahedron)", "Tricapped octahedron (cap faces are aligned)", "Icosahedron", "Dodecahedron", "Face-capped octahedron (also known as Monocapped octahedron)", "Angular", "Hendecahedron (also known as Bisymmetric hendecahedron)", "Trigonal-face bicapped square antiprism", "Pentagonal-face capped pentagonal antiprism (also known as Gyroelongated pentagonal pyramid, Diminished icosahedron, Truncated icosahedron)", # noqa: E501 "Linear", "Pentagonal plane (also known as Pentagon)", "Tricapped triangular prism (three square-face caps) (also known as Triaugmented trigonal prism)", "Tricapped octahedron (all 3 cap faces are sharingone edge of a face)", "Heptagonal dipyramid (also known as Heptagonal bipyramid)", "T-shaped", "Single neighbor", "Trigonal plane (also known as Triangular planar)", "Dodecahedron with triangular faces - p2345 plane normalized (also known as Snub disphenoid - p2345 plane normalized, Siamese dodecahedron - p2345 plane normalized)", # noqa: E501 "Tricapped triangular prism (one square-face cap and two triangular-face caps) (also known as Triaugmented trigonal prism)", # noqa: E501 "Truncated tetrahedron", "Hexagonal prism", "Tridiminished icosahedron", "Metabidiminished icosahedron", "See-saw", "Square-face capped square prism (also known as Monocapped cube)", "Square pyramid", "Pentagonal-face bicapped pentagonal prism", "Hexagonal antiprism", "Triangular non-coplanar", "End-trigonal-face capped trigonal prism (also known as Augmented triangular prism)", "Pentagonal bipyramid (also known as Pentagonal dipyramid)", "Square-face monocapped antiprism (also known as Gyroelongated square pyramid)", "Square-face bicapped square antiprism (also known as Square-face bicapped square anticube, Bicapped anticube, Gyroelongated square dipyramid)", # noqa: E501 ] class ChemEnvDoc(PropertyDoc): """ Coordination environments based on cation-anion bonds computed for all unique cations in this structure. If no oxidation states are available, all bonds will be considered as a fall-back. """ property_name: str = "coord_environment" structure: Structure = Field( ..., description="The structure used in the generation of the chemical environment data", ) valences: List[Union[int, float]] = Field( description="List of valences for each site in this material to determine cations" ) species: List[str] = Field( description="List of unique (cationic) species in structure." ) chemenv_symbol: List[COORDINATION_GEOMETRIES] = Field( description="List of ChemEnv symbols for unique (cationic) species in structure" ) chemenv_iupac: List[COORDINATION_GEOMETRIES_IUPAC] = Field( description="List of symbols for unique (cationic) species in structure in IUPAC format" ) chemenv_iucr: List[COORDINATION_GEOMETRIES_IUCR] = Field( description="List of symbols for unique (cationic) species in structure in IUCR format" ) chemenv_name: List[COORDINATION_GEOMETRIES_NAMES] = Field( description="List of text description of coordination environment for unique (cationic) species in structure." ) chemenv_name_with_alternatives: List[ COORDINATION_GEOMETRIES_NAMES_WITH_ALTERNATIVES ] = Field( description="List of text description of coordination environment including alternative descriptions for unique (cationic) species in structure." # noqa: E501 ) csm: List[Union[float, None]] = Field( description="Saves the continous symmetry measures for unique (cationic) species in structure" ) method: Union[str, None] = Field( description="Method used to compute chemical environments" ) mol_from_site_environments: List[Union[Molecule, None]] = Field( description="List of Molecule Objects describing the detected environment." ) # structure_environment: Union[StructureEnvironments, None] = Field( # description="Structure environment object" # ) wyckoff_positions: List[str] = Field( description="List of Wyckoff positions for unique (cationic) species in structure." ) warnings: Optional[str] = Field(None, description="Warning") @classmethod def from_structure( cls, structure: Structure, material_id: MPID, **kwargs, ): # type: ignore[override] """ Args: structure: structure including oxidation states material_id: mpid **kwargs: Returns: """ d = { "valences": [], "species": [], "chemenv_symbol": [], "chemenv_iupac": [], "chemenv_iucr": [], "chemenv_name": [], "chemenv_name_with_alternatives": [], "csm": [], "mol_from_site_environments": [], "wyckoff_positions": [], "method": None, "warnings": None, # "structure_environment": None, } # type: dict # try: list_mol = [] list_chemenv = [] list_chemenv_iupac = [] list_chemenv_iucr = [] list_chemenv_text = [] list_chemenv_text_with_alternatives = [] list_csm = [] list_wyckoff = [] list_species = [] valences = [getattr(site.specie, "oxi_state", None) for site in structure] valences = [v for v in valences if v is not None] sga = SpacegroupAnalyzer(structure) symm_struct = sga.get_symmetrized_structure() # We still need the whole list of indices inequivalent_indices = [ indices[0] for indices in symm_struct.equivalent_indices ] # if len(inequivalent_indices)>5: # print("Too many sites") # raise Exception # wyckoff symbols for all inequivalent indices wyckoffs_unique = symm_struct.wyckoff_symbols # use the local geometry finder to get the important information lgf = LocalGeometryFinder() lgf.setup_structure(structure=structure) all_ce = AllCoordinationGeometries() if len(valences) == len(structure): # Standard alorithm will only focus on cations and cation-anion bonds! method_description = "DefaultSimplestChemenvStrategy" method = AVAILABLE_METHODS[method_description] # We will only focus on cations! inequivalent_indices_cations = [ indices[0] for indices in symm_struct.equivalent_indices if valences[indices[0]] > 0.0 # type: ignore[operator] ] se = lgf.compute_structure_environments( only_indices=inequivalent_indices_cations, valences=valences, maximum_distance_factor=DEFAULT_DISTANCE_CUTOFF, minimum_angle_factor=DEFAULT_ANGLE_CUTOFF, ) lse = LightStructureEnvironments.from_structure_environments( strategy=method, structure_environments=se ) warnings = None else: d.update( { "warnings": "No oxidation states available. Cation-anion bonds cannot be identified." } ) return super().from_structure( meta_structure=structure, material_id=material_id, structure=structure, **d, **kwargs, ) # method_description = "DefaultSimplestChemenvStrategy_all_bonds" # method = AVAILABLE_METHODS[method_description] # se = lgf.compute_structure_environments( # only_indices=inequivalent_indices, # ) # lse = LightStructureEnvironments.from_structure_environments(strategy=method, # structure_environments=se) # Trick to get rid of duplicate code # inequivalent_indices_cations = inequivalent_indices # warnings = "No oxidation states. Analysis will now include all bonds" for index, wyckoff in zip(inequivalent_indices, wyckoffs_unique): # ONLY CATIONS if index in inequivalent_indices_cations: # Coordinaton environment will be saved as a molecule! mol = Molecule.from_sites( [structure[index]] + lse.neighbors_sets[index][0].neighb_sites ) mol = mol.get_centered_molecule() env = lse.coordination_environments[index] co = all_ce.get_geometry_from_mp_symbol(env[0]["ce_symbol"]) name = co.name if co.alternative_names: name += f" (also known as {', '.join(co.alternative_names)})" # save everything in a list list_chemenv_text.append(co.name) list_chemenv_text_with_alternatives.append(name) list_chemenv.append(co.ce_symbol) list_chemenv_iucr.append(co.IUCr_symbol_str) list_chemenv_iupac.append(co.IUPAC_symbol_str) list_mol.append(mol) list_wyckoff.append(wyckoff) list_species.append(structure[index].species_string) list_csm.append(env[0]["csm"]) d.update( { "valences": valences, "species": list_species, "chemenv_symbol": list_chemenv, "chemenv_iupac": list_chemenv_iupac, "chemenv_iucr": list_chemenv_iucr, "chemenv_name": list_chemenv_text, "chemenv_name_with_alternatives": list_chemenv_text_with_alternatives, "csm": list_csm, "mol_from_site_environments": list_mol, "wyckoff_positions": list_wyckoff, # "structure_environment": se.as_dict(), "method": METHODS_DESCRIPTION[method_description], "warnings": warnings, } ) # except Exception: # d.update({"warnings": "ChemEnv algorithm failed."}) return super().from_structure( meta_structure=structure, material_id=material_id, structure=structure, **d, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/common.py0000644000175100001770000000064614673360562017172 0ustar00runnerdockerfrom emmet.core.utils import ValueEnum from datetime import datetime from monty.json import MontyDecoder def convert_datetime(cls, v): if isinstance(v, dict): if v.get("$date"): return datetime.fromisoformat(v["$date"]) return MontyDecoder().process_decoded(v) class Status(ValueEnum): """ State of a calculation/analysis. """ SUCCESS = "successful" FAILED = "failed" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/corrected_entries.py0000644000175100001770000000213114673360562021374 0ustar00runnerdocker""" Core definition of a CorrectedEntriesDoc Document """ from typing import Dict, Union, List, Optional from datetime import datetime from pydantic import Field from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.base import EmmetBaseModel from emmet.core.thermo import ThermoType from emmet.core.vasp.calc_types.enums import RunType class CorrectedEntriesDoc(EmmetBaseModel): """ A corrected entries document """ property_name: str = "corrected_entries" chemsys: str = Field( ..., title="Chemical System", description="Dash-delimited string of elements in the material.", ) entries: Dict[ Union[ThermoType, RunType], Optional[List[Union[ComputedEntry, ComputedStructureEntry]]], ] = Field( ..., description="List of all corrected entries that are valid for the specified thermo type.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property.", default_factory=datetime.utcnow, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/defect.py0000644000175100001770000001013314673360562017124 0ustar00runnerdockerfrom __future__ import annotations from pydantic import Field from emmet.core.tasks import TaskDoc, _VOLUMETRIC_FILES from typing import TYPE_CHECKING from pymatgen.analysis.defects.core import Defect from monty.json import MontyDecoder from pydantic import BaseModel if TYPE_CHECKING: from typing import Any, Dict, Optional, Tuple, Union from pathlib import Path mdecoder = MontyDecoder().process_decoded class DefectInfo(BaseModel): """Information related to a point defect.""" defect_name: str = Field( title="The name of the defect", ) bulk_formula: str = Field( title="Bulk Formula", description="Formula of the bulk structure.", ) defect: Defect = Field( title="Defect Object", description="Unit cell representation of the defect object.", ) charge_state: int = Field( None, title="Charge State", description="Charge state of the defect.", ) supercell_matrix: list = Field( None, title="Supercell Matrix", description="Supercell matrix used to construct the defect supercell.", ) class DefectTaskDoc(DefectInfo, TaskDoc): """Defect Task Document. Contains all the task-level information for a defect supercell calculation. """ @classmethod def from_directory( cls, dir_name: Union[Path, str], volumetric_files: Tuple[str, ...] = _VOLUMETRIC_FILES, additional_fields: Optional[Dict[str, Any]] = None, volume_change_warning_tol: float = 0.2, defect_info_key: str = "info", **vasp_calculation_kwargs, ) -> TaskDoc: """ Create a task document from a directory containing VASP files. Parameters ---------- dir_name The path to the folder containing the calculation outputs. store_additional_json Whether to store additional json files found in the calculation directory. volumetric_files Volumetric files to search for. additional_fields Dictionary of additional fields to add to output document. volume_change_warning_tol Maximum volume change allowed in VASP relaxations before the calculation is tagged with a warning. defect_info_key The key in the `additional_json` to extract the defect information from **vasp_calculation_kwargs Additional parsing options that will be passed to the :obj:`.Calculation.from_vasp_files` function. Returns ------- TaskDoc A task document for the calculation. """ tdoc = TaskDoc.from_directory( dir_name=dir_name, volumetric_files=volumetric_files, store_additional_json=True, additional_fields=additional_fields, volume_change_warning_tol=volume_change_warning_tol, **vasp_calculation_kwargs, ) return cls.from_taskdoc(tdoc, defect_info_key=defect_info_key) @classmethod def from_taskdoc( cls, taskdoc: TaskDoc, defect_info_key: str = "info", ) -> DefectTaskDoc: """ Create a DefectTaskDoc from a TaskDoc Args: taskdoc: TaskDoc to convert defect_info_key: The key in the `additional_json` to extract the defect information from Returns: DefectTaskDoc """ additional_info = taskdoc.additional_json[defect_info_key] defect = additional_info["defect"] charge_state = additional_info["charge_state"] defect_name = additional_info["defect_name"] bulk_formula = additional_info["bulk_formula"] supercell_matrix = additional_info["sc_mat"] task_dict = taskdoc.model_dump() task_dict.update( { "defect_name": defect_name, "defect": defect, "charge_state": charge_state, "bulk_formula": bulk_formula, "supercell_matrix": supercell_matrix, } ) return cls(**task_dict) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/dois.py0000644000175100001770000000103714673360562016633 0ustar00runnerdockerfrom pydantic import BaseModel, Field from typing import Optional class DOIDoc(BaseModel): """ DOIs to reference specific materials on Materials Project. """ doi: Optional[str] = Field( None, description="DOI of the material.", ) bibtex: Optional[str] = Field( None, description="Bibtex reference of the material.", ) material_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/elasticity.py0000644000175100001770000006311014673360562020047 0ustar00runnerdockerfrom __future__ import annotations from typing import Any, Dict, List, Optional, Tuple, Union import numpy as np from pydantic import BaseModel, Field from pymatgen.analysis.elasticity.elastic import ElasticTensor, ElasticTensorExpansion from pymatgen.analysis.elasticity.strain import Deformation, Strain from pymatgen.analysis.elasticity.stress import Stress from pymatgen.core.structure import Structure from pymatgen.core.tensors import TensorMapping from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from emmet.core.common import Status from emmet.core.material_property import PropertyDoc from emmet.core.math import Matrix3D, MatrixVoigt from emmet.core.mpid import MPID from emmet.core.settings import EmmetSettings SETTINGS = EmmetSettings() class ElasticTensorDoc(BaseModel): raw: Optional[MatrixVoigt] = Field( None, description="Elastic tensor corresponding to structure orientation (GPa)", ) ieee_format: Optional[MatrixVoigt] = Field( None, description="Elastic tensor corresponding to IEEE orientation (GPa)", ) class ComplianceTensorDoc(BaseModel): raw: Optional[MatrixVoigt] = Field( None, description="Compliance tensor corresponding to structure orientation (TPa^-1)", ) ieee_format: Optional[MatrixVoigt] = Field( None, description="Compliance tensor corresponding to IEEE orientation (TPa^-1)", ) class BulkModulus(BaseModel): voigt: Optional[float] = Field(None, description="Bulk modulus Voigt average (GPa)") reuss: Optional[float] = Field(None, description="Bulk modulus Reuss average (GPa)") vrh: Optional[float] = Field( None, description="Bulk modulus Voigt-Reuss-Hill average (GPa)" ) class ShearModulus(BaseModel): voigt: Optional[float] = Field( None, description="Shear modulus Voigt average (GPa)" ) reuss: Optional[float] = Field( None, description="Shear modulus Reuss average (GPa)" ) vrh: Optional[float] = Field( None, description="Shear modulus Voigt-Reuss-Hill average (GPa)" ) class SoundVelocity(BaseModel): transverse: Optional[float] = Field( None, description="Transverse sound velocity (SI units)" ) longitudinal: Optional[float] = Field( None, description="Longitudinal sound velocity (SI units)" ) snyder_acoustic: Optional[float] = Field( None, description="Snyder's acoustic sound velocity (SI units)" ) snyder_optical: Optional[float] = Field( None, description="Snyder's optical sound velocity (SI units)" ) snyder_total: Optional[float] = Field( None, description="Snyder's total sound velocity (SI units)" ) class ThermalConductivity(BaseModel): clarke: Optional[float] = Field( None, description="Clarke's thermal conductivity (SI units)" ) cahill: Optional[float] = Field( None, description="Cahill's thermal conductivity (SI units)" ) class FittingData(BaseModel): """ Data used to fit the elastic tensor. Note, this only consists of the explicitly calculated primary data. With the data here, one can redo the fitting to regenerate the elastic data, e.g. using `ElasticityDoc.from_deformations_and_stresses()`. """ # data of strained structures deformations: List[Matrix3D] = Field( description="Deformations corresponding to the strained structures" ) strains: List[Matrix3D] = Field( description="Lagrangian strain tensors applied to structures" ) cauchy_stresses: List[Matrix3D] = Field( description="Cauchy stress tensors on strained structures" ) second_pk_stresses: List[Matrix3D] = Field( description="Second Piola-Kirchhoff stress tensors on structures" ) deformation_tasks: Optional[List[MPID]] = Field( None, description="Deformation task ids corresponding to the strained structures", ) deformation_dir_names: Optional[List[str]] = Field( None, description="Paths to the running directories of deformation tasks" ) # data of equilibrium structure equilibrium_cauchy_stress: Optional[Matrix3D] = Field( None, description="Cauchy stress tensor of the relaxed structure" ) optimization_task: Optional[MPID] = Field( None, description="Optimization task corresponding to the relaxed structure" ) optimization_dir_name: Optional[str] = Field( None, description="Path to the running directory of the optimization task" ) # derived strains stresses num_total_strain_stress_states: Optional[int] = Field( None, description="Number of total strain--stress states used for fitting, i.e. the " "sum of explicitly calculated deformations and derived deformations from " "symmetry.", ) class CriticalMessage(BaseModel): FITTING: str = "Critical: cannot fit elastic tensor. Error: {}." COMPLIANCE: str = ( "Critical: cannot invert elastic tensor to get compliance tensor. Error: {}." ) STRAIN_RANK: str = ( "Critical: insufficient number of valid strains. Expect the matrix of all " "strains to be of rank 6; got rank {}." ) N_STATES: str = ( "Critical: Expect 24 total (primary plus derived) strain--stress states " "to fit the data; got {}." ) class WarningMessage(BaseModel): NEGATIVE_EIGVAL: str = ( "Elastic tensor has negative eigenvalue(s), indicating that the structure is " "mechanically unstable." ) # https://doi.org/10.1103/PhysRevB.90.224104 NEGATIVE_MODULUS: str = ( "Negative modulus: {} {} is {}, indicating that the structure is mechanically " "unstable." ) SMALL_MODULUS: str = "Small modulus. {} {} is {}; smaller than {}." LARGE_MODULUS: str = "Large modulus. {} {} is {}; larger than {}." LARGE_YOUNG_MODULUS: str = "Large Young's modulus {}; larger than {}." LARGE_COMPONENT: str = "Elastic tensor has component larger than {}." class ElasticityDoc(PropertyDoc): property_name: str = "elasticity" structure: Optional[Structure] = Field( None, description="Structure to compute the elasticity" ) order: int = Field( default=2, description="Order of the expansion of the elastic tensor" ) elastic_tensor: Optional[ElasticTensorDoc] = Field( None, description="Elastic tensor" ) compliance_tensor: Optional[ComplianceTensorDoc] = Field( None, description="Compliance tensor" ) # derived properties bulk_modulus: Optional[BulkModulus] = Field(None, description="Bulk modulus") shear_modulus: Optional[ShearModulus] = Field(None, description="Shear modulus") sound_velocity: Optional[SoundVelocity] = Field(None, description="Sound velocity") thermal_conductivity: Optional[ThermalConductivity] = Field( None, description="Thermal conductivity" ) young_modulus: float = Field( None, description="Young's modulus (SI units)", alias="youngs_modulus" ) universal_anisotropy: float = Field( None, description="Universal elastic anisotropy" ) homogeneous_poisson: Optional[float] = Field( None, description="Homogeneous Poisson ratio" ) debye_temperature: Optional[float] = Field( None, description="Debye temperature (SI units)" ) fitting_data: Optional[FittingData] = Field( None, description="Data used to fit the elastic tensor" ) fitting_method: Optional[str] = Field( None, description="Method used to fit the elastic tensor" ) state: Optional[Status] = Field( None, description="State of the fitting/analysis: `successful` or `failed`", ) @classmethod def from_deformations_and_stresses( cls, structure: Structure, material_id: MPID, deformations: List[Deformation], stresses: List[Stress], deformation_task_ids: Optional[List[MPID]] = None, deformation_dir_names: Optional[List[str]] = None, equilibrium_stress: Optional[Stress] = None, optimization_task_id: Optional[MPID] = None, optimization_dir_name: Optional[str] = None, fitting_method: str = "finite_difference", **kwargs, ): """ Fitting the elastic tensor from deformation and stresses. Note, the elastic tensor are obtained by fitting to the Lagrangian strains and second Piola-Kirchhoff stresses. In continuum mechanics nomenclature, it's the `material elasticity tensor`. For more, see Section 6.5 of `Continuum Mechanics and Thermodynamics -- From Fundamental Concepts to Governing Equations` Tadmor, Miller, and Elliott, Cambridge University Press, 2012. Args: structure: relaxed structure. material_id: material id. deformations: deformations applied to the relaxed structure that generate the strained structures. stresses: Cauchy stresses on the deformed structures. Expected units: GPa. deformation_task_ids: id of the deformation tasks. deformation_dir_names: directories where the deformation tasks are run. equilibrium_stress: Cauchy stress on the relaxed structure. optimization_task_id: id of the optimization task to relax the structure. optimization_dir_name: directory where the optimization task run. fitting_method: method used to fit the elastic tensor: {`finite_difference`, `pseudoinverse`, `independent`}. """ CM = CriticalMessage() # primary fitting data p_deforms = deformations p_stresses = stresses ( p_strains, p_2nd_pk_stresses, p_task_ids, p_dir_names, ) = generate_primary_fitting_data( p_deforms, p_stresses, deformation_task_ids, deformation_dir_names ) # derived fitting data ( d_deforms, d_strains, d_stresses, d_2nd_pk_stresses, ) = generate_derived_fitting_data(structure, p_strains, p_stresses) fitting_strains = p_strains + d_strains fitting_stresses = p_2nd_pk_stresses + d_2nd_pk_stresses # avoid symmop-related strains having non-symmop-related stresses fitting_stresses = symmetrize_stresses( fitting_stresses, fitting_strains, structure ) # fitting elastic tensor try: elastic_tensor = fit_elastic_tensor( fitting_strains, fitting_stresses, eq_stress=equilibrium_stress, fitting_method=fitting_method, ) # elastic and compliance tensors, only round ieee format ones ieee_et = elastic_tensor.voigt_symmetrized.convert_to_ieee(structure) et_doc = ElasticTensorDoc( raw=elastic_tensor.voigt.tolist(), ieee_format=ieee_et.round(0).voigt.tolist(), ) except np.linalg.LinAlgError as e: et_doc = None ct_doc = None derived_props = {} state = Status("failed") warnings = [CM.FITTING.format(e)] else: try: compliance = elastic_tensor.compliance_tensor compliance_ieee = ieee_et.compliance_tensor # compliance tensor, *1000 to convert units to TPa^-1, i.e. 10^-12 Pa, # assuming elastic tensor in units of GPa ct_doc = ComplianceTensorDoc( raw=(compliance * 1000).voigt.tolist(), ieee_format=(compliance_ieee * 1000).round(0).voigt.tolist(), ) # derived properties # (should put it here since some derived properties also dependent on # compliance tensor) derived_props = get_derived_properties(structure, elastic_tensor) # check all state, warnings = sanity_check( structure, et_doc, fitting_strains, derived_props # type: ignore ) except np.linalg.LinAlgError as e: ct_doc = None derived_props = {} state = Status("failed") warnings = [CM.COMPLIANCE.format(e)] # fitting data eq_stress = None if equilibrium_stress is None else equilibrium_stress.tolist() n_states = len(p_deforms) + len(d_deforms) if n_states != 24: warnings.append(CM.N_STATES.format(n_states)) state = Status("failed") fitting_data = FittingData( deformations=[x.tolist() for x in p_deforms], # type: ignore strains=[x.tolist() for x in p_strains], # type: ignore cauchy_stresses=[x.tolist() for x in p_stresses], # type: ignore second_pk_stresses=[x.tolist() for x in p_2nd_pk_stresses], # type: ignore deformation_tasks=p_task_ids, # type: ignore deformation_dir_names=p_dir_names, # type: ignore equilibrium_cauchy_stress=eq_stress, optimization_task=optimization_task_id, optimization_dir_name=optimization_dir_name, # type: ignore num_total_strain_stress_states=n_states, ) return cls.from_structure( structure, material_id, structure=structure, order=2, elastic_tensor=et_doc, compliance_tensor=ct_doc, fitting_data=fitting_data, fitting_method=fitting_method, warnings=warnings, state=state, deprecated=state == Status("failed"), **derived_props, **kwargs, ) def generate_primary_fitting_data( deforms: List[Deformation], stresses: List[Stress], task_ids: Optional[List[MPID]] = None, dir_names: Optional[List[str]] = None, ) -> Tuple[ List[Strain], List[Stress], Union[List[MPID], None], Union[List[str], None], ]: """ Get the primary fitting data, i.e. data obtained from a calculation. Args: deforms: primary deformations stresses: primary stresses task_ids: ids of the tasks that generate the data dir_names: directories where the calculations are performed Returns: strains: primary strains second_pk_stresses: primary second Piola-Kirchhoff stresses task_ids: ids of the tasks that generate the data dir_names: directories where the calculations are performed """ size = len(deforms) assert len(stresses) == size if task_ids is not None: assert len(task_ids) == size if dir_names is not None: assert len(dir_names) == size strains = [d.green_lagrange_strain for d in deforms] second_pk_stresses = [s.piola_kirchoff_2(d) for (s, d) in zip(stresses, deforms)] return strains, second_pk_stresses, task_ids, dir_names def generate_derived_fitting_data( structure: Structure, strains: List[Strain], stresses: List[Stress], symprec=SETTINGS.SYMPREC, ) -> Tuple[List[Deformation], List[Strain], List[Stress], List[Stress]]: """ Get the derived fitting data from symmetry operations on the primary fitting data. It can happen that multiple primary deformations can be mapped to the same derived deformation from different symmetry operations. Ideally, this cannot happen if one use the same structure to determine all the symmetry operations. However, this is not the case in atomate, where the deformation tasks are determined based on the symmetry of the structure before the tight relaxation, which in this function the structure is the relaxed structure. The symmetries can be different. In atomate2, this is not a problem, because the deformation tasks are determined based on the relaxed structure. To make it work for all cases, the stress for a derived deformation is the average of all derived stresses, each corresponding to a primary calculation. In doing so, we also check to ensure that: 1. only independent derived deformations are used 2. for a specific derived strain, a primary deformation is only used (mapped) once to obtain the average Args: structure: relaxed structure strains: primary strains stresses: primary stresses symprec: symmetry operation precision Returns: derived_deforms: derived deformations derived_strains: derived strains derived_stresses: derived Cauchy stresses derived_2nd_pk_stresses: derived second Piola-Kirchhoff stresses """ sga = SpacegroupAnalyzer(structure, symprec=symprec) symmops = sga.get_symmetry_operations(cartesian=True) # primary strain mapping (used only for checking purpose below) p_mapping = TensorMapping(strains, strains) # generated derived deforms mapping = TensorMapping() for i, p_strain in enumerate(strains): for op in symmops: d_strain = p_strain.transform(op) # sym op generates another primary strain if d_strain in p_mapping: continue # seen this derived deform before if d_strain in mapping: # all the existing `i` current = [t[1] for t in mapping[d_strain]] if i not in current: mapping[d_strain].append((op, i)) # not seen this derived deform before else: mapping[d_strain] = [(op, i)] # get average stress from derived deforms derived_strains = [] derived_stresses = [] derived_deforms = [] derived_2nd_pk_stresses = [] for d_strain, op_set in mapping.items(): symmops, p_indices = zip(*op_set) # type: ignore[assignment] p_stresses = [stresses[i] for i in p_indices] d_stresses = [s.transform(op) for s, op in zip(p_stresses, symmops)] d_stress = Stress(np.average(d_stresses, axis=0)) derived_strains.append(d_strain) derived_stresses.append(d_stress) deform = d_strain.get_deformation_matrix() derived_deforms.append(deform) derived_2nd_pk_stresses.append(d_stress.piola_kirchoff_2(deform)) return derived_deforms, derived_strains, derived_stresses, derived_2nd_pk_stresses def symmetrize_stresses( stresses: List[Stress], strains: List[Strain], structure: Structure, symprec=SETTINGS.SYMPREC, tol: float = 0.002, ) -> List[Stress]: """ Symmetrize stresses by averaging over all symmetry operations. Args: stresses: stresses to be symmetrized strains: strains corresponding to the stresses structure: materials structure symprec: symmetry operation precision tol: tolerance for comparing strains and also for determining whether the deformation corresponds to the train is independent. The elastic workflow use a minimum strain of 0.005, so the default tolerance of 0.002 should be able to distinguish different strain states. Returns: symmetrized stresses """ sga = SpacegroupAnalyzer(structure, symprec=symprec) symmops = sga.get_symmetry_operations(cartesian=True) # for each strain, get the stresses from other strain states related by symmetry symmmetrized_stresses = [] # type: List[Stress] for strain, _stress in zip(strains, stresses): mapping = TensorMapping([strain], [[]], tol=tol) for strain2, stress2 in zip(strains, stresses): for op in symmops: if strain2.transform(op) in mapping: mapping[strain].append(stress2.transform(op)) sym_stress = np.average(mapping[strain], axis=0) symmmetrized_stresses.append(Stress(sym_stress)) return symmmetrized_stresses def fit_elastic_tensor( strains: List[Strain], stresses: List[Stress], eq_stress: Stress | None, fitting_method: str = "finite_difference", order: int = 2, ) -> ElasticTensor: """ Fitting the elastic tensor. Args: strains: strains (primary and derived) to fit the elastic tensor stresses: stresses (primary and derived) to fit the elastic tensor eq_stress: equilibrium stress, i.e. stress on the relaxed structure fitting_method: method used to fit the elastic tensor: {`finite_difference`, `pseudoinverse`, `independent`} order: expansion order of the elastic tensor, 2 or 3 Returns: fitted elastic tensor """ if order > 2 or fitting_method == "finite_difference": # force finite diff if order > 2 result = ElasticTensorExpansion.from_diff_fit( strains, stresses, eq_stress=eq_stress, order=order ) if order == 2: result: ElasticTensor = ElasticTensor(result[0]) # type: ignore[no-redef] elif fitting_method == "pseudoinverse": result: ElasticTensor = ElasticTensor.from_pseudoinverse(strains, stresses) # type: ignore[no-redef] elif fitting_method == "independent": result: ElasticTensor = ElasticTensor.from_independent_strains( # type: ignore[no-redef] strains, stresses, eq_stress=eq_stress ) else: raise ValueError(f"Unsupported elastic fitting method {fitting_method}") return result # type: ignore[return-value] def get_derived_properties( structure: Structure, tensor: ElasticTensor ) -> Dict[str, Any]: """ Get derived elasticity properties. Args: structure: relaxed structure tensor: elastic tensor corresponding to the structure Returns: a dict of derived elasticity properties """ try: prop_dict = tensor.get_structure_property_dict(structure) prop_dict.pop("structure") structure_prop_computed = True except ValueError: prop_dict = tensor.property_dict structure_prop_computed = False decimals = 3 derived_prop = { "bulk_modulus": BulkModulus( voigt=np.round(prop_dict["k_voigt"], decimals), # type: ignore[arg-type] reuss=np.round(prop_dict["k_reuss"], decimals), # type: ignore[arg-type] vrh=np.round(prop_dict["k_vrh"], decimals), # type: ignore[arg-type] ), "shear_modulus": ShearModulus( voigt=np.round(prop_dict["g_voigt"], decimals), # type: ignore[arg-type] reuss=np.round(prop_dict["g_reuss"], decimals), # type: ignore[arg-type] vrh=np.round(prop_dict["g_vrh"], decimals), # type: ignore[arg-type] ), "young_modulus": np.round(prop_dict["y_mod"], 0), # type: ignore[arg-type] "homogeneous_poisson": np.round(prop_dict["homogeneous_poisson"], decimals), # type: ignore[arg-type] "universal_anisotropy": np.round(prop_dict["universal_anisotropy"], decimals), # type: ignore[arg-type] } if structure_prop_computed: derived_prop.update( { "sound_velocity": SoundVelocity( transverse=prop_dict["trans_v"], # type: ignore[arg-type] longitudinal=prop_dict["long_v"], # type: ignore[arg-type] snyder_acoustic=prop_dict["snyder_ac"], # type: ignore[arg-type] snyder_optical=prop_dict["snyder_opt"], # type: ignore[arg-type] snyder_total=prop_dict["snyder_total"], # type: ignore[arg-type] ), "thermal_conductivity": ThermalConductivity( clarke=prop_dict["clarke_thermalcond"], # type: ignore[arg-type] cahill=prop_dict["cahill_thermalcond"], # type: ignore[arg-type] ), "debye_temperature": prop_dict["debye_temperature"], # type: ignore[arg-type] } ) return derived_prop def sanity_check( structure: Structure, elastic_doc: ElasticTensorDoc, strains: List[Strain], derived_props: Dict[str, Any], ) -> Tuple[Status, List[str]]: """ Post analysis to generate warnings if any. Returns: state: state of the calculation warnings: all warning messages. Messages starting with `Critical` are the ones resulting in a `failed` state. """ failed = False warnings = [] CM = CriticalMessage() WM = WarningMessage() # rank of all strains < 6? voigt_strains = [s.voigt for s in strains] rank = np.linalg.matrix_rank(voigt_strains) if rank != 6: failed = True warnings.append(CM.STRAIN_RANK.format(rank)) # elastic tensor eigenvalues eig_vals, _ = np.linalg.eig(elastic_doc.raw) # type: ignore if np.any(eig_vals < 0.0): warnings.append(WM.NEGATIVE_EIGVAL) # elastic tensor individual components et = np.asarray(elastic_doc.ieee_format) tol = 1e6 if np.any(et > tol): warnings.append(WM.LARGE_COMPONENT.format(tol)) # modulus low = 2.0 high = 1000.0 for p in ["bulk_modulus", "shear_modulus"]: doc = derived_props[p] doc = doc.model_dump() p = p.replace("_", " ") for name in ["voigt", "reuss", "vrh"]: v = doc[name] if v < 0: failed = True warnings.append(WM.NEGATIVE_MODULUS.format(name, p, v)) elif v < low: warnings.append(WM.SMALL_MODULUS.format(name, p, v, low)) elif v > high: warnings.append(WM.LARGE_MODULUS.format(name, p, v, high)) # young's modulus (note it is in Pa, not GPa) high = 1e12 v = derived_props["young_modulus"] if v > high: warnings.append(WM.LARGE_YOUNG_MODULUS.format(v, high)) state = Status("failed") if failed else Status("successful") return state, warnings ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/elasticity_legacy.py0000644000175100001770000000403614673360562021375 0ustar00runnerdockerfrom typing import List, Optional from pydantic import BaseModel, Field class ElasticityData(BaseModel): """ Elastic tensors and associated information. """ k_voigt: Optional[float] = Field( None, description="Voigt average of the bulk modulus in GPa.", ) k_reuss: Optional[float] = Field( None, description="Reuss average of the bulk modulus in GPa.", ) k_vrh: Optional[float] = Field( None, description="Voigt-Reuss-Hill average of the bulk modulus in GPa.", ) g_voigt: Optional[float] = Field( None, description="Voigt average of the shear modulus in GPa.", ) g_reuss: Optional[float] = Field( None, description="Reuss average of the shear modulus in GPa.", ) g_vrh: Optional[float] = Field( None, description="Voigt-Reuss-Hill average of the shear modulus in GPa.", ) universal_anisotropy: Optional[float] = Field( None, description="Elastic anisotropy.", ) homogeneous_poisson: Optional[float] = Field( None, description="Poisson's ratio.", ) elastic_tensor: Optional[List[List[float]]] = Field( None, description="Stiffness tensor in GPa.", ) compliance_tensor: Optional[List[List[float]]] = Field( None, description="Compliance tensor in 10^(-12)/Pa.", ) class ElasticityDoc(BaseModel): """ Model for a document containing elasticity data """ pretty_formula: Optional[str] = Field( None, description="Cleaned representation of the material formula", ) chemsys: Optional[str] = Field( None, description="Dash-delimited string of elements in the material.", ) elasticity: Optional[ElasticityData] = Field( None, description="Elasticity data for the material.", ) task_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/electrode.py0000644000175100001770000004756414673360562017662 0ustar00runnerdockerfrom __future__ import annotations import re from collections import defaultdict from datetime import datetime from typing import Dict, List, Optional, Union from pydantic import BaseModel, Field, field_validator from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.apps.battery.battery_abc import AbstractElectrode from pymatgen.apps.battery.conversion_battery import ConversionElectrode from pymatgen.apps.battery.insertion_battery import InsertionElectrode from pymatgen.core import Composition, Structure from pymatgen.core.periodic_table import DummySpecies, Element, Species from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.common import convert_datetime from emmet.core.mpid import MPID from emmet.core.utils import ValueEnum class BatteryType(str, ValueEnum): """ Enum for battery type """ insertion = "insertion" conversion = "conversion" class VoltagePairDoc(BaseModel): """ Data for individual voltage steps. Note: Each voltage step is represented as a sub_electrode (ConversionElectrode/InsertionElectrode) object to gain access to some basic statistics about the voltage step """ formula_charge: Optional[str] = Field( None, description="The chemical formula of the charged material." ) formula_discharge: Optional[str] = Field( None, description="The chemical formula of the discharged material." ) max_delta_volume: Optional[float] = Field( None, description="Volume changes in % for a particular voltage step using: " "max(charge, discharge) / min(charge, discharge) - 1.", ) average_voltage: Optional[float] = Field( None, description="The average voltage in V for a particular voltage step." ) capacity_grav: Optional[float] = Field( None, description="Gravimetric capacity in mAh/g." ) capacity_vol: Optional[float] = Field( None, description="Volumetric capacity in mAh/cc." ) energy_grav: Optional[float] = Field( None, description="Gravimetric energy (Specific energy) in Wh/kg." ) energy_vol: Optional[float] = Field( None, description="Volumetric energy (Energy Density) in Wh/l." ) fracA_charge: Optional[float] = Field( None, description="Atomic fraction of the working ion in the charged state." ) fracA_discharge: Optional[float] = Field( None, description="Atomic fraction of the working ion in the discharged state." ) @classmethod def from_sub_electrode(cls, sub_electrode: AbstractElectrode, **kwargs): """ Convert a pymatgen electrode object to a document """ return cls(**sub_electrode.get_summary_dict(), **kwargs) class InsertionVoltagePairDoc(VoltagePairDoc): """ Features specific to insertion electrode """ stability_charge: Optional[float] = Field( None, description="The energy above hull of the charged material in eV/atom." ) stability_discharge: Optional[float] = Field( None, description="The energy above hull of the discharged material in eV/atom." ) id_charge: Optional[Union[MPID, int, None]] = Field( None, description="The Materials Project ID of the charged structure." ) id_discharge: Optional[Union[MPID, int, None]] = Field( None, description="The Materials Project ID of the discharged structure." ) class ConversionVoltagePairDoc(VoltagePairDoc): """ Features specific to conversion electrode """ reaction: Optional[dict] = Field( None, description="The reaction that characterizes that particular voltage step.", ) class EntriesCompositionSummary(BaseModel): """ Composition summary data for all material entries associated with this electrode. Included to enable better searching via the API. """ all_formulas: Optional[List[str]] = Field( None, description="Reduced formulas for material entries across all voltage pairs.", ) all_chemsys: Optional[List[str]] = Field( None, description="Chemical systems for material entries across all voltage pairs.", ) all_formula_anonymous: Optional[List[str]] = Field( None, description="Anonymous formulas for material entries across all voltage pairs.", ) all_elements: Optional[List[Union[Element, Species, DummySpecies]]] = Field( None, description="Elements in material entries across all voltage pairs.", ) all_composition_reduced: Optional[Dict] = Field( None, description="Composition reduced data for entries across all voltage pairs.", ) @classmethod def from_compositions(cls, compositions: List[Composition]): all_formulas = list({comp.reduced_formula for comp in compositions}) all_chemsys = list({comp.chemical_system for comp in compositions}) all_formula_anonymous = list({comp.anonymized_formula for comp in compositions}) all_elements = sorted(compositions)[-1].elements all_composition_reduced = defaultdict(set) for comp in compositions: comp_red = comp.get_reduced_composition_and_factor()[0].as_dict() for ele, num in comp_red.items(): all_composition_reduced[ele].add(num) return cls( all_formulas=all_formulas, all_chemsys=all_chemsys, all_formula_anonymous=all_formula_anonymous, all_elements=all_elements, all_composition_reduced={ k: sorted(list(v)) for k, v in all_composition_reduced.items() }, ) class BaseElectrode(BaseModel): battery_type: Optional[BatteryType] = Field( None, description="The type of battery (insertion or conversion)." ) battery_id: Optional[str] = Field( None, description="The id for this battery document is the numerically smallest material_id followed by " "the working ion.", ) thermo_type: Optional[str] = Field( None, description="The functional type used to compute the thermodynamics of this electrode document.", ) battery_formula: Optional[str] = Field( None, description="Reduced formula with working ion range produced by combining the charge and discharge formulas.", ) working_ion: Optional[Element] = Field( None, description="The working ion as an Element object." ) num_steps: Optional[int] = Field( None, description="The number of distinct voltage steps in from fully charge to " "discharge based on the stable intermediate states.", ) max_voltage_step: Optional[float] = Field( None, description="Maximum absolute difference in adjacent voltage steps." ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this Material document.", ) framework: Optional[Composition] = Field( None, description="The chemical compositions of the host framework." ) framework_formula: Optional[str] = Field( None, description="The id for this battery document." ) elements: Optional[List[Element]] = Field( None, description="The atomic species contained in this electrode (not including the working ion).", ) nelements: Optional[int] = Field( None, description="The number of elements in the material (not including the working ion).", ) chemsys: Optional[str] = Field( None, description="The chemical system this electrode belongs to (not including the working ion).", ) formula_anonymous: Optional[str] = Field( None, title="Anonymous Formula", description="Anonymized representation of the formula (not including the working ion).", ) warnings: List[str] = Field( [], description="Any warnings related to this electrode data." ) # Make sure that the datetime field is properly formatted @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) class InsertionElectrodeDoc(InsertionVoltagePairDoc, BaseElectrode): """ Insertion electrode """ host_structure: Optional[Structure] = Field( None, description="Host structure (structure without the working ion)." ) adj_pairs: Optional[List[InsertionVoltagePairDoc]] = Field( None, description="Returns all of the voltage steps material pairs." ) material_ids: Optional[List[MPID]] = Field( None, description="The ids of all structures that matched to the present host lattice, regardless of stability. " "The stable entries can be found in the adjacent pairs.", ) entries_composition_summary: Optional[EntriesCompositionSummary] = Field( None, description="Composition summary data for all material in entries across all voltage pairs.", ) electrode_object: Optional[InsertionElectrode] = Field( None, description="The Pymatgen electrode object." ) @classmethod def from_entries( cls, grouped_entries: List[ComputedStructureEntry], working_ion_entry: ComputedEntry, battery_id: str, strip_structures: bool = False, ) -> Union["InsertionElectrodeDoc", None]: try: ie = InsertionElectrode.from_entries( entries=grouped_entries, working_ion_entry=working_ion_entry, strip_structures=strip_structures, ) except IndexError: return None d = cls.get_elec_doc(ie) d["last_updated"] = datetime.utcnow() stripped_host = ie.fully_charged_entry.structure.copy() stripped_host.remove_species([d["working_ion"]]) elements = stripped_host.composition.elements chemsys = stripped_host.composition.chemical_system framework = Composition(d["framework_formula"]) dchg_comp = Composition(d["formula_discharge"]) battery_formula = get_battery_formula( Composition(d["formula_charge"]), dchg_comp, ie.working_ion, ) compositions = [] for doc in d["adj_pairs"]: compositions.append(Composition(doc["formula_charge"])) compositions.append(Composition(doc["formula_discharge"])) entries_composition_summary = EntriesCompositionSummary.from_compositions( compositions ) # Check if more than one working ion per transition metal and warn warnings = [] if any([element.is_transition_metal for element in dchg_comp]): transition_metal_fraction = sum( [ dchg_comp.get_atomic_fraction(elem) for elem in dchg_comp if elem.is_transition_metal ] ) if ( dchg_comp.get_atomic_fraction(ie.working_ion) / transition_metal_fraction > 1.0 ): warnings.append("More than one working ion per transition metal") else: warnings.append("Transition metal not found") return cls( battery_type="insertion", # type: ignore battery_id=battery_id, host_structure=stripped_host.as_dict(), framework=framework, battery_formula=battery_formula, electrode_object=ie, elements=elements, nelements=len(elements), chemsys=chemsys, formula_anonymous=framework.anonymized_formula, entries_composition_summary=entries_composition_summary, warnings=warnings, **d, ) @staticmethod def get_elec_doc(ie: InsertionElectrode) -> dict: """ Gets a summary doc for an InsertionElectrode object. Similar to InsertionElectrode.get_summary_dict() with modifications specific to the Materials Project. Args: ie (pymatgen InsertionElectrode): electrode_object Returns: summary doc """ entries = ie.get_all_entries() def get_dict_from_elec(ie): d = { "average_voltage": ie.get_average_voltage(), "max_voltage": ie.max_voltage, "min_voltage": ie.min_voltage, "max_delta_volume": ie.max_delta_volume, "max_voltage_step": ie.max_voltage_step, "capacity_grav": ie.get_capacity_grav(), "capacity_vol": ie.get_capacity_vol(), "energy_grav": ie.get_specific_energy(), "energy_vol": ie.get_energy_density(), "working_ion": ie.working_ion.symbol, "num_steps": ie.num_steps, "fracA_charge": ie.voltage_pairs[0].frac_charge, "fracA_discharge": ie.voltage_pairs[-1].frac_discharge, "framework_formula": ie.framework_formula, "id_charge": ie.fully_charged_entry.data["material_id"], "formula_charge": ie.fully_charged_entry.composition.reduced_formula, "id_discharge": ie.fully_discharged_entry.data["material_id"], "formula_discharge": ie.fully_discharged_entry.composition.reduced_formula, "max_instability": ie.get_max_instability(), "min_instability": ie.get_min_instability(), "material_ids": [itr_ent.data["material_id"] for itr_ent in entries], "stable_material_ids": [ itr_ent.data["material_id"] for itr_ent in ie.get_stable_entries() ], "unstable_material_ids": [ itr_ent.data["material_id"] for itr_ent in ie.get_unstable_entries() ], } if all("decomposition_energy" in e.data for e in entries): thermo_data = { "stability_charge": ie.fully_charged_entry.data[ "decomposition_energy" ], "stability_discharge": ie.fully_discharged_entry.data[ "decomposition_energy" ], "stability_data": { e.entry_id: e.data["decomposition_energy"] for e in entries }, } else: thermo_data = { "stability_charge": None, "stability_discharge": None, "stability_data": {}, } d.update(thermo_data) return d d = get_dict_from_elec(ie) d["adj_pairs"] = list( map(get_dict_from_elec, ie.get_sub_electrodes(adjacent_only=True)) ) return d class ConversionElectrodeDoc(ConversionVoltagePairDoc, BaseElectrode): """ Conversion electrode """ initial_comp_formula: Optional[str] = Field( None, description="The starting composition for the ConversionElectrode represented as a string/formula.", ) adj_pairs: Optional[List[ConversionVoltagePairDoc]] = Field( None, description="Returns all of the voltage steps material pairs." ) electrode_object: Optional[ConversionElectrode] = Field( None, description="The Pymatgen conversion electrode object." ) @classmethod def from_composition_and_entries( cls, composition: Composition, entries: List[ComputedEntry], working_ion_symbol: str, battery_id: str, thermo_type: str, ): ce = ConversionElectrode.from_composition_and_entries( comp=composition, entries_in_chemsys=entries, working_ion_symbol=working_ion_symbol, ) d = cls.get_conversion_elec_doc(ce) # type: ignore[arg-type] return cls(battery_id=battery_id, thermo_type=thermo_type, **d) @classmethod def from_composition_and_pd( cls, comp: Composition, pd: PhaseDiagram, working_ion_symbol: str, battery_id: str, thermo_type: str, ): ce = ConversionElectrode.from_composition_and_pd( comp=comp, pd=pd, working_ion_symbol=working_ion_symbol ) d = cls.get_conversion_elec_doc(ce) # type: ignore[arg-type] return cls(battery_id=battery_id, thermo_type=thermo_type, **d) @staticmethod def get_conversion_elec_doc(ce: ConversionElectrode) -> dict: """ Gets a summary doc for a ConversionElectrode object. Args: ie (pymatgen ConversionElectrode): electrode_object Returns: summary doc """ def get_dict_from_conversion_elec(ce): fracA_charge = ce.voltage_pairs[0].frac_charge fracA_discharge = ce.voltage_pairs[-1].frac_discharge x_charge = fracA_charge * ce.framework.num_atoms / (1 - fracA_charge) x_discharge = ( fracA_discharge * ce.framework.num_atoms / (1 - fracA_discharge) ) comp_charge = ce.framework + {ce.working_ion.symbol: x_charge} comp_discharge = ce.framework + {ce.working_ion.symbol: x_discharge} battery_formula = get_battery_formula( comp_charge, comp_discharge, ce.working_ion, ) d = { "battery_type": "conversion", "battery_formula": battery_formula, "framework": ce.framework, "framework_formula": ce.framework_formula, "initial_comp_formula": ce.initial_comp_formula, "chemsys": ce.framework.chemical_system, "elements": ce.framework.elements, "nelements": len(ce.framework.elements), "formula_anonymous": ce.framework.anonymized_formula, "electrode_object": ce.as_dict(), "average_voltage": ce.get_average_voltage(), "max_voltage": ce.max_voltage, "min_voltage": ce.min_voltage, "max_delta_volume": ce.max_delta_volume, "max_voltage_step": ce.max_voltage_step, "capacity_grav": ce.get_capacity_grav(), "capacity_vol": ce.get_capacity_vol(), "energy_grav": ce.get_specific_energy(), "energy_vol": ce.get_energy_density(), "working_ion": ce.working_ion.symbol, "num_steps": ce.num_steps, "fracA_charge": fracA_charge, "fracA_discharge": fracA_discharge, "formula_charge": comp_charge.reduced_formula, "formula_discharge": comp_discharge.reduced_formula, "reaction": ce.voltage_pairs[0].rxn.as_dict(), "last_updated": datetime.utcnow(), } return d d = get_dict_from_conversion_elec(ce) d["adj_pairs"] = list( map( get_dict_from_conversion_elec, ce.get_sub_electrodes(adjacent_only=True) ) ) return d def get_battery_formula( charge_comp: Composition, discharge_comp: Composition, working_ion: Element ): working_ion_subscripts = [] for comp in [charge_comp, discharge_comp]: comp_dict = comp.get_el_amt_dict() working_ion_num = ( comp_dict.pop(working_ion.value) if working_ion.value in comp_dict else 0 ) temp_comp = Composition.from_dict(comp_dict) (temp_reduced, n) = temp_comp.get_reduced_composition_and_factor() new_subscript = re.sub(".00$", "", "{:.2f}".format(working_ion_num / n)) if new_subscript != "0": new_subscript = new_subscript.rstrip("0") working_ion_subscripts.append(new_subscript) return ( working_ion.value + "-".join(working_ion_subscripts) + temp_reduced.reduced_formula ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/electronic_structure.py0000644000175100001770000004340514673360562022151 0ustar00runnerdocker""" Core definition of an Electronic Structure """ from __future__ import annotations from collections import defaultdict from datetime import datetime from enum import Enum from math import isnan from typing import Dict, List, Optional, Type, TypeVar, Union import numpy as np from pydantic import BaseModel, Field from pymatgen.analysis.magnetism.analyzer import ( CollinearMagneticStructureAnalyzer, Ordering, ) from pymatgen.core import Structure from pymatgen.core.periodic_table import Element from pymatgen.electronic_structure.bandstructure import BandStructureSymmLine from pymatgen.electronic_structure.core import OrbitalType, Spin from pymatgen.electronic_structure.dos import CompleteDos from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from pymatgen.symmetry.bandstructure import HighSymmKpath from typing_extensions import Literal from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID from emmet.core.settings import EmmetSettings SETTINGS = EmmetSettings() class BSPathType(Enum): setyawan_curtarolo = "setyawan_curtarolo" hinuma = "hinuma" latimer_munro = "latimer_munro" class DOSProjectionType(Enum): total = "total" elemental = "elemental" orbital = "orbital" class BSObjectDoc(BaseModel): """ Band object document. """ task_id: Optional[MPID] = Field( None, description="The source calculation (task) ID that this band structure comes from. " "This has the same form as a Materials Project ID.", ) last_updated: datetime = Field( description="The timestamp when this calculation was last updated", default_factory=datetime.utcnow, ) data: Optional[Union[Dict, BandStructureSymmLine]] = Field( None, description="The band structure object for the given calculation ID" ) class DOSObjectDoc(BaseModel): """ DOS object document. """ task_id: Optional[MPID] = Field( None, description="The source calculation (task) ID that this density of states comes from. " "This has the same form as a Materials Project ID.", ) last_updated: datetime = Field( description="The timestamp when this calculation was last updated.", default_factory=datetime.utcnow, ) data: Optional[CompleteDos] = Field( None, description="The density of states object for the given calculation ID." ) class ElectronicStructureBaseData(BaseModel): task_id: MPID = Field( ..., description="The source calculation (task) ID for the electronic structure data. " "This has the same form as a Materials Project ID.", ) band_gap: float = Field(..., description="Band gap energy in eV.") cbm: Optional[Union[float, Dict]] = Field( None, description="Conduction band minimum data." ) vbm: Optional[Union[float, Dict]] = Field( None, description="Valence band maximum data." ) efermi: Optional[float] = Field(None, description="Fermi energy in eV.") class ElectronicStructureSummary(ElectronicStructureBaseData): is_gap_direct: bool = Field(..., description="Whether the band gap is direct.") is_metal: bool = Field(..., description="Whether the material is a metal.") magnetic_ordering: Union[str, Ordering] = Field( ..., description="Magnetic ordering of the calculation." ) class BandStructureSummaryData(ElectronicStructureSummary): nbands: float = Field(..., description="Number of bands.") equivalent_labels: Dict = Field( ..., description="Equivalent k-point labels in other k-path conventions." ) direct_gap: float = Field(..., description="Direct gap energy in eV.") class DosSummaryData(ElectronicStructureBaseData): spin_polarization: Optional[float] = Field( None, description="Spin polarization at the fermi level." ) class BandstructureData(BaseModel): setyawan_curtarolo: Optional[BandStructureSummaryData] = Field( None, description="Band structure summary data using the Setyawan-Curtarolo path convention.", ) hinuma: Optional[BandStructureSummaryData] = Field( None, description="Band structure summary data using the Hinuma et al. path convention.", ) latimer_munro: Optional[BandStructureSummaryData] = Field( None, description="Band structure summary data using the Latimer-Munro path convention.", ) class DosData(BaseModel): total: Optional[Dict[Union[Spin, str], DosSummaryData]] = Field( None, description="Total DOS summary data." ) elemental: Optional[ Dict[ Element, Dict[ Union[Literal["total", "s", "p", "d", "f"], OrbitalType], Dict[Union[Literal["1", "-1"], Spin], DosSummaryData], ], ] ] = Field( None, description="Band structure summary data using the Hinuma et al. path convention.", ) orbital: Optional[ Dict[ Union[Literal["total", "s", "p", "d", "f"], OrbitalType], Dict[Union[Literal["1", "-1"], Spin], DosSummaryData], ] ] = Field( None, description="Band structure summary data using the Latimer-Munro path convention.", ) magnetic_ordering: Optional[Union[Ordering, str]] = Field( None, description="Magnetic ordering of the calculation." ) T = TypeVar("T", bound="ElectronicStructureDoc") class ElectronicStructureDoc(PropertyDoc, ElectronicStructureSummary): """ Definition for a core Electronic Structure Document """ property_name: str = "electronic_structure" bandstructure: Optional[BandstructureData] = Field( None, description="Band structure data for the material." ) dos: Optional[DosData] = Field( None, description="Density of states data for the material." ) last_updated: datetime = Field( description="Timestamp for when this document was last updated.", default_factory=datetime.utcnow, ) @classmethod def from_bsdos( # type: ignore[override] cls: Type[T], material_id: MPID, dos: Dict[MPID, CompleteDos], is_gap_direct: bool, is_metal: bool, origins: List[dict] = [], structures: Optional[Dict[MPID, Structure]] = None, setyawan_curtarolo: Optional[Dict[MPID, BandStructureSymmLine]] = None, hinuma: Optional[Dict[MPID, BandStructureSymmLine]] = None, latimer_munro: Optional[Dict[MPID, BandStructureSymmLine]] = None, **kwargs, ) -> T: """ Builds a electronic structure document using band structure and density of states data. Args: material_id (MPID): A material ID. dos (Dict[MPID, CompleteDos]): Dictionary mapping a calculation (task) ID to a CompleteDos object. is_gap_direct (bool): Direct gap indicator included at root level of document. is_metal (bool): Metallic indicator included at root level of document. structures (Dict[MPID, Structure]) = Dictionary mapping a calculation (task) ID to the structures used as inputs. This is to ensures correct magnetic moment information is included. setyawan_curtarolo (Dict[MPID, BandStructureSymmLine]): Dictionary mapping a calculation (task) ID to a BandStructureSymmLine object from a calculation run using the Setyawan-Curtarolo k-path convention. hinuma (Dict[MPID, BandStructureSymmLine]): Dictionary mapping a calculation (task) ID to a BandStructureSymmLine object from a calculation run using the Hinuma et al. k-path convention. latimer_munro (Dict[MPID, BandStructureSymmLine]): Dictionary mapping a calculation (task) ID to a BandStructureSymmLine object from a calculation run using the Latimer-Munro k-path convention. origins (List[dict]): Optional origins information for final doc """ # -- Process density of states data dos_task, dos_obj = list(dos.items())[0] orbitals = [OrbitalType.s, OrbitalType.p, OrbitalType.d] spins = list(dos_obj.densities.keys()) ele_dos = dos_obj.get_element_dos() tot_orb_dos = dos_obj.get_spd_dos() elements = ele_dos.keys() dos_efermi = dos_obj.efermi is_gap_direct = is_gap_direct is_metal = is_metal structure = dos_obj.structure if structures is not None and structures[dos_task]: structure = structures[dos_task] dos_mag_ordering = CollinearMagneticStructureAnalyzer(structure).ordering dos_data = { "total": defaultdict(dict), "elemental": {element: defaultdict(dict) for element in elements}, "orbital": defaultdict(dict), "magnetic_ordering": dos_mag_ordering, } for spin in spins: # - Process total DOS data band_gap = dos_obj.get_gap(spin=spin) (cbm, vbm) = dos_obj.get_cbm_vbm(spin=spin) try: spin_polarization = dos_obj.spin_polarization if spin_polarization is None or isnan(spin_polarization): spin_polarization = None except KeyError: spin_polarization = None dos_data["total"][spin] = DosSummaryData( # type: ignore[index] task_id=dos_task, band_gap=band_gap, cbm=cbm, vbm=vbm, efermi=dos_efermi, spin_polarization=spin_polarization, ) # - Process total orbital projection data for orbital in orbitals: band_gap = tot_orb_dos[orbital].get_gap(spin=spin) (cbm, vbm) = tot_orb_dos[orbital].get_cbm_vbm(spin=spin) spin_polarization = None dos_data["orbital"][orbital][spin] = DosSummaryData( # type: ignore[index] task_id=dos_task, band_gap=band_gap, cbm=cbm, vbm=vbm, efermi=dos_efermi, spin_polarization=spin_polarization, ) # - Process element and element orbital projection data for ele in ele_dos: orb_dos = dos_obj.get_element_spd_dos(ele) for orbital in ["total"] + list(orb_dos.keys()): # type: ignore[assignment] if orbital == "total": proj_dos = ele_dos label = ele else: proj_dos = orb_dos label = orbital for spin in spins: band_gap = proj_dos[label].get_gap(spin=spin) (cbm, vbm) = proj_dos[label].get_cbm_vbm(spin=spin) spin_polarization = None dos_data["elemental"][ele][orbital][spin] = DosSummaryData( # type: ignore[index] task_id=dos_task, band_gap=band_gap, cbm=cbm, vbm=vbm, efermi=dos_efermi, spin_polarization=spin_polarization, ) # -- Process band structure data bs_data = { # type: ignore "setyawan_curtarolo": setyawan_curtarolo, "hinuma": hinuma, "latimer_munro": latimer_munro, } for bs_type, bs_input in bs_data.items(): if bs_input is not None: bs_task, bs = list(bs_input.items())[0] if structures is not None and structures[bs_task]: bs_mag_ordering = CollinearMagneticStructureAnalyzer( structures[bs_task] ).ordering else: bs_mag_ordering = CollinearMagneticStructureAnalyzer( bs.structure # type: ignore[arg-type] ).ordering gap_dict = bs.get_band_gap() is_metal = bs.is_metal() direct_gap = bs.get_direct_band_gap() if is_metal: band_gap = 0.0 cbm = None # type: ignore[assignment] vbm = None # type: ignore[assignment] is_gap_direct = False else: band_gap = gap_dict["energy"] cbm = bs.get_cbm() # type: ignore[assignment] vbm = bs.get_vbm() # type: ignore[assignment] is_gap_direct = gap_dict["direct"] bs_efermi = bs.efermi nbands = bs.nb_bands # - Get equivalent labels between different conventions hskp = HighSymmKpath( bs.structure, path_type="all", symprec=0.1, angle_tolerance=5, atol=1e-5, ) equivalent_labels = hskp.equiv_labels if bs_type == "latimer_munro": gen_labels = set( [ label for label in equivalent_labels["latimer_munro"][ "setyawan_curtarolo" ] ] ) kpath_labels = set( [ kpoint.label for kpoint in bs.kpoints if kpoint.label is not None ] ) if not gen_labels.issubset(kpath_labels): new_structure = SpacegroupAnalyzer( bs.structure # type: ignore[arg-type] ).get_primitive_standard_structure( international_monoclinic=False ) hskp = HighSymmKpath( new_structure, path_type="all", symprec=SETTINGS.SYMPREC, angle_tolerance=SETTINGS.ANGLE_TOL, atol=1e-5, ) equivalent_labels = hskp.equiv_labels bs_data[bs_type] = BandStructureSummaryData( # type: ignore task_id=bs_task, band_gap=band_gap, direct_gap=direct_gap, cbm=cbm, vbm=vbm, is_gap_direct=is_gap_direct, is_metal=is_metal, efermi=bs_efermi, nbands=nbands, equivalent_labels=equivalent_labels, magnetic_ordering=bs_mag_ordering, ) bs_entry = BandstructureData(**bs_data) # type: ignore dos_entry = DosData(**dos_data) # type: ignore[arg-type] # Obtain summary data bs_gap = ( bs_entry.setyawan_curtarolo.band_gap if bs_entry.setyawan_curtarolo is not None else None ) dos_cbm, dos_vbm = dos_obj.get_cbm_vbm() dos_gap = max(dos_cbm - dos_vbm, 0.0) new_origin_last_updated = None new_origin_task_id = None if bs_gap is not None and bs_gap <= dos_gap + 0.2: summary_task = bs_entry.setyawan_curtarolo.task_id # type: ignore summary_band_gap = bs_gap summary_cbm = ( bs_entry.setyawan_curtarolo.cbm.get("energy", None) # type: ignore if bs_entry.setyawan_curtarolo.cbm is not None # type: ignore else None ) summary_vbm = ( bs_entry.setyawan_curtarolo.vbm.get("energy", None) # type: ignore if bs_entry.setyawan_curtarolo.cbm is not None # type: ignore else None ) # type: ignore summary_efermi = bs_entry.setyawan_curtarolo.efermi # type: ignore is_gap_direct = bs_entry.setyawan_curtarolo.is_gap_direct # type: ignore is_metal = bs_entry.setyawan_curtarolo.is_metal # type: ignore summary_magnetic_ordering = bs_entry.setyawan_curtarolo.magnetic_ordering # type: ignore for origin in origins: if origin["name"] == "setyawan_curtarolo": new_origin_last_updated = origin["last_updated"] new_origin_task_id = origin["task_id"] else: summary_task = dos_entry.model_dump()["total"][Spin.up]["task_id"] summary_band_gap = dos_gap summary_cbm = dos_cbm summary_vbm = dos_vbm summary_efermi = dos_efermi summary_magnetic_ordering = dos_mag_ordering is_metal = True if np.isclose(dos_gap, 0.0, atol=0.01, rtol=0) else False for origin in origins: if origin["name"] == "dos": new_origin_last_updated = origin["last_updated"] new_origin_task_id = origin["task_id"] if new_origin_task_id is not None: for origin in origins: if origin["name"] == "electronic_structure": origin["last_updated"] = new_origin_last_updated origin["task_id"] = new_origin_task_id return cls.from_structure( material_id=MPID(material_id), task_id=summary_task, meta_structure=structure, band_gap=summary_band_gap, cbm=summary_cbm, vbm=summary_vbm, efermi=summary_efermi, is_gap_direct=is_gap_direct, is_metal=is_metal, magnetic_ordering=summary_magnetic_ordering, bandstructure=bs_entry, dos=dos_entry, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/eos.py0000644000175100001770000000143214673360562016462 0ustar00runnerdockerfrom typing import Dict, List, Optional from pydantic import BaseModel, Field class EOSDoc(BaseModel): """ Fitted equations of state and energies and volumes used for fits. """ energies: Optional[List[float]] = Field( None, description="Common energies in eV/atom that the equations of state are plotted with.", ) volumes: Optional[List[float]] = Field( None, description="Common volumes in A³/atom that the equations of state are plotted with.", ) eos: Optional[Dict] = Field( None, description="Data for each type of equation of state.", ) material_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0462902 emmet-core-0.84.2/emmet/core/feff/0000755000175100001770000000000014673360566016234 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/feff/__init__.py0000644000175100001770000000000014673360562020327 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/feff/task.py0000644000175100001770000000536214673360562017552 0ustar00runnerdocker""" Core definition of a VASP Task Document """ from __future__ import annotations from typing import Any, Dict, List from pydantic import Field from pymatgen.analysis.xas.spectrum import XAS from pymatgen.core import Structure from pymatgen.core.periodic_table import Element, Species from emmet.core.structure import StructureMetadata from emmet.core.utils import ValueEnum from emmet.core.vasp.task_valid import TaskDocument as BaseTaskDocument class CalcType(ValueEnum): """ The type of FEFF Calculation XANES - Just the near-edge region EXAFS - Just the extended region XAFS - Fully stitchted XANES + EXAFS """ XANES = "XANES" EXAFS = "EXAFS" XAFS = "XAFS" class TaskDocument(BaseTaskDocument, StructureMetadata): """Task Document for a FEFF XAS Calculation. Doesn't support EELS for now""" calc_code: str = "FEFF" structure: Structure input_parameters: Dict[str, Any] = Field( {}, description="Input parameters for the FEFF calculation" ) spectrum: List[List[float]] = Field( [[]], description="Raw spectrum data from FEFF xmu.dat or eels.dat" ) absorbing_atom: int = Field( ..., description="Index in the cluster or structure for the absorbing atom" ) spectrum_type: CalcType = Field(..., title="XAS Spectrum Type") edge: str = Field( ..., title="Absorption Edge", description="The interaction edge for XAS" ) # TEMP Stub properties for compatibility with atomate drone @property def absorbing_element(self) -> Element | Species: if isinstance(self.structure[self.absorbing_atom].specie, Element): return self.structure[self.absorbing_atom].specie return self.structure[self.absorbing_atom].specie.element @property def xas_spectrum(self) -> XAS: if not hasattr(self, "_xas_spectrum"): if not all([len(p) == 6 for p in self.spectrum]): raise ValueError( "Spectrum data doesn't appear to be from xmu.dat which holds XAS data" ) energy = [point[0] for point in self.spectrum] # (eV) intensity = [point[3] for point in self.spectrum] # (mu) structure = self.structure absorbing_index = self.absorbing_atom absorbing_element = self.absorbing_element edge = self.edge spectrum_type = str(self.spectrum_type) self._xas_spectrum = XAS( x=energy, y=intensity, structure=structure, absorbing_element=absorbing_element, absorbing_index=absorbing_index, edge=edge, spectrum_type=spectrum_type, ) return self._xas_spectrum ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/fermi.py0000644000175100001770000000214514673360562017000 0ustar00runnerdockerfrom datetime import datetime from typing import List, Optional from pydantic import BaseModel, Field, field_validator from emmet.core.common import convert_datetime class FermiDoc(BaseModel): """ Fermi surfaces. """ fermi_surfaces: Optional[List[dict]] = Field( None, description="List of IFermi FermiSurface objects.", ) surface_types: Optional[List[str]] = Field( None, description="Type of each fermi surface in the fermi_surfaces list.\ Is either CBM or VBM for semiconductors, or fermi_surface for metals.", ) material_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this fermi surface document.", ) # Make sure that the datetime field is properly formatted @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/find_structure.py0000644000175100001770000000216614673360562020741 0ustar00runnerdockerfrom emmet.core.mpid import MPID, MPculeID from pydantic import Field, BaseModel from typing import Optional class FindStructure(BaseModel): """ Class defining find structure return data """ material_id: Optional[MPID] = Field( None, description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******.", ) normalized_rms_displacement: Optional[float] = Field( None, description="Volume normalized root-mean squared displacement between the structures", ) max_distance_paired_sites: Optional[float] = Field( None, description="Maximum distance between paired sites.", ) class FindMolecule(BaseModel): """ Class defining find molecule return data """ molecule_id: Optional[MPculeID] = Field( None, description="The ID of this molecule, used as a universal reference across property documents.", ) rmsd: Optional[float] = Field( None, description="Root-mean-squared displacement of the molecule compared to a reference", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/formula_autocomplete.py0000644000175100001770000000044614673360562022126 0ustar00runnerdockerfrom pydantic import Field, BaseModel from typing import Optional class FormulaAutocomplete(BaseModel): """ Class defining formula autocomplete return data """ formula_pretty: Optional[str] = Field( None, description="Human readable chemical formula.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/grain_boundary.py0000644000175100001770000000435314673360562020704 0ustar00runnerdockerfrom typing import List, Optional from pydantic import field_validator, BaseModel, Field from enum import Enum from datetime import datetime from emmet.core.common import convert_datetime from pymatgen.analysis.gb.grain import GrainBoundary class GBTypeEnum(Enum): """ Grain boundary types """ tilt = "tilt" twist = "twist" class GrainBoundaryDoc(BaseModel): """ Grain boundary energies, work of separation... """ material_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) sigma: Optional[int] = Field( None, description="Sigma value of the boundary.", ) type: Optional[GBTypeEnum] = Field( None, description="Grain boundary type.", ) rotation_axis: Optional[List[int]] = Field( None, description="Rotation axis.", ) gb_plane: Optional[List[int]] = Field( None, description="Grain boundary plane.", ) rotation_angle: Optional[float] = Field( None, description="Rotation angle in degrees.", ) gb_energy: Optional[float] = Field( None, description="Grain boundary energy in J/m^2.", ) initial_structure: Optional[GrainBoundary] = Field( None, description="Initial grain boundary structure." ) final_structure: Optional[GrainBoundary] = Field( None, description="Final grain boundary structure." ) pretty_formula: Optional[str] = Field( None, description="Reduced formula of the material." ) w_sep: Optional[float] = Field(None, description="Work of separation in J/m^2.") cif: Optional[str] = Field(None, description="CIF file of the structure.") chemsys: Optional[str] = Field( None, description="Dash-delimited string of elements in the material." ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this Material document.", ) # Make sure that the datetime field is properly formatted @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/magnetism.py0000644000175100001770000000614414673360562017665 0ustar00runnerdockerfrom typing import List, Optional from pydantic import Field from pymatgen.core import Structure from pymatgen.analysis.magnetism import CollinearMagneticStructureAnalyzer from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID class MagnetismDoc(PropertyDoc): """ Magnetic data obtain from the calculated structure """ property_name: str = "magnetism" ordering: Optional[str] = Field( None, description="Magnetic ordering.", ) is_magnetic: Optional[bool] = Field( None, description="Whether the material is magnetic.", ) exchange_symmetry: Optional[int] = Field( None, description="Exchange symmetry.", ) num_magnetic_sites: Optional[int] = Field( None, description="The number of magnetic sites.", ) num_unique_magnetic_sites: Optional[int] = Field( None, description="The number of unique magnetic sites.", ) types_of_magnetic_species: Optional[List[str]] = Field( None, description="Magnetic specie elements.", ) magmoms: Optional[List[float]] = Field( None, description="Magnetic moments for each site.", ) total_magnetization: Optional[float] = Field( None, description="Total magnetization in μB.", ) total_magnetization_normalized_vol: Optional[float] = Field( None, description="Total magnetization normalized by volume in μB/ų.", ) total_magnetization_normalized_formula_units: Optional[float] = Field( None, description="Total magnetization normalized by formula unit in μB/f.u. .", ) @classmethod def from_structure( cls, structure: Structure, total_magnetization: float, material_id: MPID, **kwargs ): # noqa: E501 struct_has_magmoms = "magmom" in structure.site_properties total_magnetization = abs( total_magnetization ) # not necessarily == sum(magmoms) msa = CollinearMagneticStructureAnalyzer( structure, round_magmoms=True, threshold_nonmag=0.2, threshold=0 ) magmoms = msa.magmoms.tolist() d = { "ordering": msa.ordering.value if struct_has_magmoms else "Unknown", "is_magnetic": msa.is_magnetic, "exchange_symmetry": msa.get_exchange_group_info()[1], "num_magnetic_sites": msa.number_of_magnetic_sites, "num_unique_magnetic_sites": msa.number_of_unique_magnetic_sites(), "types_of_magnetic_species": [str(t) for t in msa.types_of_magnetic_specie], "magmoms": magmoms, "total_magnetization": total_magnetization, "total_magnetization_normalized_vol": total_magnetization / structure.volume, "total_magnetization_normalized_formula_units": total_magnetization / (structure.composition.get_reduced_composition_and_factor()[1]), } return super().from_structure( meta_structure=structure, material_id=material_id, **d, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/material.py0000644000175100001770000001365714673360562017506 0ustar00runnerdocker""" Core definition of a Materials Document """ from __future__ import annotations from datetime import datetime from typing import List, Mapping, Type, TypeVar, Union, Optional from pydantic import BaseModel, Field, field_validator from pymatgen.core import Structure from pymatgen.core.structure import Molecule from emmet.core.mpid import MPID, MPculeID from emmet.core.structure import MoleculeMetadata, StructureMetadata from emmet.core.vasp.validation import DeprecationMessage from emmet.core.common import convert_datetime class PropertyOrigin(BaseModel): """ Provenance document for the origin of properties in a material document """ name: str = Field(..., description="The property name") task_id: Union[MPID, MPculeID] = Field( ..., description="The calculation ID this property comes from" ) last_updated: datetime = Field( # type: ignore description="The timestamp when this calculation was last updated", default_factory=datetime.utcnow, ) @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) T = TypeVar("T", bound="MaterialsDoc") S = TypeVar("S", bound="CoreMoleculeDoc") class MaterialsDoc(StructureMetadata): """ Definition for a core Materials Document """ # Only material_id is required for all documents material_id: MPID = Field( ..., description="The Materials Project ID of the material, used as a universal reference across property documents." "This comes in the form: mp-******.", ) structure: Structure = Field( ..., description="The structure of the this material.", ) deprecated: bool = Field( True, description="Whether this materials document is deprecated.", ) deprecation_reasons: Optional[List[Union[DeprecationMessage, str]]] = Field( None, description="List of deprecation tags detailing why this materials document isn't valid.", ) initial_structures: List[Structure] = Field( [], description="Initial structures used in the DFT optimizations corresponding to this material.", ) task_ids: List[MPID] = Field( [], description="List of Calculations IDs used to make this Materials Document.", ) deprecated_tasks: List[str] = Field([], title="Deprecated Tasks") calc_types: Optional[Mapping[str, str]] = Field( None, description="Calculation types for all the calculations that make up this material.", ) last_updated: datetime = Field( description="Timestamp for when this document was last updated.", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created.", default_factory=datetime.utcnow, ) origins: Optional[List[PropertyOrigin]] = Field( None, description="Dictionary for tracking the provenance of properties." ) warnings: List[str] = Field( [], description="Any warnings related to this material." ) @classmethod def from_structure( cls: Type[T], structure: Structure, material_id: MPID, **kwargs ) -> T: # type: ignore[override] """ Builds a materials document using the minimal amount of information """ return super().from_structure( # type: ignore meta_structure=structure, material_id=material_id, structure=structure, **kwargs, ) class CoreMoleculeDoc(MoleculeMetadata): """ Definition for a core Molecule Document """ # Only molecule_id is required for all documents molecule_id: MPculeID = Field( ..., description="The ID of this molecule, used as a universal reference across property documents." "This comes in the form of an MPID (or int) or MPculeID (or str)", ) molecule: Molecule = Field( ..., description="The best (typically meaning lowest in energy) structure for this molecule", ) deprecated: bool = Field( True, description="Whether this molecule document is deprecated.", ) # TODO: Why might a molecule be deprecated? deprecation_reasons: Optional[List[str]] = Field( None, description="List of deprecation tags detailing why this molecules document isn't valid", ) initial_molecules: List[Molecule] = Field( [], description="Initial molecules used in the DFT geometry optimizations corresponding to this molecule", ) task_ids: List[MPID] = Field( [], title="Calculation IDs", description="List of Calculations IDs used to make this Molecule Document", ) # TODO: Should this be MPID? deprecated_tasks: List[str] = Field([], title="Deprecated Tasks") calc_types: Optional[Mapping[str, str]] = Field( None, description="Calculation types for all the tasks that make up this molecule", ) last_updated: datetime = Field( description="Timestamp for when this document was last updated", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this document was first created", default_factory=datetime.utcnow, ) origins: Optional[List[PropertyOrigin]] = Field( None, description="Dictionary for tracking the provenance of properties" ) warnings: List[str] = Field([], description="Any warnings related to this molecule") @classmethod def from_molecule( cls: Type[S], molecule: Molecule, molecule_id: MPculeID, **kwargs ) -> S: # type: ignore[override] """ Builds a molecule document using the minimal amount of information """ return super().from_molecule( # type: ignore meta_molecule=molecule, molecule_id=molecule_id, molecule=molecule, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/material_property.py0000644000175100001770000000441414673360562021441 0ustar00runnerdocker""" Core definition of a Materials Document """ from __future__ import annotations from typing import Sequence, Type, TypeVar, Union, List, Optional from pydantic import Field, field_validator from pymatgen.core import Structure from datetime import datetime from emmet.core.material import PropertyOrigin from emmet.core.mpid import MPID from emmet.core.structure import StructureMetadata from emmet.core.vasp.validation import DeprecationMessage from emmet.core.common import convert_datetime S = TypeVar("S", bound="PropertyDoc") class PropertyDoc(StructureMetadata): """ Base model definition for any singular materials property. This may contain any amount of structure metadata for the purpose of search This is intended to be inherited and extended not used directly """ property_name: str material_id: MPID = Field( ..., description="The Materials Project ID of the material, used as a universal reference across property documents." "This comes in the form: mp-******.", ) deprecated: bool = Field( ..., description="Whether this property document is deprecated.", ) deprecation_reasons: Optional[List[Union[DeprecationMessage, str]]] = Field( None, description="List of deprecation tags detailing why this document isn't valid.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property.", default_factory=datetime.utcnow, ) origins: Sequence[PropertyOrigin] = Field( [], description="Dictionary for tracking the provenance of properties." ) warnings: Sequence[str] = Field( [], description="Any warnings related to this property." ) @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) @classmethod def from_structure( # type: ignore[override] cls: Type[S], meta_structure: Structure, material_id: MPID, **kwargs ) -> S: """ Builds a materials document using the minimal amount of information """ return super().from_structure( meta_structure=meta_structure, material_id=material_id, **kwargs ) # type: ignore ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/math.py0000644000175100001770000000161514673360562016630 0ustar00runnerdockerfrom typing import Tuple, List Vector3D = Tuple[float, float, float] Vector3D.__doc__ = "Real space vector" # type: ignore Matrix3D = Tuple[Vector3D, Vector3D, Vector3D] Matrix3D.__doc__ = "Real space Matrix" # type: ignore Vector6D = Tuple[float, float, float, float, float, float] Vector6D.__doc__ = "6D Voigt matrix component" # type: ignore MatrixVoigt = Tuple[Vector6D, Vector6D, Vector6D, Vector6D, Vector6D, Vector6D] Vector6D.__doc__ = "Voigt representation of a 3x3x3x3 tensor" # type: ignore Tensor3R = List[List[List[float]]] Tensor3R.__doc__ = "Generic tensor of rank 3" # type: ignore Tensor4R = List[List[List[List[float]]]] Tensor4R.__doc__ = "Generic tensor of rank 4" # type: ignore ListVector3D = List[float] ListVector3D.__doc__ = "Real space vector as list" # type: ignore ListMatrix3D = List[ListVector3D] ListMatrix3D.__doc__ = "Real space Matrix as list" # type: ignore ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/ml.py0000644000175100001770000001555414673360562016316 0ustar00runnerdockerfrom typing import TYPE_CHECKING, Dict, List, Optional, Union from matcalc.elasticity import ElasticityCalc from matcalc.eos import EOSCalc from matcalc.phonon import PhononCalc from matcalc.relaxation import RelaxCalc from matcalc.utils import get_universal_calculator from pydantic import Field, validator from pymatgen.analysis.elasticity import ElasticTensor from pymatgen.core import Structure from emmet.core.elasticity import ( BulkModulus, ElasticityDoc, ElasticTensorDoc, ShearModulus, ) if TYPE_CHECKING: from ase.calculators.calculator import Calculator class MLDoc(ElasticityDoc): """Document model for matcalc-generated material properties from machine learning interatomic potential predictions. Attributes: - metadata - material_id (str): MP ID - structure (Structure): pymatgen Structure object - deprecated (bool): whether this material is deprecated in MP - calculator (str): name of model used as ML potential. - version (str): version of matcalc used to generate this document - relaxation - final_structure: relaxed pymatgen Structure object - energy (float): final energy in eV - volume (float): final volume in Angstrom^3 - lattice parameters (float): a, b, c, alpha, beta, gamma - equation of state - eos (dict[str, list[float]]): with keys energies and volumes - bulk_modulus_bm (float): Birch-Murnaghan bulk modulus in GPa - phonon - temperatures (list[float]): temperatures in K - free_energy (list[float]): Helmholtz energies at those temperatures in eV - entropy (list[float]): entropies at those temperatures in eV/K - heat_capacities (list[float]): heat capacities at constant volume in eV/K - elasticity - elastic_tensor (ElasticTensorDoc): pydantic model from emmet.core.elasticity - shear_modulus (ShearModulus): Voigt-Reuss-Hill shear modulus (single float in eV/Angstrom^3) - bulk_modulus (BulkModulus): Voigt-Reuss-Hill bulk modulus (single float in eV/Angstrom^3) - youngs_modulus (float): Young's modulus (single float in eV/Angstrom^3) """ property_name: str = "ml" # metadata structure: Structure = Field(description="Original structure") matcalc_version: Optional[str] = Field( None, description="Version of matcalc used to generate this document" ) model: Optional[str] = Field( None, description="Name of model used as ML potential." ) version: Optional[str] = Field( None, description="Version of model used as ML potential" ) # relaxation attributes final_structure: Optional[Structure] = Field( None, description="ML-potential-relaxed structure" ) energy: Optional[float] = Field(None, description="Final energy in eV") volume: Optional[float] = Field(None, description="Final volume in Angstrom^3") a: Optional[float] = Field(None, description="Lattice length a in Angstrom") b: Optional[float] = Field(None, description="Lattice length b in Angstrom") c: Optional[float] = Field(None, description="Lattice length c in Angstrom") alpha: Optional[float] = Field(None, description="Lattice angle alpha in degrees") beta: Optional[float] = Field(None, description="Lattice angle beta in degrees") gamma: Optional[float] = Field(None, description="Lattice angle gamma in degrees") # equation of state attributes eos: Optional[Dict[str, List[float]]] = Field( None, description="dict with keys energies and volumes" ) bulk_modulus_bm: Optional[float] = Field(None, description="bm.b0_GPa") # phonons attributes temperatures: Optional[List[float]] = Field( None, description="list of temperatures" ) free_energy: Optional[List[float]] = Field( None, description="list of Helmholtz free energies at corresponding temperatures", ) entropy: Optional[List[float]] = Field( None, description="list of entropies at corresponding temperatures in eV/K" ) heat_capacity: Optional[List[float]] = Field( None, description="list of heat capacities at constant volume at corresponding " "temperatures in eV/K", ) # elasticity attributes # all inherited from ElasticityDoc @validator("elastic_tensor", pre=True) def elastic_tensor(cls, val) -> ElasticTensorDoc: """ElasticTensorDoc from MSONable dict of ElasticTensor, or list (specifying the Voigt array) or the ElasticTensor class itself. """ if isinstance(val, dict): tensor = ElasticTensor.from_dict(val) elif isinstance(val, (list, tuple)): tensor = ElasticTensor(val) else: tensor = val return ElasticTensorDoc(raw=tensor.voigt.tolist()) @validator("bulk_modulus", pre=True, always=True) def bulk_vrh_no_suffix(cls, new_key, values): """Map field bulk_modulus_vrh to bulk_modulus.""" val = values.get("bulk_modulus_vrh", new_key) return BulkModulus(vrh=val) @validator("shear_modulus", pre=True, always=True) def shear_vrh_no_suffix(cls, new_key, values): """Map field shear_modulus_vrh to shear_modulus.""" val = values.get("shear_modulus_vrh", new_key) return ShearModulus(vrh=val) def __init__( cls, structure, material_id, calculator: Union[str, "Calculator"], prop_kwargs: Optional[dict] = None, **kwargs, ) -> None: """ Args: structure (Structure): Pymatgen Structure object. material_id (str): MP ID. calculator (str | Calculator): ASE calculator or name of model to use as ML potential. See matcalc.utils.UNIVERSAL_CALCULATORS for recognized names. prop_kwargs (dict): Keyword arguments for each matcalc PropCalc class. Recognized keys are RelaxCalc, ElasticityCalc, PhononCalc, EOSCalc. **kwargs: Passed to the PropertyDoc constructor. Returns: MLDoc """ calculator = get_universal_calculator(calculator) results = {} for prop_cls in (RelaxCalc, PhononCalc, EOSCalc, ElasticityCalc): kwds = (prop_kwargs or {}).get(prop_cls.__name__, {}) output = prop_cls(calculator, **kwds).calc(structure) # extract thermal_properties from PhononCalc output if isinstance(output, dict) and {*output} == { "phonon", "thermal_properties", }: output = output["thermal_properties"] results.update(output) for key, val in results.items(): # convert arrays to lists if hasattr(val, "tolist"): results[key] = val.tolist() super().__init__( structure=structure, material_id=material_id, **results, **kwargs ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0462902 emmet-core-0.84.2/emmet/core/mobility/0000755000175100001770000000000014673360566017156 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/mobility/migrationgraph.py0000644000175100001770000003466214673360562022552 0ustar00runnerdockerfrom datetime import datetime from typing import List, Union, Dict, Tuple, Sequence, Optional from pydantic import Field import numpy as np from emmet.core.base import EmmetBaseModel from pymatgen.core import Structure from pymatgen.analysis.structure_matcher import StructureMatcher from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry try: from pymatgen.analysis.diffusion.neb.full_path_mapper import MigrationGraph from pymatgen.analysis.diffusion.utils.supercells import get_sc_fromstruct except ImportError: raise ImportError("Install pymatgen-analysis-diffusion to use MigrationGraphDoc") class MigrationGraphDoc(EmmetBaseModel): """ MigrationGraph Doc. Stores MigrationGraph and info such as ComputedStructureEntries (ComputedEntry can be used for working ion) and cutoff distance that are used to generated the object. Note: this doc is not self-contained within pymatgen, as it has dependence on pymatgen.analysis.diffusion, a namespace package aka pymatgen-diffusion. """ battery_id: str = Field( ..., description="The battery id for this MigrationGraphDoc" ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this MigrationGraph document.", ) warnings: Sequence[str] = Field( [], description="Any warnings related to this property." ) deprecated: bool = Field( False, description="Indicates whether a migration graph fails to be constructed from the provided entries. Defaults to False, indicating mg can be constructed from entries.", # noqa: E501 ) hop_cutoff: Optional[float] = Field( None, description="The numerical value in angstroms used to cap the maximum length of a hop.", ) entries_for_generation: Optional[List[ComputedStructureEntry]] = Field( None, description="A list of ComputedStructureEntries used to generate the structure with all working ion sites.", ) working_ion_entry: Optional[Union[ComputedEntry, ComputedStructureEntry]] = Field( None, description="The ComputedStructureEntry of the working ion." ) migration_graph: Optional[MigrationGraph] = Field( None, description="The MigrationGraph object as defined in pymatgen.analysis.diffusion.", ) populate_sc_fields: bool = Field( True, description="Flag indicating whether this document has populated the supercell fields", ) min_length_sc: Optional[float] = Field( None, description="The minimum length used to generate supercell using pymatgen.", ) minmax_num_atoms: Optional[Tuple[int, int]] = Field( None, description="The min/max number of atoms used to genreate supercell using pymatgen.", ) matrix_supercell_structure: Optional[Structure] = Field( None, description="The matrix suprcell structure that does not contain the mobile ions for the purpose of migration analysis.", # noqa: E501 ) conversion_matrix: Optional[List[List[Union[int, float]]]] = Field( None, description="The conversion matrix used to convert unit cell to supercell.", ) inserted_ion_coords: Optional[ List[Dict[str, Union[List[float], str, int]]] ] = Field( None, description="A dictionary containing all mobile ion fractional coordinates in terms of supercell.", ) insert_coords_combo: Optional[List[str]] = Field( None, description="A list of combinations 'a+b' to designate hops in the supercell. Each combo should correspond to one unique hop in MigrationGraph.", # noqa: E501 ) @classmethod def from_entries_and_distance( cls, battery_id: str, grouped_entries: List[ComputedStructureEntry], working_ion_entry: Union[ComputedEntry, ComputedStructureEntry], hop_cutoff: float, populate_sc_fields: bool = True, ltol: float = 0.2, stol: float = 0.3, angle_tol: float = 5, **kwargs, ) -> Union["MigrationGraphDoc", None]: """ This classmethod takes a group of ComputedStructureEntries (can also use ComputedEntry for wi) and generates a full sites structure. Then a MigrationGraph object is generated with with_distance() method with a designated cutoff. If populate_sc_fields set to True, this method will populate the supercell related fields. Required kwargs are min_length_sc and minmax_num_atoms. """ ranked_structures = MigrationGraph.get_structure_from_entries( entries=grouped_entries, migrating_ion_entry=working_ion_entry ) max_sites_struct = ranked_structures[0] migration_graph = MigrationGraph.with_distance( structure=max_sites_struct, migrating_specie=working_ion_entry.composition.chemical_system, max_distance=hop_cutoff, ) if not populate_sc_fields: return cls( battery_id=battery_id, hop_cutoff=hop_cutoff, entries_for_generation=grouped_entries, working_ion_entry=working_ion_entry, migration_graph=migration_graph, **kwargs, ) else: if all(arg in kwargs for arg in ["min_length_sc", "minmax_num_atoms"]): sm = StructureMatcher(ltol, stol, angle_tol) ( host_sc, sc_mat, min_length_sc, minmax_num_atoms, coords_list, combo, ) = MigrationGraphDoc.generate_sc_fields( mg=migration_graph, min_length_sc=kwargs["min_length_sc"], minmax_num_atoms=kwargs["minmax_num_atoms"], sm=sm, ) return cls( battery_id=battery_id, hop_cutoff=hop_cutoff, entries_for_generation=grouped_entries, working_ion_entry=working_ion_entry, migration_graph=migration_graph, matrix_supercell_structure=host_sc, conversion_matrix=sc_mat, inserted_ion_coords=coords_list, insert_coords_combo=combo, **kwargs, ) else: raise TypeError( "Please make sure to have kwargs min_length_sc and minmax_num_atoms if populate_sc_fields is set to True." # noqa: E501 ) @staticmethod def generate_sc_fields( mg: MigrationGraph, min_length_sc: float, minmax_num_atoms: Tuple[int, int], sm: StructureMatcher, ): min_length_sc = min_length_sc minmax_num_atoms = minmax_num_atoms sc_mat = get_sc_fromstruct( base_struct=mg.structure, min_atoms=minmax_num_atoms[0], max_atoms=minmax_num_atoms[1], min_length=min_length_sc, ) sc_mat = sc_mat.tolist() # type: ignore[attr-defined] host_sc = mg.host_structure * sc_mat working_ion = mg.only_sites[0].species_string coords_list = MigrationGraphDoc.ordered_sc_site_list(mg.only_sites, sc_mat) combo, coords_list = MigrationGraphDoc.get_hop_sc_combo( mg.unique_hops, sc_mat, sm, host_sc, working_ion, coords_list ) return host_sc, sc_mat, min_length_sc, minmax_num_atoms, coords_list, combo @staticmethod def ordered_sc_site_list(uc_sites_only: Structure, sc_mat: List[List[int]]): uc_no_site = uc_sites_only.copy() uc_no_site.remove_sites(range(len(uc_sites_only))) working_ion = uc_sites_only[0].species_string sc_site_dict = {} # type: dict for i, e in enumerate(uc_sites_only): uc_one_set = uc_no_site.copy() uc_one_set.insert(0, working_ion, e.frac_coords) sc_one_set = uc_one_set * sc_mat for index in range(len(sc_one_set)): sc_site_dict[len(sc_site_dict) + 1] = { "uc_site_type": i, "site_frac_coords": list(sc_one_set[index].frac_coords), # "extra_site": False } ordered_site_list = [ e for i, e in enumerate( sorted( sc_site_dict.values(), key=lambda v: float(np.linalg.norm(v["site_frac_coords"])), ) ) ] return ordered_site_list @staticmethod def get_hop_sc_combo( unique_hops: Dict, sc_mat: List[List[int]], sm: StructureMatcher, host_sc: Structure, working_ion: str, ordered_sc_site_list: list, ): combo = [] unique_hops = {k: v for k, v in sorted(unique_hops.items())} for one_hop in unique_hops.values(): added = False sc_isite_set = { k: v for k, v in enumerate(ordered_sc_site_list) if v["uc_site_type"] == one_hop["iindex"] } sc_esite_set = { k: v for k, v in enumerate(ordered_sc_site_list) if v["uc_site_type"] == one_hop["eindex"] } for sc_iindex, sc_isite in sc_isite_set.items(): for sc_eindex, sc_esite in sc_esite_set.items(): sc_check = host_sc.copy() sc_check.insert(0, working_ion, sc_isite["site_frac_coords"]) sc_check.insert(1, working_ion, sc_esite["site_frac_coords"]) if MigrationGraphDoc.compare_sc_one_hop( one_hop, sc_mat, sm, host_sc, sc_check, working_ion, (sc_isite["uc_site_type"], sc_esite["uc_site_type"]), ): combo.append(f"{sc_iindex}+{sc_eindex}") added = True break if added: break if not added: new_combo, ordered_sc_site_list = MigrationGraphDoc.append_new_site( host_sc, ordered_sc_site_list, one_hop, sc_mat, working_ion ) combo.append(new_combo) return combo, ordered_sc_site_list @staticmethod def compare_sc_one_hop( one_hop: Dict, sc_mat: List, sm: StructureMatcher, host_sc: Structure, sc_check: Structure, working_ion: str, uc_site_types: Tuple[int, int], ): sc_mat_inv = np.linalg.inv(sc_mat) convert_sc_icoords = np.dot(one_hop["ipos"], sc_mat_inv) convert_sc_ecoords = np.dot(one_hop["epos"], sc_mat_inv) convert_sc = host_sc.copy() convert_sc.insert(0, working_ion, convert_sc_icoords) convert_sc.insert(1, working_ion, convert_sc_ecoords) if sm.fit(convert_sc, sc_check): one_hop_dis = one_hop["hop"].length sc_check_hop_dis = np.linalg.norm(sc_check[0].coords - sc_check[1].coords) if np.isclose(one_hop_dis, sc_check_hop_dis, atol=1e-5): if ( one_hop["iindex"] == uc_site_types[0] and one_hop["eindex"] == uc_site_types[1] ): return True return False @staticmethod def append_new_site( host_sc: Structure, ordered_sc_site_list: list, one_hop: Dict, sc_mat: List[List[int]], working_ion: str, ): sc_mat_inv = np.linalg.inv(sc_mat) sc_ipos = np.dot(one_hop["ipos"], sc_mat_inv) sc_epos = np.dot(one_hop["epos"], sc_mat_inv) sc_iindex, sc_eindex = None, None host_sc_insert = host_sc.copy() for k, v in enumerate(ordered_sc_site_list): if np.allclose(sc_ipos, v["site_frac_coords"], rtol=0.1, atol=0.1): sc_iindex = k if np.allclose(sc_epos, v["site_frac_coords"], rtol=0.1, atol=0.1): sc_eindex = k if sc_iindex is None: host_sc_insert.insert(0, working_ion, sc_ipos) ordered_sc_site_list.append( { "uc_site_type": one_hop["iindex"], "site_frac_coords": list(host_sc_insert[0].frac_coords), "extra_site": True, } ) sc_iindex = len(ordered_sc_site_list) - 1 if sc_eindex is None: host_sc_insert.insert(0, working_ion, sc_epos) ordered_sc_site_list.append( { "uc_site_type": one_hop["eindex"], "site_frac_coords": list(host_sc_insert[0].frac_coords), "extra_site": True, } ) sc_eindex = len(ordered_sc_site_list) - 1 return f"{sc_iindex}+{sc_eindex}", ordered_sc_site_list def get_distinct_hop_sites( inserted_ion_coords: List[str], insert_coords_combo: List ) -> Tuple[List, List[str], Dict]: """ This is a utils function that converts the site dict and combo into a site list and combo that contain only distince endpoints used the combos. # noqa: E501 """ dis_sites_list = [] dis_combo_list = [] mgdoc_sites_mapping = {} # type: dict combo_mapping = {} for one_combo in insert_coords_combo: ini, end = list(map(int, one_combo.split("+"))) if ini in mgdoc_sites_mapping.keys(): dis_ini = mgdoc_sites_mapping[ini] else: dis_sites_list.append(list(inserted_ion_coords[ini]["site_frac_coords"])) # type: ignore dis_ini = len(dis_sites_list) - 1 mgdoc_sites_mapping[ini] = dis_ini if end in mgdoc_sites_mapping.keys(): dis_end = mgdoc_sites_mapping[end] else: dis_sites_list.append(list(inserted_ion_coords[end]["site_frac_coords"])) # type: ignore dis_end = len(dis_sites_list) - 1 mgdoc_sites_mapping[end] = dis_end dis_combo = f"{dis_ini}+{dis_end}" dis_combo_list.append(dis_combo) combo_mapping[dis_combo] = one_combo return dis_sites_list, dis_combo_list, combo_mapping ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1726865782.04729 emmet-core-0.84.2/emmet/core/molecules/0000755000175100001770000000000014673360566017316 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/__init__.py0000644000175100001770000000000014673360562021411 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/atomic.py0000644000175100001770000001355714673360562021153 0ustar00runnerdockerfrom typing import List from hashlib import blake2b from pydantic import Field from emmet.core.mpid import MPculeID from emmet.core.qchem.task import TaskDocument from emmet.core.material import PropertyOrigin from emmet.core.molecules.molecule_property import PropertyDoc __author__ = "Evan Spotte-Smith " CHARGES_METHODS = ["nbo", "resp", "critic2", "mulliken"] SPINS_METHODS = ["nbo", "mulliken"] class PartialChargesDoc(PropertyDoc): """Atomic partial charges of a molecule""" property_name: str = "partial_charges" method: str = Field( ..., description="Method used to compute atomic partial charges" ) partial_charges: List[float] = Field( ..., description="Atomic partial charges for the molecule" ) @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, preferred_methods: List[str], deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Determine partial charges from a task document :param task: task document from which partial charges can be extracted :param molecule_id: MPculeID :param preferred_methods: list of methods; by default, NBO7, RESP, Critic2, and Mulliken, in that order :param kwargs: to pass to PropertyDoc :return: """ charges = None method = None if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule for m in preferred_methods: if m == "nbo" and task.output.nbo is not None: method = m charges = [ float(task.output.nbo["natural_populations"][0]["Charge"][str(i)]) for i in range(len(mol)) ] break elif m == "resp" and task.output.resp is not None: method = m charges = [float(i) for i in task.output.resp] break elif m == "critic2" and task.critic2 is not None: method = m charges = list([float(i) for i in task.critic2["processed"]["charges"]]) break elif m == "mulliken" and task.output.mulliken is not None: method = m if isinstance(task.output.mulliken[0], list): charges = [float(mull[0]) for mull in task.output.mulliken] else: charges = [float(i) for i in task.output.mulliken] break id_string = ( f"partial_charges-{molecule_id}-{task.task_id}-{task.lot_solvent}-{method}" ) h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() if charges is None: raise Exception("No valid partial charge information!") return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, partial_charges=charges, method=method, origins=[PropertyOrigin(name="partial_charges", task_id=task.task_id)], deprecated=deprecated, **kwargs, ) class PartialSpinsDoc(PropertyDoc): """Atomic partial charges of a molecule""" property_name: str = "partial_spins" method: str = Field(..., description="Method used to compute atomic partial spins") partial_spins: List[float] = Field( ..., description="Atomic partial spins for the molecule" ) @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, preferred_methods: List[str], deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Determine partial spins from a task document :param task: task document from which partial spins can be extracted :param molecule_id: MPculeID :param preferred_methods: list of methods; by default, NBO7 and Mulliken, in that order :param kwargs: to pass to PropertyDoc :return: """ spins = None method = None if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule if mol.spin_multiplicity == 1: raise Exception("Closed-shell molecule has no partial spins!") for m in preferred_methods: if m == "nbo" and task.output.nbo is not None: method = m spins = [ float(task.output.nbo["natural_populations"][0]["Density"][str(i)]) for i in range(len(mol)) ] break elif m == "mulliken" and task.output.mulliken is not None: method = m spins = [float(mull[1]) for mull in task.output.mulliken] break id_string = ( f"partial_spins-{molecule_id}-{task.task_id}-{task.lot_solvent}-{method}" ) h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() if spins is None: raise Exception("No valid partial spin information!") return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, partial_spins=spins, method=method, origins=[PropertyOrigin(name="partial_spins", task_id=task.task_id)], deprecated=deprecated, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/bonds.py0000644000175100001770000003432714673360562021002 0ustar00runnerdockerfrom typing import Dict, List, Any, Optional, Tuple import copy from hashlib import blake2b from pydantic import Field import networkx as nx from pymatgen.core.structure import Molecule from pymatgen.analysis.graphs import MoleculeGraph from emmet.core.mpid import MPculeID from emmet.core.utils import make_mol_graph from emmet.core.qchem.task import TaskDocument from emmet.core.material import PropertyOrigin from emmet.core.molecules.molecule_property import PropertyDoc __author__ = "Evan Spotte-Smith " metals = [ "Li", "Be", "Na", "Mg", "Al", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Cs", "Ba", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", ] BOND_METHODS = ["nbo", "critic2", "OpenBabelNN + metal_edge_extender"] def fix_C_Li_bonds(critic: Dict) -> Dict: """ Adjust C-Li coordinate bonding for Critic2 calculations. :param critic: Critic2 output dictionary :return: critic: modified Critic2 output dictionary """ for key in critic["bonding"]: if critic["bonding"][key]["atoms"] == ["Li", "C"] or critic["bonding"][key][ "atoms" ] == ["C", "Li"]: if ( critic["bonding"][key]["field"] <= 0.02 and critic["bonding"][key]["field"] > 0.012 and critic["bonding"][key]["distance"] < 2.5 ): critic["processed"]["bonds"].append( [int(entry) - 1 for entry in critic["bonding"][key]["atom_ids"]] ) return critic def _bonds_hybridization(nbo: Dict[str, Any], index: int): """ Extract bonds from "hybridization_character" NBO output """ bonds = set() warnings = set() if len(nbo["hybridization_character"]) > index: for bond_ind in nbo["hybridization_character"][index].get("type", list()): if nbo["hybridization_character"][index]["type"][bond_ind] != "BD": continue from_ind = ( int(nbo["hybridization_character"][index]["atom 1 number"][bond_ind]) - 1 ) to_ind = ( int(nbo["hybridization_character"][index]["atom 2 number"][bond_ind]) - 1 ) if ( nbo["hybridization_character"][index]["atom 1 symbol"][bond_ind] in metals ): m_contrib = float( nbo["hybridization_character"][index]["atom 1 polarization"][ bond_ind ] ) elif ( nbo["hybridization_character"][index]["atom 2 symbol"][bond_ind] in metals ): m_contrib = float( nbo["hybridization_character"][index]["atom 2 polarization"][ bond_ind ] ) else: m_contrib = None if m_contrib is None: bond_type = "covalent" elif m_contrib >= 30.0: bond_type = "covalent" warnings.add("Contains covalent bond with metal atom") else: bond_type = "electrostatic" bonds.add((from_ind, to_ind, bond_type)) return bonds, warnings def _bonds_peturbation( nbo: Dict[str, Any], index: int, poss_coord: Dict[Optional[int], List[Optional[int]]], energy_cutoff: float, metal_indices: List[int], ): """ Extract bonds from "perturbation_energy" NBO output """ bonds = set() # type: ignore # No metals, so don't need to use perturbation analysis to get bonds if len(metal_indices) == 0: return bonds if len(nbo["perturbation_energy"]) > index: for inter_ind in nbo["perturbation_energy"][index].get("donor type", list()): coord = False m_ind: Optional[int] = None x_ind: Optional[int] = None if ( int( nbo["perturbation_energy"][index]["acceptor atom 1 number"][ inter_ind ] ) - 1 in metal_indices ): if ( nbo["perturbation_energy"][index]["donor type"][inter_ind] == "LP" and nbo["perturbation_energy"][index]["acceptor type"][inter_ind] == "LV" ): coord = True m_ind = ( int( nbo["perturbation_energy"][index]["acceptor atom 1 number"][ inter_ind ] ) - 1 ) x_ind = ( int( nbo["perturbation_energy"][index]["donor atom 1 number"][ inter_ind ] ) - 1 ) elif ( nbo["perturbation_energy"][index]["donor type"][inter_ind] == "LP" and nbo["perturbation_energy"][index]["acceptor type"][inter_ind] == "RY*" ): coord = True m_ind = ( int( nbo["perturbation_energy"][index]["acceptor atom 1 number"][ inter_ind ] ) - 1 ) x_ind = ( int( nbo["perturbation_energy"][index]["donor atom 1 number"][ inter_ind ] ) - 1 ) elif ( nbo["perturbation_energy"][index]["donor atom 1 number"][inter_ind] - 1 in metal_indices ): if ( nbo["perturbation_energy"][index]["donor type"][inter_ind] == "LP" and nbo["perturbation_energy"][index]["acceptor type"][inter_ind] == "LV" ): coord = True m_ind = ( int( nbo["perturbation_energy"][index]["donor atom 1 number"][ inter_ind ] ) - 1 ) x_ind = ( int( nbo["perturbation_energy"][index]["acceptor atom 1 number"][ inter_ind ] ) - 1 ) if not coord: continue elif x_ind not in poss_coord[m_ind]: continue energy = float( nbo["perturbation_energy"][index]["perturbation energy"][inter_ind] ) if energy >= energy_cutoff: bonds.add((x_ind, m_ind, "electrostatic")) return bonds def nbo_molecule_graph(mol: Molecule, nbo: Dict[str, Any]): """ Construct a molecule graph from NBO data. :param mol: molecule to be analyzed :param nbo: Output from NBO7 :return: """ mg = MoleculeGraph.with_empty_graph(mol) alpha_bonds, warnings = _bonds_hybridization(nbo, 1) beta_bonds, new_warnings = _bonds_hybridization(nbo, 3) warnings = warnings.union(new_warnings) distance_cutoff = 3.0 energy_cutoff = 3.0 metal_indices = [i for i, e in enumerate(mol.species) if str(e) in metals] poss_coord: Dict[Optional[int], List[Optional[int]]] = dict() dist_mat = mol.distance_matrix for i in metal_indices: poss_coord[i] = list() row = dist_mat[i] for j, val in enumerate(row): if i != j and val < distance_cutoff: poss_coord[i].append(j) new_alpha_bonds = _bonds_peturbation( nbo, 0, poss_coord, energy_cutoff, metal_indices ) alpha_bonds = alpha_bonds.union(new_alpha_bonds) if mol.spin_multiplicity != 1: new_beta_bonds = _bonds_peturbation( nbo, 1, poss_coord, energy_cutoff, metal_indices ) beta_bonds = beta_bonds.union(new_beta_bonds) sorted_alpha = set([tuple(sorted([a[0], a[1]])) for a in alpha_bonds]) sorted_beta = set([tuple(sorted([b[0], b[1]])) for b in beta_bonds]) if sorted_alpha != sorted_beta: warnings.add("Difference in bonding between alpha and beta electrons") for bond in alpha_bonds.union(beta_bonds): if (bond[0], bond[1]) not in mg.graph.edges() and ( bond[1], bond[0], ) not in mg.graph.edges(): if bond[0] < bond[1]: mg.add_edge(bond[0], bond[1], edge_properties={"type": bond[2]}) else: mg.add_edge(bond[1], bond[0], edge_properties={"type": bond[2]}) mg_copy = copy.deepcopy(mg) mg_copy.remove_nodes(metal_indices) try: if not nx.is_connected(mg_copy.graph.to_undirected()): warnings.add("Metal-centered complex") except nx.exception.NetworkXPointlessConcept: if len(mg.molecule) == 1: warnings.add("Single-atom; no bonds") return (mg, list(warnings)) class MoleculeBondingDoc(PropertyDoc): """Representation of molecular bonding.""" property_name: str = "bonding" molecule_graph: MoleculeGraph = Field(..., description="Molecule graph") method: str = Field(..., description="Method used to compute molecule graph") bond_types: Dict[str, List[float]] = Field( dict(), description="Dictionary of bond types to their length, e.g. C-O to " "a list of the lengths of C-O bonds in Angstrom.", ) bonds: List[Tuple[int, int]] = Field( [], description="List of bonds in the form (a, b), where a and b are 0-indexed atom indices", ) bonds_nometal: List[Tuple[int, int]] = Field( [], description="List of bonds in the form (a, b), where a and b are 0-indexed atom indices, " "with all metal ions removed", ) @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, preferred_methods: List[str], deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Determine bonding from a task document Method preferences are as follows: - NBO7 - OpenBabelNN + metal_edge_extender in pymatgen - Critic2 (really OpenBabelNN + metal_edge_extender + Critic2) :param task: task document from which bonding properties can be extracted :param molecule_id: MPculeID :param preferred_methods: list of methods; by default, NBO7, Critic2, and the combination of OpenBabelNN and metal_edge_extender in pymatgen, in that order :param kwargs: to pass to PropertyDoc :return: """ mg_made = False method = None warnings = list() if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule for m in preferred_methods: if mg_made: break if ( m == "nbo" and task.output.nbo is not None and ( task.orig["rem"].get("run_nbo6", False) or task.orig["rem"].get("nbo_external", False) ) ): method = "nbo" mg, warnings = nbo_molecule_graph(mol, task.output.nbo) mg_made = True elif m == "critic2" and task.critic2 is not None: method = "critic2" critic = fix_C_Li_bonds(task.critic2) critic_bonds = critic["processed"]["bonds"] mg = make_mol_graph(mol, critic_bonds=critic_bonds) mg_made = True else: method = "OpenBabelNN + metal_edge_extender" mg = make_mol_graph(mol) mg_made = True bonds = list() for bond in mg.graph.edges(): bonds.append(sorted([bond[0], bond[1]])) # Calculate bond lengths bond_types = dict() for u, v in mg.graph.edges(): species_u = str(mg.molecule.species[u]) species_v = str(mg.molecule.species[v]) if species_u < species_v: species = f"{species_u}-{species_v}" else: species = f"{species_v}-{species_u}" dist = mg.molecule.get_distance(u, v) if species not in bond_types: bond_types[species] = [dist] else: bond_types[species].append(dist) m_inds = [e for e in range(len(mol)) if str(mol.species[e]) in metals] bonds_nometal = list() for bond in bonds: if not any([m in bond for m in m_inds]): bonds_nometal.append(bond) id_string = f"bonding-{molecule_id}-{task.task_id}-{task.lot_solvent}-{method}" h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, method=method, warnings=warnings, molecule_graph=mg, bond_types=bond_types, bonds=bonds, bonds_nometal=bonds_nometal, origins=[PropertyOrigin(name="bonding", task_id=task.task_id)], deprecated=deprecated, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/metal_binding.py0000644000175100001770000004111014673360562022455 0ustar00runnerdockerfrom typing import Dict, List, Optional, Type, TypeVar, Union from hashlib import blake2b from scipy.stats import describe from pydantic import BaseModel, Field from pymatgen.core.periodic_table import Species, Element from emmet.core.mpid import MPculeID from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.molecules.molecule_property import PropertyDoc from emmet.core.molecules.atomic import PartialChargesDoc, PartialSpinsDoc from emmet.core.molecules.bonds import MoleculeBondingDoc from emmet.core.molecules.thermo import MoleculeThermoDoc __author__ = "Evan Spotte-Smith " METAL_BINDING_METHODS = ["nbo", "mulliken-OB-mee"] T = TypeVar("T", bound="MetalBindingDoc") class MetalBindingData(BaseModel): """ Metal binding information for one metal or ion in a molecule """ metal_molecule_id: MPculeID = Field( ..., description="The MPculeID of the metal atom or ion being bound" ) nometal_molecule_id: MPculeID = Field( ..., description="The MPculeID of the molecule with the metal atom/ion removed" ) metal_index: Optional[int] = Field( None, description="Index of the metal in this Molecule (in case of a molecule with multiple identical " "metal atoms/ions)", ) metal_element: Optional[Union[str, Species, Element]] = Field( None, description="The metal bound to the molecule" ) metal_partial_charge: Optional[float] = Field( None, description="The exact calculated partial charge of the metal" ) metal_partial_spin: Optional[float] = Field( None, description="The exact calculated partial spin on the metal" ) metal_assigned_charge: Optional[float] = Field( None, description="The integral charge assigned to this metal based on partial charge/spin data", ) metal_assigned_spin: Optional[float] = Field( None, description="The integral spin multiplicity assigned to this metal based on partial spin data", ) number_coordinate_bonds: Optional[int] = Field( None, description="The number of atoms neighboring the metal atom or ion of interest", ) coordinating_atoms: Optional[List[str]] = Field( None, description="The elements/species coordinating the metal." ) coordinate_bond_lengths: Optional[ Dict[str, Dict[str, Union[float, List[float]]]] ] = Field( None, description="Bond lengths and statistics broken down by the coordinating atoms", ) binding_energy: Optional[float] = Field( None, description="The electronic energy change (∆E) of binding (units: eV)" ) binding_enthalpy: Optional[float] = Field( None, description="The enthalpy change (∆H) of binding (units: eV)" ) binding_entropy: Optional[float] = Field( None, description="The entropy change (∆S) of binding (units: eV/K)" ) binding_free_energy: Optional[float] = Field( None, description="The free energy change (∆G) of binding (units: eV)" ) metal_thermo_property_id: Optional[str] = Field( None, description="ID of MoleculeThermoDoc used to obtain the thermochemistry of the metal atom/ion", ) nometal_thermo_property_id: Optional[str] = Field( None, description="ID of MoleculeThermoDoc used to obtain the thermochemistry of of the molecule with the " "metal atom/ion removed", ) def get_id_string(self): """ Return a string representation of the binding data for this atom in the molecule """ id_str = f"{self.metal_element}-{self.metal_index}-" id_str += f"{self.metal_thermo_property_id}-{self.nometal_thermo_property_id}" return id_str class MetalBindingDoc(PropertyDoc): """Metal binding properties of a molecule""" property_name: str = "metal_binding" method: str = Field( ..., description="Method used to determine the charge, spin, and coordination environment of a metal", ) binding_partial_charges_property_id: Optional[str] = Field( None, description="ID of PartialChargesDoc used to estimate metal charge", ) binding_partial_spins_property_id: Optional[str] = Field( None, description="ID of PartialSpinsDoc used to estimate metal spin", ) binding_partial_charges_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used to calculate atomic partial charges", ) binding_partial_spins_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used to calculate atomic partial spins", ) binding_charge_spin_method: Optional[str] = Field( None, description="The method used for partial charges and spins (must be the same).", ) binding_bonding_property_id: Optional[str] = Field( None, description="ID of MoleculeBondingDoc used to detect bonding in this molecule", ) binding_bonding_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used to determine the coordination environment " "of the metal atom or ion", ) binding_bonding_method: Optional[str] = Field( None, description="The method used for to define bonding." ) binding_thermo_property_id: Optional[str] = Field( None, description="ID of MoleculeThermoDoc used to obtain this molecule's thermochemistry", ) binding_thermo_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used for uncorrected thermochemistry", ) binding_thermo_correction_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used to correct the electronic energy", ) binding_thermo_combined_lot_solvent: Optional[str] = Field( None, description="Combination of level of theory and solvent used for molecular thermochemistry, combining " "both the frequency calculation and (potentially) the single-point energy correction.", ) binding_data: Optional[List[MetalBindingData]] = Field( None, description="Binding data for each metal atom or ion in the molecule" ) @classmethod def from_docs( cls: Type[T], method: str, metal_indices: List[int], base_molecule_doc: MoleculeDoc, partial_charges: PartialChargesDoc, partial_spins: Optional[PartialSpinsDoc], bonding: MoleculeBondingDoc, base_thermo: MoleculeThermoDoc, metal_thermo: Dict[int, MoleculeThermoDoc], nometal_thermo: Dict[int, MoleculeThermoDoc], **kwargs, ): # type: ignore[override] """ Construct a document describing the binding energy of a metal atom or ion to a molecule from MoleculeThermoDocs (for thermochemistry), PartialChargesDocs and PartialSpinsDocs (to assess the oxidation state and spin state of the metal), and MoleculeBondingDocs (to assess the coordination environment of the metal). :param method: What method was used to construct this document? :param metal_indices: List of indices in the Molecule corresponding to metals :param base_molecule_doc: MoleculeDoc used for basic ID, species, structure information :param partial_charges: PartialChargesDoc used to determine the oxidation state of the metal of interest :param partial_spins: PartialSpinsDoc used to determine the spin state of the metal of interest :param bonding: MoleculeBondingDoc used to determine the coordination environment :param base_thermo: MoleculeThermoDoc for the molecule of interest. :param metal_thermo: Dict[int, MoleculeThermoDoc], where the keys are the indices of the metal ions or atoms in this molecule and the values are the MoleculeThermoDocs corresponding to the appropriate metal (with the correct charge and spin) :param nometal_thermo: Dict[int, MoleculeThermoDoc], where the keys are the indices of the metal ions or atoms in this molecule and the values are the MoleculeThermoDocs corresponding to the appropriate metal (with the correct charge and spin) :param kwargs: To be passed to PropertyDoc :return: """ # Sanity checks for i, doc in metal_thermo.items(): if not doc.lot_solvent == base_thermo.lot_solvent: raise ValueError( "All MoleculeThermoDocs must use the same lot_solvent!" ) for i, doc in nometal_thermo.items(): if not doc.lot_solvent == base_thermo.lot_solvent: raise ValueError( "All MoleculeThermoDocs must use the same lot_solvent!" ) if partial_spins is not None: if not ( partial_charges.method == partial_spins.method and partial_charges.lot_solvent == partial_spins.lot_solvent ): raise ValueError( "Partial charges and partial spins must use the same method and lot_solvent!" ) if not ( base_thermo.solvent == partial_charges.solvent and base_thermo.solvent == bonding.solvent ): raise ValueError("All documents must use the same solvent!") partial_charges_property_id = partial_charges.property_id partial_charges_lot_solvent = partial_charges.lot_solvent if partial_spins is not None: partial_spins_property_id = partial_spins.property_id partial_spins_lot_solvent = partial_spins.lot_solvent else: partial_spins_property_id = None partial_spins_lot_solvent = None bonding_property_id = bonding.property_id bonding_lot_solvent = bonding.lot_solvent thermo_property_id = base_thermo.property_id thermo_lot_solvent = base_thermo.lot_solvent thermo_correction_lot_solvent = base_thermo.correction_lot_solvent thermo_combined_lot_solvent = base_thermo.combined_lot_solvent level_of_theory = base_thermo.level_of_theory solvent = base_thermo.solvent lot_solvent = base_thermo.lot_solvent molecule = base_molecule_doc.molecule dist_mat = molecule.distance_matrix species = base_molecule_doc.species binding_data = list() for metal_index in metal_indices: metal_element = species[metal_index] this_metal_thermo = metal_thermo.get(metal_index) this_nometal_thermo = nometal_thermo.get(metal_index) if this_metal_thermo is None or this_nometal_thermo is None: continue # Partial charges and spins charge = partial_charges.partial_charges[metal_index] if partial_spins is not None: spin = partial_spins.partial_spins[metal_index] else: spin = None # Coordinate bonding relevant_bonds = [b for b in bonding.bonds if metal_index in b] number_coordinate_bonds = len(relevant_bonds) # Binding is not meaningful if there are no coordinate bonds if number_coordinate_bonds == 0: return None coordinating_atoms = list() coordinate_bond_lengths = dict() # type: ignore for bond in relevant_bonds: other_ids = [i for i in bond if i != metal_index] # Edge case - possible if we (later) account for 3-center bonds or hyperbonds if len(other_ids) != 1: continue other_index = other_ids[0] other_species = str(species[other_index]) coordinating_atoms.append(other_species) if other_species not in coordinate_bond_lengths: coordinate_bond_lengths[other_species] = { "lengths": list(), } this_length = dist_mat[metal_index][other_index] coordinate_bond_lengths[other_species]["lengths"].append(this_length) for s, data in coordinate_bond_lengths.items(): stats = describe(data["lengths"], nan_policy="omit") coordinate_bond_lengths[s]["min"] = stats.minmax[0] coordinate_bond_lengths[s]["max"] = stats.minmax[1] coordinate_bond_lengths[s]["mean"] = stats.mean coordinate_bond_lengths[s]["variance"] = stats.variance coordinating_atoms = sorted(coordinating_atoms) # Thermo binding_e = None binding_h = None binding_s = None binding_g = None if this_metal_thermo is not None and this_nometal_thermo is not None: thermos = [base_thermo, this_metal_thermo, this_nometal_thermo] binding_e = ( thermos[1].electronic_energy + thermos[2].electronic_energy ) - thermos[0].electronic_energy if all([x.total_enthalpy is not None for x in thermos]): binding_h = ( thermos[1].total_enthalpy + thermos[2].total_enthalpy ) - thermos[0].total_enthalpy if all([x.total_entropy is not None for x in thermos]): binding_s = ( thermos[1].total_entropy + thermos[2].total_entropy ) - thermos[0].total_entropy if all([x.free_energy is not None for x in thermos]): binding_g = ( thermos[1].free_energy + thermos[2].free_energy ) - thermos[0].free_energy binding_data.append( MetalBindingData( metal_molecule_id=this_metal_thermo.molecule_id, nometal_molecule_id=this_nometal_thermo.molecule_id, metal_index=metal_index, metal_element=metal_element, metal_partial_charge=charge, metal_partial_spin=spin, metal_assigned_charge=this_metal_thermo.charge, metal_assigned_spin=this_metal_thermo.spin_multiplicity, number_coordinate_bonds=number_coordinate_bonds, coordinating_atoms=coordinating_atoms, coordinate_bond_lengths=coordinate_bond_lengths, binding_energy=binding_e, binding_enthalpy=binding_h, binding_entropy=binding_s, binding_free_energy=binding_g, metal_thermo_property_id=this_metal_thermo.property_id, nometal_thermo_property_id=this_nometal_thermo.property_id, ) ) # Property ID id_string = f"binding-{base_molecule_doc.molecule_id}-{lot_solvent}-" id_string += f"{partial_charges_property_id}-{partial_spins_property_id}-" id_string += f"{bonding.property_id}-" id_string += f"{thermo_property_id}" for d in binding_data: id_string += f"-{d.get_id_string()}" h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() return super().from_molecule( meta_molecule=base_molecule_doc.molecule, property_id=property_id, molecule_id=base_molecule_doc.molecule_id, level_of_theory=level_of_theory, solvent=solvent, lot_solvent=lot_solvent, method=method, binding_partial_charges_property_id=partial_charges_property_id, binding_partial_spins_property_id=partial_spins_property_id, binding_partial_charges_lot_solvent=partial_charges_lot_solvent, binding_partial_spins_lot_solvent=partial_spins_lot_solvent, binding_charge_spin_method=partial_charges.method, binding_bonding_property_id=bonding_property_id, binding_bonding_lot_solvent=bonding_lot_solvent, binding_bonding_method=bonding.method, binding_thermo_property_id=thermo_property_id, binding_thermo_lot_solvent=thermo_lot_solvent, binding_thermo_correction_lot_solvent=thermo_correction_lot_solvent, binding_thermo_combined_lot_solvent=thermo_combined_lot_solvent, binding_data=binding_data, deprecated=False, origins=[], **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/molecule_property.py0000644000175100001770000000553414673360562023444 0ustar00runnerdocker""" Core definition of a Materials Document """ from __future__ import annotations from datetime import datetime from typing import Sequence, Type, TypeVar, List, Optional from pydantic import Field from pymatgen.core.structure import Molecule from emmet.core.qchem.calc_types import LevelOfTheory from emmet.core.material import PropertyOrigin from emmet.core.mpid import MPculeID from emmet.core.structure import MoleculeMetadata __author__ = "Evan Spotte-Smith " S = TypeVar("S", bound="PropertyDoc") class PropertyDoc(MoleculeMetadata): """ Base model definition for any singular molecule property. This may contain any amount of molecule metadata for the purpose of search This is intended to be inherited and extended not used directly """ property_name: str property_id: str = Field( ..., description="The unique identifier of this property document." ) molecule_id: MPculeID = Field( ..., description="The ID of the molecule, used as a reference across property documents." "This comes in the form of an MPculeID (or appropriately formatted string)", ) deprecated: bool = Field( ..., description="Whether this property document is deprecated.", ) deprecation_reasons: Optional[List[str]] = Field( None, description="List of deprecation tags detailing why this document isn't valid", ) level_of_theory: Optional[LevelOfTheory] = Field( None, description="Level of theory used to generate this property document." ) solvent: Optional[str] = Field( None, description="String representation of the solvent " "environment used to generate this property document.", ) lot_solvent: Optional[str] = Field( None, description="String representation of the level of theory and solvent " "environment used to generate this property document.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) origins: Sequence[PropertyOrigin] = Field( [], description="Dictionary for tracking the provenance of properties" ) warnings: Sequence[str] = Field( [], description="Any warnings related to this property" ) @classmethod def from_molecule( # type: ignore[override] cls: Type[S], meta_molecule: Molecule, property_id: str, molecule_id: MPculeID, **kwargs, ) -> S: """ Builds a molecule document using the minimal amount of information """ return super().from_molecule( meta_molecule=meta_molecule, property_id=property_id, molecule_id=molecule_id, **kwargs, ) # type: ignore ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/orbitals.py0000644000175100001770000004762714673360562021523 0ustar00runnerdockerfrom typing import List, Optional, Dict, Any from hashlib import blake2b from pydantic import Field from monty.json import MSONable from emmet.core.mpid import MPculeID from emmet.core.material import PropertyOrigin from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.molecule_property import PropertyDoc __author__ = "Evan Spotte-Smith " class NaturalPopulation(MSONable): def __init__( self, atom_index: int, core_electrons: float, valence_electrons: float, rydberg_electrons: float, total_electrons: float, ): """ Basic description of an atomic electron population. :param atom_index (int): :param core_electrons (float): Number of core electrons on this atom :param valence_electrons (float): Number of valence electrons on this atom :param rydberg_electrons (float): Number of Rydberg electrons on this atom :param total_electrons (float): Total number of electrons on this atom """ self.atom_index = int(atom_index) self.core_electrons = float(core_electrons) self.valence_electrons = float(valence_electrons) self.rydberg_electrons = float(rydberg_electrons) self.total_electrons = float(total_electrons) class LonePair(MSONable): def __init__( self, index: int, number: int, atom_index: int, s_character: float, p_character: float, d_character: float, f_character: float, occupancy: float, type_code: str, ): """ Basic description of a lone pair (LP) natural bonding orbital. :param index (int): Lone pair index from NBO. 1-indexed :param number (int): Another index, for cases where there are multiple lone pairs on an atom. 1-indexed :param atom_index (int): 0-indexed :param s_character (float): What fraction of this orbital is s-like in nature. :param p_character (float): What fraction of this orbital is p-like in nature. :param d_character (float): What fraction of this orbital is d-like in nature. :param f_character (float): What fraction of this orbital is f-like in nature. :param occupancy (float): Total electron occupancy of this lone pair :param type_code (str): Description of this lone pair (ex: "LV" for "lone valence") """ self.index = int(index) self.number = int(number) self.atom_index = int(atom_index) self.s_character = float(s_character) self.p_character = float(p_character) self.d_character = float(d_character) self.f_character = float(f_character) self.occupancy = float(occupancy) self.type_code = type_code class Bond(MSONable): def __init__( self, index: int, number: int, atom1_index: int, atom2_index: int, atom1_s_character: float, atom2_s_character: float, atom1_p_character: float, atom2_p_character: float, atom1_d_character: float, atom2_d_character: float, atom1_f_character: float, atom2_f_character: float, atom1_polarization: float, atom2_polarization: float, atom1_polarization_coeff: float, atom2_polarization_coeff: float, occupancy: float, type_code: str, ): """ Basic description of a bond (BD) natural bonding orbital. :param index: Bond orbital index from NBO. 1-indexed. :param number: Another index, for cases where there are multiple bonds between two atoms. 1-indexed :param atom1_index: Index of first atom involved in this orbital. 0-indexed :param atom2_index: Index of second atom involved in this orbital. 0-indexed :param atom1_s_character: What fraction of this orbital comes from atom 1 s electrons :param atom2_s_character: What fraction of this orbital comes from atom 2 s electrons :param atom1_p_character: What fraction of this orbital comes from atom 1 p electrons :param atom2_p_character: What fraction of this orbital comes from atom 2 p electrons :param atom1_d_character: What fraction of this orbital comes from atom 1 d electrons :param atom2_d_character: What fraction of this orbital comes from atom 2 d electrons :param atom1_f_character: What fraction of this orbital comes from atom 1 f electrons :param atom2_f_character: What fraction of this orbital comes from atom 2 f electrons :param atom1_polarization: Percentage of polarization from atom 1 :param atom2_polarization: Percentage of polarization from atom 2 :param atom1_polarization_coeff: Polarization coefficient of atom 1 :param atom2_polarization_coeff: Polarization coefficient of atom 2 :param occupancy: Total electron occupancy of this orbital :param type_code: Description of this bonding orbital (ex: BD for bonding, BD* for anti-bonding) """ self.index = int(index) self.number = int(number) self.atom1_index = int(atom1_index) self.atom2_index = int(atom2_index) self.atom1_s_character = float(atom1_s_character) self.atom2_s_character = float(atom2_s_character) self.atom1_p_character = float(atom1_p_character) self.atom2_p_character = float(atom2_p_character) self.atom1_d_character = float(atom1_d_character) self.atom2_d_character = float(atom2_d_character) self.atom1_f_character = float(atom1_f_character) self.atom2_f_character = float(atom2_f_character) self.atom1_polarization = float(atom1_polarization) self.atom2_polarization = float(atom2_polarization) self.atom1_polarization_coeff = float(atom1_polarization_coeff) self.atom2_polarization_coeff = float(atom2_polarization_coeff) self.occupancy = float(occupancy) self.type_code = type_code class Interaction(MSONable): def __init__( self, perturbation_energy: float, energy_difference: float, fock_element: float, donor_index: int, acceptor_index: int, donor_type: str, acceptor_type: str, donor_atom1_index: int, acceptor_atom1_index: int, donor_atom2_index: Optional[int] = None, acceptor_atom2_index: Optional[int] = None, ): self.donor_index = int(donor_index) self.acceptor_index = int(acceptor_index) self.donor_type = donor_type self.acceptor_type = acceptor_type if isinstance(donor_atom2_index, int): donor2 = int(donor_atom2_index) else: donor2 = None if isinstance(acceptor_atom2_index, int): acceptor2 = int(acceptor_atom2_index) else: acceptor2 = None self.donor_atom_indices = (int(donor_atom1_index), donor2) self.acceptor_atom_indices = (int(acceptor_atom1_index), acceptor2) self.perturbation_energy = float(perturbation_energy) self.energy_difference = float(energy_difference) self.fock_element = float(fock_element) def as_dict(self): return { "@module": self.__class__.__module__, "@class": self.__class__.__name__, "donor_index": self.donor_index, "acceptor_index": self.acceptor_index, "donor_type": self.donor_type, "acceptor_type": self.acceptor_type, "donor_atom_indices": self.donor_atom_indices, "acceptor_atom_indices": self.acceptor_atom_indices, "perturbation_energy": self.perturbation_energy, "energy_difference": self.energy_difference, "fock_element": self.fock_element, } @classmethod def from_dict(cls, d): return cls( d["perturbation_energy"], d["energy_difference"], d["fock_element"], d["donor_index"], d["acceptor_index"], d["donor_type"], d["acceptor_type"], d["donor_atom_indices"][0], d["acceptor_atom_indices"][0], d["donor_atom_indices"][1], d["acceptor_atom_indices"][1], ) class OrbitalDoc(PropertyDoc): property_name: str = "natural bonding orbitals" # Always populated - closed-shell and open-shell open_shell: bool = Field( ..., description="Is this molecule open-shell (spin multiplicity != 1)?" ) nbo_population: List[NaturalPopulation] = Field( ..., description="Natural electron populations of the molecule" ) # Populated for closed-shell molecules nbo_lone_pairs: Optional[List[LonePair]] = Field( None, description="Lone pair orbitals of a closed-shell molecule" ) nbo_bonds: Optional[List[Bond]] = Field( None, description="Bond-like orbitals of a closed-shell molecule" ) nbo_interactions: Optional[List[Interaction]] = Field( None, description="Orbital-orbital interactions of a closed-shell molecule" ) # Populated for open-shell molecules alpha_population: Optional[List[NaturalPopulation]] = Field( None, description="Natural electron populations of the alpha electrons of an " "open-shell molecule", ) beta_population: Optional[List[NaturalPopulation]] = Field( None, description="Natural electron populations of the beta electrons of an " "open-shell molecule", ) alpha_lone_pairs: Optional[List[LonePair]] = Field( None, description="Alpha electron lone pair orbitals of an open-shell molecule" ) beta_lone_pairs: Optional[List[LonePair]] = Field( None, description="Beta electron lone pair orbitals of an open-shell molecule" ) alpha_bonds: Optional[List[Bond]] = Field( None, description="Alpha electron bond-like orbitals of an open-shell molecule" ) beta_bonds: Optional[List[Bond]] = Field( None, description="Beta electron bond-like orbitals of an open-shell molecule" ) alpha_interactions: Optional[List[Interaction]] = Field( None, description="Alpha electron orbital-orbital interactions of an open-shell molecule", ) beta_interactions: Optional[List[Interaction]] = Field( None, description="Beta electron orbital-orbital interactions of an open-shell molecule", ) @staticmethod def get_populations(nbo: Dict[str, Any], indices: List[int]): """ Helper function to extract natural population information from NBO output :param nbo: Dictionary of NBO output data :param indices: Data subsets from which to extract natural populations :return: population_sets (list of lists of NaturalPopulation) """ population_sets = list() for pop_ind in indices: pops = nbo["natural_populations"][pop_ind] population = list() for ind, atom_num in pops["No"].items(): population.append( NaturalPopulation( atom_num - 1, pops["Core"][ind], pops["Valence"][ind], pops["Rydberg"][ind], pops["Total"][ind], ) ) population_sets.append(population) return population_sets @staticmethod def get_lone_pairs(nbo: Dict[str, Any], indices: List[int]): """ Helper function to extract lone pair information from NBO output :param nbo: Dictionary of NBO output data :param indices: Data subsets from which to extract lone pair information :return: lone_pairs (list of LonePairs) """ lone_pair_sets = list() for lp_ind in indices: lps = nbo["hybridization_character"][lp_ind] lone_pairs = list() for ind, orb_ind in lps.get("bond index", dict()).items(): this_lp = LonePair( orb_ind, lps["orbital index"][ind], int(lps["atom number"][ind]) - 1, lps["s"][ind], lps["p"][ind], lps["d"][ind], lps["f"][ind], lps["occupancy"][ind], lps["type"][ind], ) lone_pairs.append(this_lp) lone_pair_sets.append(lone_pairs) return lone_pair_sets @staticmethod def get_bonds(nbo: Dict[str, Any], indices: List[int]): """ Helper function to extract bonding information from NBO output :param nbo: Dictionary of NBO output data :param indices: Data subsets from which to extract bonds :return: bonds (list of Bonds) """ bond_sets = list() for bd_ind in indices: bds = nbo["hybridization_character"][bd_ind] bonds = list() for ind, orb_ind in bds.get("bond index", dict()).items(): this_bond = Bond( orb_ind, bds["orbital index"][ind], int(bds["atom 1 number"][ind]) - 1, int(bds["atom 2 number"][ind]) - 1, bds["atom 1 s"][ind], bds["atom 2 s"][ind], bds["atom 1 p"][ind], bds["atom 2 p"][ind], bds["atom 1 d"][ind], bds["atom 2 d"][ind], bds["atom 1 f"][ind], bds["atom 2 f"][ind], bds["atom 1 polarization"][ind], bds["atom 2 polarization"][ind], bds["atom 1 pol coeff"][ind], bds["atom 2 pol coeff"][ind], bds["occupancy"][ind], bds["type"][ind], ) bonds.append(this_bond) bond_sets.append(bonds) return bond_sets @staticmethod def get_interactions(nbo: Dict[str, Any], indices: List[int]): """ Helper function to extract orbital interaction information from NBO output :param nbo: Dictionary of NBO output data :param indices: Data subsets from which to extract interactions :return: interactions (list of Interactions) """ interaction_sets = list() for pert_ind in indices: perts = nbo["perturbation_energy"][pert_ind] interactions = list() for ind in perts.get("donor bond index", list()): if perts["donor atom 2 number"].get(ind) is None: donor_atom2_number = None else: donor_atom2_number = int(perts["donor atom 2 number"][ind]) - 1 if perts["acceptor atom 2 number"].get(ind) is None: acceptor_atom2_number = None else: acceptor_atom2_number = ( int(perts["acceptor atom 2 number"][ind]) - 1 ) this_inter = Interaction( perts["perturbation energy"][ind], perts["energy difference"][ind], perts["fock matrix element"][ind], int(perts["donor bond index"][ind]), int(perts["acceptor bond index"][ind]), perts["donor type"][ind], perts["acceptor type"][ind], int(perts["donor atom 1 number"][ind]) - 1, int(perts["acceptor atom 1 number"][ind]) - 1, donor_atom2_number, acceptor_atom2_number, ) interactions.append(this_inter) interaction_sets.append(interactions) return interaction_sets @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Construct an orbital document from a task :param task: document from which vibrational properties can be extracted :param molecule_id: MPculeID :param deprecated: bool. Is this document deprecated? :param kwargs: to pass to PropertyDoc :return: """ if task.output.nbo is None: raise ValueError("No NBO output in task {}!".format(task.task_id)) elif not ( task.orig["rem"].get("run_nbo6", False) or task.orig["rem"].get("nbo_external", False) ): raise ValueError("Only NBO7 is allowed!") nbo = task.output.nbo if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule spin = mol.spin_multiplicity # Closed-shell if int(spin) == 1: pops_inds = [0] lps_inds = [0] bds_inds = [1] perts_inds = [0] # Open-shell else: pops_inds = [0, 1, 2] lps_inds = [0, 2] bds_inds = [1, 3] perts_inds = [0, 1] for dset, inds in [ ("natural_populations", pops_inds), ("hybridization_character", bds_inds), ("perturbation_energy", perts_inds), ]: if len(nbo[dset]) < inds[-1]: return population_sets = cls.get_populations(nbo, pops_inds) lone_pair_sets = cls.get_lone_pairs(nbo, lps_inds) bond_sets = cls.get_bonds(nbo, bds_inds) interaction_sets = cls.get_interactions(nbo, perts_inds) if not ( task.orig["rem"].get("run_nbo6") or task.orig["rem"].get("nbo_external", False) ): warnings = ["Using NBO5"] else: warnings = list() id_string = ( f"natural_bonding_orbitals-{molecule_id}-{task.task_id}-{task.lot_solvent}" ) h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() if int(spin) == 1: return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, open_shell=False, nbo_population=population_sets[0], nbo_lone_pairs=lone_pair_sets[0], nbo_bonds=bond_sets[0], nbo_interactions=interaction_sets[0], origins=[ PropertyOrigin( name="natural_bonding_orbitals", task_id=task.task_id ) ], warnings=warnings, deprecated=deprecated, **kwargs, ) else: return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, open_shell=True, nbo_population=population_sets[0], alpha_population=population_sets[1], beta_population=population_sets[2], alpha_lone_pairs=lone_pair_sets[0], beta_lone_pairs=lone_pair_sets[1], alpha_bonds=bond_sets[0], beta_bonds=bond_sets[1], alpha_interactions=interaction_sets[0], beta_interactions=interaction_sets[1], origins=[ PropertyOrigin( name="natural bonding orbitals", task_id=task.task_id ) ], warnings=warnings, deprecated=deprecated, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/redox.py0000644000175100001770000002306014673360562021006 0ustar00runnerdockerfrom hashlib import blake2b from typing import Any, Dict, Optional, Type, TypeVar from pydantic import Field from emmet.core.qchem.task import TaskDocument from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.material import PropertyOrigin from emmet.core.molecules.molecule_property import PropertyDoc from emmet.core.molecules.thermo import get_free_energy, MoleculeThermoDoc from emmet.core.mpid import MPID, MPculeID __author__ = "Evan Spotte-Smith " reference_potential = 4.44 T = TypeVar("T", bound="RedoxDoc") class RedoxDoc(PropertyDoc): """ Molecular properties related to reduction and oxidation, including vertical ionization energies and electron affinities, as well as reduction and oxidation potentials """ property_name: str = "redox" base_property_id: str = Field( description="Property ID for the thermodynamic data of the " "base molecule" ) electron_affinity: Optional[float] = Field( None, description="Vertical electron affinity (units: eV)" ) ea_task_id: Optional[MPID] = Field( None, description="Task ID for the electron affinity calculation" ) ionization_energy: Optional[float] = Field( None, description="Vertical ionization energy (units: eV)" ) ie_task_id: Optional[MPID] = Field( None, description="Task ID for the ionization energy calculation" ) reduction_energy: Optional[float] = Field( None, description="Adiabatic electronic energy of reduction (units: eV)" ) reduction_free_energy: Optional[float] = Field( None, description="Adiabatic free energy of reduction (units: eV)" ) red_molecule_id: Optional[MPculeID] = Field( None, description="Molecule ID for adiabatic reduction" ) red_property_id: Optional[str] = Field( None, description="Property ID for the thermodynamic data of the " "reduced molecule", ) oxidation_energy: Optional[float] = Field( None, description="Adiabatic electronic energy of oxidation (units: eV)" ) oxidation_free_energy: Optional[float] = Field( None, description="Adiabatic free energy of oxidation (units: eV)" ) ox_molecule_id: Optional[MPculeID] = Field( None, description="Molecule ID for adiabatic oxidation" ) ox_property_id: Optional[str] = Field( None, description="Property ID for the thermodynamic data of the " "oxidized molecule", ) reduction_potential: Optional[float] = Field( None, description="Reduction potential referenced to the standard hydrogen electrode (SHE) (units: V)", ) oxidation_potential: Optional[float] = Field( None, description="Oxidation potential referenced to the standard hydrogen electrode (SHE) (units: V)", ) @classmethod def _g_or_e(cls: Type[T], entry: Dict[str, Any]) -> float: """ Single atoms may not have free energies like more complex molecules do. This function returns the free energy of a TaskDocument entry if possible, and otherwise returns the electronic energy. :param entry: dict representation of a TaskDocument :return: """ try: result = get_free_energy( entry["output"]["final_energy"], entry["output"]["enthalpy"], entry["output"]["entropy"], ) # Single atoms won't have enthalpy and entropy except TypeError: result = entry["output"]["final_energy"] return result @classmethod def from_docs( cls: Type[T], base_molecule_doc: MoleculeDoc, base_thermo_doc: MoleculeThermoDoc, red_doc: Optional[MoleculeThermoDoc] = None, ox_doc: Optional[MoleculeThermoDoc] = None, ea_doc: Optional[TaskDocument] = None, ie_doc: Optional[TaskDocument] = None, deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Construct a document describing molecular redox properties from MoleculeThermoDocs (for adiabatic redox potentials and thermodynamics) and TaskDocs (for vertical ionization energies and electron affinities) :param base_molecule_doc: MoleculeDoc of interest :param base_thermo_doc: MoleculeThermoDoc for the molecule of interest. All properties will be calculated in reference to this document :param red_doc: MoleculeThermoDoc for the reduced molecule. This molecule will have the same (covalent) bonding as base_thermo_doc but will differ in charge by -1 :param ox_doc: MoleculeThermoDoc for the oxidized molecule. This molecule will have the same (covalent) bonding as the base_thermo_doc but will differ in charge by +1 :param ea_doc: A TaskDocument performed at the same structure as base_thermo_doc, but at a charge that differs by -1. This document will be used to calculate the electron affinity of the molecule :param ie_doc: A TaskDocument performed at the same structure as base_thermo_doc, but at a charge that differs by +1. This document will be used to calculate the ionization energy of the molecule :param kwargs: To be passed to PropertyDoc :return: """ if all([x is None for x in [red_doc, ox_doc, ea_doc, ie_doc]]): # No redox properties can be extracted return None base_has_g = base_thermo_doc.free_energy is not None base_property_id = base_thermo_doc.property_id red_molecule_id = None red_property_id = None reduction_energy = None reduction_free_energy = None reduction_potential = None ox_molecule_id = None ox_property_id = None oxidation_energy = None oxidation_free_energy = None oxidation_potential = None ea_task_id = None electron_affinity = None ie_task_id = None ionization_energy = None id_string = ( f"redox-{base_molecule_doc.molecule_id}-{base_thermo_doc.lot_solvent}-" f"{base_thermo_doc.property_id}" ) origins = list() # Adiabatic reduction properties if red_doc is not None: red_molecule_id = red_doc.molecule_id red_property_id = red_doc.property_id id_string += f"-{red_doc.property_id}" reduction_energy = ( red_doc.electronic_energy - base_thermo_doc.electronic_energy ) if base_has_g and red_doc.free_energy is not None: reduction_free_energy = ( red_doc.free_energy - base_thermo_doc.free_energy ) else: reduction_free_energy = None red = reduction_free_energy or reduction_energy reduction_potential = -1 * red - reference_potential # Adiabatic oxidation properties if ox_doc is not None: ox_molecule_id = ox_doc.molecule_id ox_property_id = ox_doc.property_id id_string += f"-{ox_doc.property_id}" oxidation_energy = ( ox_doc.electronic_energy - base_thermo_doc.electronic_energy ) if base_has_g and ox_doc.free_energy is not None: oxidation_free_energy = ox_doc.free_energy - base_thermo_doc.free_energy else: oxidation_free_energy = None ox = oxidation_free_energy or oxidation_energy oxidation_potential = ox - reference_potential # Electron affinity if ea_doc is not None: ea_task_id = ea_doc.task_id id_string += f"-{ea_task_id}" origins.append(PropertyOrigin(name="electron_affinity", task_id=ea_task_id)) electron_affinity = ( ea_doc.output.final_energy * 27.2114 - base_thermo_doc.electronic_energy ) # Ionization energy if ie_doc is not None: ie_task_id = ie_doc.task_id id_string += f"-{ie_task_id}" origins.append(PropertyOrigin(name="ionization_energy", task_id=ie_task_id)) ionization_energy = ( ie_doc.output.final_energy * 27.2114 - base_thermo_doc.electronic_energy ) h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() return super().from_molecule( meta_molecule=base_molecule_doc.molecule, property_id=property_id, molecule_id=base_molecule_doc.molecule_id, base_property_id=base_property_id, level_of_theory=base_thermo_doc.level_of_theory, solvent=base_thermo_doc.solvent, lot_solvent=base_thermo_doc.lot_solvent, red_molecule_id=red_molecule_id, red_property_id=red_property_id, reduction_energy=reduction_energy, reduction_free_energy=reduction_free_energy, reduction_potential=reduction_potential, ox_molecule_id=ox_molecule_id, ox_property_id=ox_property_id, oxidation_energy=oxidation_energy, oxidation_free_energy=oxidation_free_energy, oxidation_potential=oxidation_potential, ea_task_id=ea_task_id, electron_affinity=electron_affinity, ie_task_id=ie_task_id, ionization_energy=ionization_energy, deprecated=deprecated, origins=origins, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/summary.py0000644000175100001770000005716314673360562021375 0ustar00runnerdockerfrom enum import Enum from typing import Any, Dict, List, Optional, Tuple, TypeVar from hashlib import blake2b from pydantic import Field from pymatgen.core.structure import Molecule from pymatgen.analysis.graphs import MoleculeGraph from emmet.core.qchem.calc_types import CalcType, LevelOfTheory, TaskType from emmet.core.molecules.molecule_property import PropertyDoc from emmet.core.mpid import MPID, MPculeID from emmet.core.molecules.orbitals import NaturalPopulation, LonePair, Bond, Interaction from emmet.core.molecules.metal_binding import MetalBindingData __author__ = "Evan Spotte-Smith " T = TypeVar("T", bound="MoleculeSummaryDoc") class HasProps(Enum): """ Enum of possible hasprops values. """ molecules = "molecules" bonding = "bonding" metal_binding = "metal_binding" orbitals = "orbitals" partial_charges = "partial_charges" partial_spins = "partial_spins" redox = "redox" thermo = "thermo" vibration = "vibration" class MoleculeSummaryDoc(PropertyDoc): """ Summary information about molecules and their properties, useful for searching. """ property_name: str = "summary" # molecules molecules: Dict[str, Molecule] = Field( ..., description="The lowest energy optimized structures for this molecule for each solvent.", ) molecule_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Level of theory used to optimize the best molecular structure for each solvent.", ) species_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom species as the graph " "node attribute.", ) coord_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom coordinates as the graph " "node attribute.", ) inchi: Optional[str] = Field( None, description="International Chemical Identifier (InChI) for this molecule" ) inchi_key: Optional[str] = Field( None, description="Standardized hash of the InChI for this molecule" ) task_ids: List[MPID] = Field( [], title="Calculation IDs", description="List of Calculation IDs associated with this molecule.", ) similar_molecules: List[MPculeID] = Field( [], description="IDs associated with similar molecules" ) constituent_molecules: List[MPculeID] = Field( [], description="IDs of associated MoleculeDocs used to construct this molecule.", ) unique_calc_types: Optional[List[CalcType]] = Field( None, description="Collection of all unique calculation types used for this molecule", ) unique_task_types: Optional[List[TaskType]] = Field( None, description="Collection of all unique task types used for this molecule", ) unique_levels_of_theory: Optional[List[LevelOfTheory]] = Field( None, description="Collection of all unique levels of theory used for this molecule", ) unique_solvents: Optional[List[str]] = Field( None, description="Collection of all unique solvents (solvent parameters) used for this molecule", ) unique_lot_solvents: Optional[List[str]] = Field( None, description="Collection of all unique combinations of level of theory and solvent used for this molecule", ) # thermo thermo_property_ids: Optional[Dict[str, str]] = Field( None, description="Solvent:property ID map for each MoleculeThermoDoc for this molecule.", ) thermo_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Solvent:level of theory map for each MoleculeThermoDoc for this molecule.", ) electronic_energy: Optional[Dict[str, float]] = Field( None, description="Electronic energy of the molecule (units: eV)" ) zero_point_energy: Optional[Dict[str, Optional[float]]] = Field( None, description="Zero-point energy of the molecule (units: eV)" ) rt: Optional[Dict[str, Optional[float]]] = Field( None, description="R*T, where R is the gas constant and T is temperature, taken " "to be 298.15K (units: eV)", ) total_enthalpy: Optional[Dict[str, Optional[float]]] = Field( None, description="Total enthalpy of the molecule at 298.15K (units: eV)" ) total_entropy: Optional[Dict[str, Optional[float]]] = Field( None, description="Total entropy of the molecule at 298.15K (units: eV/K)" ) translational_enthalpy: Optional[Dict[str, Optional[float]]] = Field( None, description="Translational enthalpy of the molecule at 298.15K (units: eV)", ) translational_entropy: Optional[Dict[str, Optional[float]]] = Field( None, description="Translational entropy of the molecule at 298.15K (units: eV/K)", ) rotational_enthalpy: Optional[Dict[str, Optional[float]]] = Field( None, description="Rotational enthalpy of the molecule at 298.15K (units: eV)" ) rotational_entropy: Optional[Dict[str, Optional[float]]] = Field( None, description="Rotational entropy of the molecule at 298.15K (units: eV/K)" ) vibrational_enthalpy: Optional[Dict[str, Optional[float]]] = Field( None, description="Vibrational enthalpy of the molecule at 298.15K (units: eV)" ) vibrational_entropy: Optional[Dict[str, Optional[float]]] = Field( None, description="Vibrational entropy of the molecule at 298.15K (units: eV/K)" ) free_energy: Optional[Dict[str, Optional[float]]] = Field( None, description="Gibbs free energy of the molecule at 298.15K (units: eV)" ) # vibrational properties vibration_property_ids: Optional[Dict[str, str]] = Field( None, description="Solvent:property ID map for each VibrationDoc for this molecule.", ) vibration_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Solvent:level of theory map for each VibrationDoc for this molecule.", ) frequencies: Optional[Dict[str, List[float]]] = Field( None, description="List of molecular vibrational frequencies" ) frequency_modes: Optional[Dict[str, List[List[List[float]]]]] = Field( None, description="Vibrational frequency modes of the molecule (units: Angstrom)", ) ir_intensities: Optional[Dict[str, List[float]]] = Field( None, title="IR intensities", description="Intensities for infrared vibrational spectrum peaks", ) ir_activities: Optional[Dict[str, List]] = Field( None, title="IR activities", description="List indicating if frequency-modes are IR-active", ) # natural bonding orbitals orbitals_property_ids: Optional[Dict[str, str]] = Field( None, description="Solvent:property ID map for each OrbitalDoc for this molecule.", ) orbitals_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Solvent:level of theory map for each OrbitalDoc for this molecule.", ) open_shell: Optional[Dict[str, bool]] = Field( None, description="Is this molecule open-shell (spin multiplicity != 1)?" ) nbo_population: Optional[Dict[str, Optional[List[NaturalPopulation]]]] = Field( None, description="Natural electron populations of the molecule" ) nbo_lone_pairs: Optional[Dict[str, Optional[List[LonePair]]]] = Field( None, description="Lone pair orbitals of a closed-shell molecule" ) nbo_bonds: Optional[Dict[str, Optional[List[Bond]]]] = Field( None, description="Bond-like orbitals of a closed-shell molecule" ) nbo_interactions: Optional[Dict[str, Optional[List[Interaction]]]] = Field( None, description="Orbital-orbital interactions of a closed-shell molecule" ) alpha_population: Optional[Dict[str, Optional[List[NaturalPopulation]]]] = Field( None, description="Natural electron populations of the alpha electrons of an " "open-shell molecule", ) beta_population: Optional[Dict[str, Optional[List[NaturalPopulation]]]] = Field( None, description="Natural electron populations of the beta electrons of an " "open-shell molecule", ) alpha_lone_pairs: Optional[Dict[str, Optional[List[LonePair]]]] = Field( None, description="Alpha electron lone pair orbitals of an open-shell molecule" ) beta_lone_pairs: Optional[Dict[str, Optional[List[LonePair]]]] = Field( None, description="Beta electron lone pair orbitals of an open-shell molecule" ) alpha_bonds: Optional[Dict[str, Optional[List[Bond]]]] = Field( None, description="Alpha electron bond-like orbitals of an open-shell molecule" ) beta_bonds: Optional[Dict[str, Optional[List[Bond]]]] = Field( None, description="Beta electron bond-like orbitals of an open-shell molecule" ) alpha_interactions: Optional[Dict[str, Optional[List[Interaction]]]] = Field( None, description="Alpha electron orbital-orbital interactions of an open-shell molecule", ) beta_interactions: Optional[Dict[str, Optional[List[Interaction]]]] = Field( None, description="Beta electron orbital-orbital interactions of an open-shell molecule", ) # partial charges partial_charges_property_ids: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:property ID map for each PartialChargesDoc for this molecule.", ) partial_charges_levels_of_theory: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:level of theory map for each PartialChargesDoc for this molecule.", ) partial_charges: Optional[Dict[str, Dict[str, List[float]]]] = Field( None, description="Atomic partial charges for the molecule using different partitioning schemes " "(Mulliken, Restrained Electrostatic Potential, Natural Bonding Orbitals, etc.)", ) # partial spins partial_spins_property_ids: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:property ID map for each PartialSpinsDoc for this molecule.", ) partial_spins_levels_of_theory: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:level of theory map for each PartialSpinsDoc for this molecule.", ) partial_spins: Optional[Dict[str, Dict[str, List[float]]]] = Field( None, description="Atomic partial spins for the molecule using different partitioning schemes " "(Mulliken, Natural Bonding Orbitals, etc.)", ) # bonding bonding_property_ids: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:property ID map for each MoleculeBondingDoc for this molecule.", ) bonding_levels_of_theory: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Solvent:method:level of theory map for each MoleculeBondingDoc for this molecule.", ) molecule_graph: Optional[Dict[str, Dict[str, MoleculeGraph]]] = Field( None, description="Molecular graph representations of the molecule using different " "definitions of bonding.", ) bond_types: Optional[Dict[str, Dict[str, Dict[str, List[float]]]]] = Field( None, description="Dictionaries of bond types to their length under different " "definitions of bonding, e.g. C-O to a list of the lengths of " "C-O bonds in Angstrom.", ) bonds: Optional[Dict[str, Dict[str, List[Tuple[int, int]]]]] = Field( None, description="List of bonds under different definitions of bonding. Each bond takes " "the form (a, b), where a and b are 0-indexed atom indices", ) bonds_nometal: Optional[Dict[str, Dict[str, List[Tuple[int, int]]]]] = Field( None, description="List of bonds under different definitions of bonding with all metal ions " "removed. Each bond takes the form in the form (a, b), where a and b are " "0-indexed atom indices.", ) # redox properties redox_property_ids: Optional[Dict[str, str]] = Field( None, description="Solvent:property ID map for each RedoxDoc for this molecule." ) redox_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Solvent:level of theory map for each RedoxDoc for this molecule.", ) electron_affinity: Optional[Dict[str, float]] = Field( None, description="Vertical electron affinity in eV" ) ea_task_id: Optional[Dict[str, MPID]] = Field( None, description="Molecule ID for electron affinity" ) ionization_energy: Optional[Dict[str, float]] = Field( None, description="Vertical ionization energy in eV" ) ie_task_id: Optional[Dict[str, MPID]] = Field( None, description="Molecule ID for ionization energy" ) reduction_free_energy: Optional[Dict[str, float]] = Field( None, description="Adiabatic free energy of reduction" ) red_molecule_id: Optional[Dict[str, MPculeID]] = Field( None, description="Molecule ID for adiabatic reduction" ) oxidation_free_energy: Optional[Dict[str, float]] = Field( None, description="Adiabatic free energy of oxidation" ) ox_molecule_id: Optional[Dict[str, MPculeID]] = Field( None, description="Molecule ID for adiabatic oxidation" ) reduction_potential: Optional[Dict[str, float]] = Field( None, description="Reduction potential referenced to the standard hydrogen electrode (SHE) (units: V)", ) oxidation_potential: Optional[Dict[str, float]] = Field( None, description="Oxidation potential referenced to the standard hydrogen electrode (SHE) (units: V)", ) # metal binding properties binding_partial_charges_property_id: Optional[Dict[str, Dict[str, str]]] = Field( None, description="ID of PartialChargesDoc used to estimate metal charge", ) binding_partial_spins_property_id: Optional[Dict[str, Dict[str, str]]] = Field( None, description="ID of PartialSpinsDoc used to estimate metal spin", ) binding_partial_charges_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used to calculate atomic partial charges", ) binding_partial_spins_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used to calculate atomic partial spins", ) binding_charge_spin_method: Optional[Dict[str, Dict[str, str]]] = Field( None, description="The method used for partial charges and spins (must be the same).", ) binding_bonding_property_id: Optional[Dict[str, Dict[str, str]]] = Field( None, description="ID of MoleculeBondingDoc used to detect bonding in this molecule", ) binding_bonding_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used to determine the coordination environment " "of the metal atom or ion", ) binding_bonding_method: Optional[Dict[str, Dict[str, str]]] = Field( None, description="The method used for to define bonding." ) binding_thermo_property_id: Optional[Dict[str, Dict[str, str]]] = Field( None, description="ID of MoleculeThermoDoc used to obtain this molecule's thermochemistry", ) binding_thermo_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used for uncorrected thermochemistry", ) binding_thermo_correction_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used to correct the electronic energy", ) binding_thermo_combined_lot_solvent: Optional[Dict[str, Dict[str, str]]] = Field( None, description="Combination of level of theory and solvent used for molecular thermochemistry, combining " "both the frequency calculation and (potentially) the single-point energy correction.", ) binding_data: Optional[Dict[str, Dict[str, List[MetalBindingData]]]] = Field( None, description="Binding data for each metal atom or ion in the molecule" ) # has props has_props: Optional[List[HasProps]] = Field( None, description="List of properties that are available for a given material." ) @classmethod def from_docs(cls, molecule_id: MPculeID, docs: Dict[str, Any]): """Converts a bunch of property docs into a SummaryDoc""" doc = _copy_from_doc(docs) if len(doc["has_props"]) == 0: raise ValueError("Missing minimal properties!") id_string = f"summary-{molecule_id}" h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() doc["property_id"] = property_id doc["has_props"] = list(set(doc["has_props"])) return MoleculeSummaryDoc(molecule_id=molecule_id, **doc) # Key mapping summary_fields: Dict[str, list] = { HasProps.molecules.value: [ "charge", "spin_multiplicity", "natoms", "elements", "nelements", "composition", "formula_alphabetical", "chemsys", "symmetry", "molecules", "deprecated", "task_ids", "species_hash", "coord_hash", "inchi", "inchi_key", "unique_calc_types", "unique_task_types", "unique_levels_of_theory", "unique_solvents", "unique_lot_solvents", "similar_molecules", "constituent_molecules", "molecule_levels_of_theory", ], HasProps.thermo.value: [ "electronic_energy", "zero_point_energy", "rt", "total_enthalpy", "total_entropy", "translational_enthalpy", "translational_entropy", "rotational_enthalpy", "rotational_entropy", "vibrational_enthalpy", "vibrational_entropy", "free_energy", ], HasProps.vibration.value: [ "frequencies", "frequency_modes", "ir_intensities", "ir_activities", ], HasProps.orbitals.value: [ "open_shell", "nbo_population", "nbo_lone_pairs", "nbo_bonds", "nbo_interactions", "alpha_population", "beta_population", "alpha_lone_pairs", "beta_lone_pairs", "alpha_bonds", "beta_bonds", "alpha_interactions", "beta_interactions", ], HasProps.partial_charges.value: ["partial_charges"], HasProps.partial_spins.value: ["partial_spins"], HasProps.bonding.value: ["molecule_graph", "bond_types", "bonds", "bonds_nometal"], HasProps.redox.value: [ "electron_affinity", "ea_task_id", "ionization_energy", "ie_task_id", "reduction_free_energy", "red_molecule_id", "oxidation_free_energy", "ox_molecule_id", "reduction_potential", "oxidation_potential", ], HasProps.metal_binding.value: [ "binding_partial_charges_property_id", "binding_partial_spins_property_id", "binding_partial_charges_lot_solvent", "binding_partial_spins_lot_solvent", "binding_charge_spin_method", "binding_bonding_property_id", "binding_bonding_lot_solvent", "binding_bonding_method", "binding_thermo_property_id", "binding_thermo_lot_solvent", "binding_thermo_correction_lot_solvent", "binding_thermo_combined_lot_solvent", "binding_data", ], } def _copy_from_doc(doc: Dict[str, Any]): """Helper function to copy the list of keys over from amalgamated document""" # Doc format: # {property0: {...}, # property1: {solvent1: {...}, solvent2: {...}}, # property2: {solvent1: [{...}, {...}], solvent2: [{...}, {...}]} # } d: Dict[str, Any] = {"has_props": []} # Function to grab the keys and put them in the root doc for doc_key in summary_fields: sub_doc = doc.get(doc_key, None) if doc_key == "molecules": # Molecules is special because there should only ever be one # MoleculeDoc for a given molecule # There are not multiple MoleculeDocs for different solvents if sub_doc is None: break for copy_key in summary_fields[doc_key]: d[copy_key] = sub_doc[copy_key] else: # No information for this particular set of properties # Shouldn't happen, but can if sub_doc is None: continue sd, by_method = sub_doc if isinstance(sd, dict) and len(sd) > 0: d["has_props"].append(doc_key) for copy_key in summary_fields[doc_key]: d[copy_key] = dict() if by_method: for solvent, solv_entries in sd.items(): d[copy_key][solvent] = dict() for method, entry in solv_entries.items(): if entry.get(copy_key) is not None: d[copy_key][solvent][method] = entry[copy_key] if len(d[copy_key][solvent]) == 0: # If this key was not populated at all for this solvent, get rid of it del d[copy_key][solvent] else: for solvent, entry in sd.items(): if entry.get(copy_key) is not None: d[copy_key][solvent] = entry[copy_key] if len(d[copy_key]) == 0: # If this key was not populated at all, set it to None d[copy_key] = None # Populate property id and level of theory values d[doc_key + "_property_ids"] = dict() d[doc_key + "_levels_of_theory"] = dict() if by_method: for solvent, solv_entries in sd.items(): d[doc_key + "_property_ids"][solvent] = dict() d[doc_key + "_levels_of_theory"][solvent] = dict() for method, entry in solv_entries.items(): d[doc_key + "_property_ids"][solvent][method] = entry[ "property_id" ] d[doc_key + "_levels_of_theory"][solvent][method] = entry[ "level_of_theory" ] if len(d[doc_key + "_property_ids"][solvent]) == 0: del d[doc_key + "_property_ids"][solvent] if len(d[doc_key + "_levels_of_theory"][solvent]) == 0: del d[doc_key + "_levels_of_theory"][solvent] else: for solvent, entry in sd.items(): d[doc_key + "_property_ids"][solvent] = entry["property_id"] d[doc_key + "_levels_of_theory"][solvent] = entry[ "level_of_theory" ] if len(d[doc_key + "_property_ids"]) == 0: d[doc_key + "_property_ids"] = None if len(d[doc_key + "_levels_of_theory"]) == 0: d[doc_key + "_levels_of_theory"] = None return d ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/thermo.py0000644000175100001770000002335214673360562021167 0ustar00runnerdockerfrom pydantic import Field from hashlib import blake2b from typing import Optional from emmet.core.mpid import MPculeID from emmet.core.qchem.calc_types import LevelOfTheory from emmet.core.qchem.task import TaskDocument from emmet.core.material import PropertyOrigin from emmet.core.molecules.molecule_property import PropertyDoc __author__ = "Evan Spotte-Smith " def get_free_energy(energy, enthalpy, entropy, temperature=298.15, convert_energy=True): """ Helper function to calculate Gibbs free energy from electronic energy, enthalpy, and entropy :param energy: Electronic energy in Ha :param enthalpy: Enthalpy in kcal/mol :param entropy: Entropy in csal/mol-K :param temperature: Temperature in K. Default is 298.15, 25C returns: Free energy in eV """ if convert_energy: e = energy * 27.2114 else: e = energy return e + enthalpy * 0.043363 - temperature * entropy * 0.000043363 class MoleculeThermoDoc(PropertyDoc): property_name: str = "thermo" electronic_energy: float = Field( ..., description="Electronic energy of the molecule (units: eV)" ) correction: bool = Field( False, description="Was a single-point calculation at higher level of " "theory used to correct the electronic energy?", ) base_level_of_theory: Optional[LevelOfTheory] = Field( None, description="Level of theory used for uncorrected thermochemistry." ) base_solvent: Optional[str] = Field( None, description="String representation of the solvent " "environment used for uncorrected thermochemistry.", ) base_lot_solvent: Optional[str] = Field( None, description="String representation of the level of theory and solvent " "environment used for uncorrected thermochemistry.", ) correction_level_of_theory: Optional[LevelOfTheory] = Field( None, description="Level of theory used to correct the electronic energy." ) correction_solvent: Optional[str] = Field( None, description="String representation of the solvent " "environment used to correct the electronic energy.", ) correction_lot_solvent: Optional[str] = Field( None, description="String representation of the level of theory and solvent " "environment used to correct the electronic energy.", ) combined_lot_solvent: Optional[str] = Field( None, description="String representation of the level of theory and solvent " "environment used to generate this ThermoDoc, combining " "both the frequency calculation and (potentially) the " "single-point energy correction.", ) zero_point_energy: Optional[float] = Field( None, description="Zero-point energy of the molecule (units: eV)" ) rt: Optional[float] = Field( None, description="R*T, where R is the gas constant and T is temperature, taken " "to be 298.15K (units: eV)", ) total_enthalpy: Optional[float] = Field( None, description="Total enthalpy of the molecule at 298.15K (units: eV)" ) total_entropy: Optional[float] = Field( None, description="Total entropy of the molecule at 298.15K (units: eV/K)" ) translational_enthalpy: Optional[float] = Field( None, description="Translational enthalpy of the molecule at 298.15K (units: eV)", ) translational_entropy: Optional[float] = Field( None, description="Translational entropy of the molecule at 298.15K (units: eV/K)", ) rotational_enthalpy: Optional[float] = Field( None, description="Rotational enthalpy of the molecule at 298.15K (units: eV)" ) rotational_entropy: Optional[float] = Field( None, description="Rotational entropy of the molecule at 298.15K (units: eV/K)" ) vibrational_enthalpy: Optional[float] = Field( None, description="Vibrational enthalpy of the molecule at 298.15K (units: eV)" ) vibrational_entropy: Optional[float] = Field( None, description="Vibrational entropy of the molecule at 298.15K (units: eV/K)" ) free_energy: Optional[float] = Field( None, description="Gibbs free energy of the molecule at 298.15K (units: eV)" ) @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, correction_task: Optional[TaskDocument] = None, deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Construct a thermodynamics document from a task :param task: document from which thermodynamic properties can be extracted :param molecule_id: MPculeID :param deprecated: bool. Is this document deprecated? :param kwargs: to pass to PropertyDoc :return: """ if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule if correction_task is None: energy = task.output.final_energy correction = False correction_lot = None correction_solvent = None correction_lot_solvent = None level_of_theory = task.level_of_theory solvent = task.solvent lot_solvent = task.lot_solvent combined_lot_solvent = task.lot_solvent else: energy = correction_task.output.final_energy correction = True correction_lot = correction_task.level_of_theory correction_solvent = correction_task.solvent correction_lot_solvent = correction_task.lot_solvent combined_lot_solvent = f"{task.lot_solvent}//{correction_lot_solvent}" level_of_theory = correction_lot solvent = correction_solvent lot_solvent = combined_lot_solvent total_enthalpy = task.output.enthalpy total_entropy = task.output.entropy origins = [PropertyOrigin(name="thermo", task_id=task.task_id)] id_string = f"thermo-{molecule_id}-{task.task_id}-{task.lot_solvent}" if correction and correction_task is not None: origins.append( PropertyOrigin( name="thermo_energy_correction", task_id=correction_task.task_id ) ) id_string += f"-{correction_task.task_id}-{correction_task.lot_solvent}" h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() if total_enthalpy is not None and total_entropy is not None: free_energy = get_free_energy(energy, total_enthalpy, total_entropy) for calc in task.calcs_reversed: if all( [ calc.get(x) is not None for x in [ "ZPE", "trans_enthalpy", "rot_enthalpy", "vib_enthalpy", "gas_constant", "trans_entropy", "rot_entropy", "vib_entropy", ] ] ): return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=level_of_theory, solvent=solvent, lot_solvent=lot_solvent, correction=correction, base_level_of_theory=task.level_of_theory, base_solvent=task.solvent, base_lot_solvent=task.lot_solvent, correction_level_of_theory=correction_lot, correction_solvent=correction_solvent, correction_lot_solvent=correction_lot_solvent, combined_lot_solvent=combined_lot_solvent, electronic_energy=energy * 27.2114, zero_point_energy=calc["ZPE"] * 0.043363, rt=calc["gas_constant"] * 0.043363, total_enthalpy=total_enthalpy * 0.043363, translational_enthalpy=calc["trans_enthalpy"] * 0.043363, rotational_enthalpy=calc["rot_enthalpy"] * 0.043363, vibrational_enthalpy=calc["vib_enthalpy"] * 0.043363, total_entropy=total_entropy * 0.000043363, translational_entropy=calc["trans_entropy"] * 0.000043363, rotational_entropy=calc["rot_entropy"] * 0.000043363, vibrational_entropy=calc["vib_entropy"] * 0.000043363, free_energy=free_energy, deprecated=deprecated, origins=origins, **kwargs, ) # If all thermodynamic data is not available return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, correction=correction, correction_level_of_theory=correction_lot, correction_solvent=correction_solvent, correction_lot_solvent=correction_lot_solvent, combined_lot_solvent=combined_lot_solvent, electronic_energy=energy * 27.2114, deprecated=deprecated, origins=origins, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules/vibration.py0000644000175100001770000000736114673360562021670 0ustar00runnerdockerfrom typing import List from hashlib import blake2b from pydantic import Field from pymatgen.core.structure import Molecule from emmet.core.mpid import MPculeID from emmet.core.material import PropertyOrigin from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.molecule_property import PropertyDoc __author__ = "Evan Spotte-Smith " class VibrationDoc(PropertyDoc): property_name: str = "vibrations" molecule: Molecule = Field(..., description="Molecular structure") frequencies: List[float] = Field( ..., description="List of molecular vibrational frequencies" ) frequency_modes: List[List[List[float]]] = Field( ..., description="Vibrational frequency modes of the molecule" ) ir_intensities: List[float] = Field( ..., title="IR intensities", description="Intensities for IR vibrational spectrum peaks", ) ir_activities: List = Field( ..., title="IR activities", description="List indicating if frequency-modes are IR-active", ) @classmethod def from_task( cls, task: TaskDocument, molecule_id: MPculeID, deprecated: bool = False, **kwargs, ): # type: ignore[override] """ Construct a vibration document from a task document :param task: document from which vibrational properties can be extracted :param molecule_id: MPculeID :param deprecated: bool. Is this document deprecated? :param kwargs: to pass to PropertyDoc :return: """ if task.output.frequencies is None: raise Exception("No frequencies in task!") if task.output.optimized_molecule is not None: mol = task.output.optimized_molecule else: mol = task.output.initial_molecule frequencies = task.output.frequencies frequency_modes = None intensities = None active = None for calc in task.calcs_reversed: if ( calc.get("frequency_mode_vectors", None) is not None and frequency_modes is None ): frequency_modes = calc.get("frequency_mode_vectors") if calc.get("IR_intens", None) is not None and intensities is None: intensities = calc.get("IR_intens") if calc.get("IR_active", None) is not None and active is None: active = calc.get("IR_active") if all([x is not None for x in [frequency_modes, intensities, active]]): break if frequency_modes is None: raise Exception("No frequency modes in task!") elif intensities is None: raise Exception("No IR intensities in task!") elif active is None: raise Exception("No IR activities in task!") warnings = list() if frequencies[0] < 0.0: warnings.append("Imaginary frequencies") id_string = f"vibrations-{molecule_id}-{task.task_id}-{task.lot_solvent}" h = blake2b() h.update(id_string.encode("utf-8")) property_id = h.hexdigest() return super().from_molecule( meta_molecule=mol, property_id=property_id, molecule_id=molecule_id, level_of_theory=task.level_of_theory, solvent=task.solvent, lot_solvent=task.lot_solvent, molecule=mol, frequencies=frequencies, frequency_modes=frequency_modes, ir_intensities=intensities, ir_activities=active, warnings=warnings, origins=[PropertyOrigin(name="vibrations", task_id=task.task_id)], deprecated=deprecated, **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/molecules_jcesr.py0000644000175100001770000000321514673360562021053 0ustar00runnerdockerfrom typing import List, Optional from pydantic import BaseModel, Field from pymatgen.core.periodic_table import Element from pymatgen.core.structure import Molecule class MoleculesDoc(BaseModel): """ Molecules relevant to battery electrolytes. """ elements: Optional[List[Element]] = Field( None, description="List of elements in the molecule.", ) nelements: Optional[int] = Field( None, description="Number of elements in the molecule.", ) EA: Optional[float] = Field( None, description="Electron affinity of the molecule in eV.", ) IE: Optional[float] = Field( None, description="Ionization energy of the molecule in eV.", ) charge: Optional[int] = Field( None, description="Charge of the molecule in +e.", ) pointgroup: Optional[str] = Field( None, description="Point group of the molecule in Schoenflies notation.", ) smiles: Optional[str] = Field( None, description="The simplified molecular input line-entry system (SMILES) \ representation of the molecule.", ) task_id: Optional[str] = Field( None, description="Materials Project molecule ID. This takes the form mol-*****.", ) molecule: Optional[Molecule] = Field( None, description="Pymatgen molecule object.", ) formula_pretty: Optional[str] = Field( None, description="Chemical formula of the molecule.", ) svg: Optional[str] = Field( None, description="String representation of the SVG image of the molecule.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/mpcomplete.py0000644000175100001770000000146714673360562020051 0ustar00runnerdockerfrom pydantic import Field from pydantic.main import BaseModel from pymatgen.core.structure import Structure from enum import Enum from typing import Optional class MPCompleteDoc(BaseModel): """ Defines data for MPComplete structure submissions """ structure: Optional[Structure] = Field( None, description="Structure submitted by the user.", ) public_name: Optional[str] = Field( None, description="Public name of submitter.", ) public_email: Optional[str] = Field( None, description="Public email of submitter.", ) class MPCompleteDataStatus(Enum): """ Submission status for MPComplete data """ submitted = "SUBMITTED" pending = "PENDING" running = "RUNNING" error = "ERROR" complete = "COMPLETE" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/mpid.py0000644000175100001770000001737714673360562016644 0ustar00runnerdocker# %% import re from typing import Union, Any, Callable from pydantic_core import CoreSchema, core_schema from pydantic import GetJsonSchemaHandler from pydantic.json_schema import JsonSchemaValue # matches "mp-1234" or "1234" followed by and optional "-(Alphanumeric)" mpid_regex = re.compile(r"^([A-Za-z]*-)?(\d+)(-[A-Za-z0-9]+)*$") mpculeid_regex = re.compile( r"^([A-Za-z]+-)?([A-Fa-f0-9]+)-([A-Za-z0-9]+)-(m?[0-9]+)-([0-9]+)$" ) # matches capital letters and numbers of length 26 (ULID) # followed by and optional "-(Alphanumeric)" check_ulid = re.compile(r"^[A-Z0-9]{26}(-[A-Za-z0-9]+)*$") class MPID(str): """ A Materials Project type ID with a prefix and an integer This class enables seemlessly mixing MPIDs and regular integer IDs Prefixed IDs are considered less than non-prefixed IDs to enable proper mixing with the Materials Project Args: val: Either 1) a prefixed string e.g. "mp-1234" 2) an integer e.g. 1234 3) a number stored as a string e.g. '1234' 4) an MPID Numbers stored as strings are coerced to ints """ def __init__(self, val: Union["MPID", int, str]): if isinstance(val, MPID): self.parts = val.parts # type: ignore self.string = val.string # type: ignore elif isinstance(val, int) or (isinstance(val, str) and val.isnumeric()): self.parts = ("", int(val)) self.string = str(val) elif isinstance(val, str): if mpid_regex.fullmatch(val): parts = val.split("-") parts[1] = int(parts[1]) # type: ignore self.parts = tuple(parts) elif check_ulid.fullmatch(val): ulid = val.split("-")[0] self.parts = (ulid, 0) else: raise ValueError( "MPID string representation must follow the format prefix-number or start with a valid ULID." ) self.string = val else: raise ValueError( "Must provide an MPID, int, or string of the format prefix-number or start with a valid ULID." ) def __eq__(self, other: object): if isinstance(other, MPID): return self.string == other.string elif isinstance(other, (int, str)): return self.string == MPID(other).string def __str__(self): return self.string def __repr__(self): return f"MPID({self})" def __lt__(self, other: Union["MPID", int, str]): other_parts = MPID(other).parts if self.parts[0] != "" and other_parts[0] != "": # both have prefixes; normal comparison return self.parts < other_parts elif self.parts[0] != "": # other is a pure int, self is prefixed # Always sort MPIDs before pure integer IDs return True elif other_parts[0] != "": # self is pure int, other is prefixed return False else: # both are pure ints; normal comparison return self.parts[1] < other_parts[1] def __gt__(self, other: Union["MPID", int, str]): return not self.__lt__(other) def __hash__(self): return hash(self.string) @classmethod def __get_pydantic_core_schema__( cls, source: type[Any], handler: Callable[[Any], core_schema.CoreSchema] ) -> core_schema.CoreSchema: return core_schema.with_info_plain_validator_function(cls.validate) @classmethod def __get_pydantic_json_schema__( cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler ) -> JsonSchemaValue: return dict( pattern=r"^([A-Za-z]*-)?(\d+)(-[A-Za-z0-9]+)*$", examples=["mp-3534", "3453", "mp-834-Ag"], type="string", ) @classmethod def validate(cls, __input_value: Any, _: core_schema.ValidationInfo): if isinstance(__input_value, MPID): return __input_value elif isinstance(__input_value, str) and mpid_regex.fullmatch(__input_value): return MPID(__input_value) elif isinstance(__input_value, str) and check_ulid.fullmatch(__input_value): return MPID(__input_value) elif isinstance(__input_value, int): return MPID(__input_value) raise ValueError("Invalid MPID Format") # %% class MPculeID(str): """ A Materials Project Molecule ID with a prefix, hash, and two integer values representing the charge and spin of the molecule Unlike the MPID, you cannot compare raw hashes or raw integers to MPculeIDs Args: val: Either 1) an MPculeID 2) a prefixed string of format "prefix-hash-formula-charge-spin" 3) a non-prefixed string of format "hash-formula-charge-spin" Numbers stored as strings are coerced to ints """ def __init__(self, val: Union["MPculeID", str]): if isinstance(val, MPculeID): self.parts = val.parts # type: ignore self.string = val.string # type: ignore elif isinstance(val, str): parts = val.split("-") if len(parts) == 4: parts[1] = int(parts[2].replace("m", "-")) # type: ignore parts[2] = int(parts[3]) # type: ignore elif len(parts) == 5: parts[3] = int(parts[3].replace("m", "-")) # type: ignore parts[4] = int(parts[4]) # type: ignore else: raise ValueError( "MPculeID string representation must follow the " "format prefix-hash-formula-charge-spin or hash-formula-charge-spin." ) self.parts = tuple(parts) self.string = val else: raise ValueError( "Must provide an MPculeID, or string of the format prefix-hash-formula-charge-spin " "or hash-formula-charge-spin" ) def __eq__(self, other: object): if isinstance(other, MPculeID): return self.string == other.string elif isinstance(other, str): return self.string == MPculeID(other).string def __str__(self): return self.string def __repr__(self): return f"MPculeID({self})" def __lt__(self, other: Union["MPculeID", str]): other_parts = MPculeID(other).parts return "-".join([str(x) for x in self.parts[-4:]]) < "-".join( [str(x) for x in other_parts[-4:]] ) def __gt__(self, other: Union["MPculeID", str]): return not self.__lt__(other) def __hash__(self): return hash(self.string) @classmethod def __get_pydantic_core_schema__( cls, source: type[Any], handler: Callable[[Any], core_schema.CoreSchema] ) -> core_schema.CoreSchema: return core_schema.with_info_plain_validator_function(cls.validate) @classmethod def __get_pydantic_json_schema__( cls, core_schema: CoreSchema, handler: GetJsonSchemaHandler ) -> JsonSchemaValue: return dict( pattern=r"^^([A-Za-z]+-)?([A-Fa-f0-9]+)-([A-Za-z0-9]+)-(m?[0-9]+)-([0-9]+)$", examples=[ "1a525231bdac3f13e2fac0962fe8d053-Mg1-0-1", "22b40b99719ac570fc7e6225e855ec6e-F5Li1P1-m1-2", "mpcule-b9ba54febc77d2a9177accf4605767db-C1H41-2", ], type="string", ) @classmethod def validate(cls, __input_value: Any, _: core_schema.ValidationInfo): if isinstance(__input_value, MPculeID): return __input_value elif isinstance(__input_value, str) and mpculeid_regex.fullmatch(__input_value): return MPculeID(__input_value) raise ValueError("Invalid MPculeID Format") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0482903 emmet-core-0.84.2/emmet/core/openff/0000755000175100001770000000000014673360566016603 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openff/__init__.py0000644000175100001770000000015314673360562020707 0ustar00runnerdockerfrom emmet.core.openff.tasks import ( MoleculeSpec, ClassicalMDTaskDocument, MDTaskDocument, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openff/benchmarking.py0000644000175100001770000000612114673360562021601 0ustar00runnerdockerfrom pydantic import BaseModel, Field from typing import Optional from MDAnalysis import Universe from MDAnalysis.analysis.dielectric import DielectricConstant from transport_analysis.viscosity import ViscosityHelfand class SolventBenchmarkingDoc(BaseModel, arbitrary_types_allowed=True): density: Optional[float] = Field(None, description="Density of the solvent") viscosity_function_values: Optional[list[float]] = Field( None, description="Viscosity function over time" ) viscosity: Optional[float] = Field(None, description="Viscosity of the solvent") dielectric: Optional[float] = Field( None, description="Dielectric constant of the solvent" ) job_uuid: Optional[str] = Field( None, description="The UUID of the flow that generated this data." ) flow_uuid: Optional[str] = Field( None, description="The UUID of the top level host from that job." ) dielectric_run_kwargs: Optional[dict] = Field( None, description="kwargs passed to the DielectricConstant.run method" ) viscosity_run_kwargs: Optional[dict] = Field( None, description="kwargs passed to the ViscosityHelfand.run method" ) tags: Optional[list[str]] = Field( [], title="tag", description="Metadata tagged to the parent job." ) @classmethod def from_universe( cls, u: Universe, temperature: Optional[float] = None, density: Optional[float] = None, job_uuid: Optional[str] = None, flow_uuid: Optional[str] = None, dielectric_run_kwargs: Optional[dict] = None, viscosity_run_kwargs: Optional[dict] = None, tags: Optional[list[str]] = None, ) -> "SolventBenchmarkingDoc": if temperature is not None: dielectric = DielectricConstant( u.atoms, temperature=temperature, make_whole=False ) dielectric_run_kwargs = dielectric_run_kwargs or {} dielectric.run(**dielectric_run_kwargs) eps = dielectric.results.eps_mean else: eps = None if u.atoms.ts.has_velocities: start, stop = int(0.2 * len(u.trajectory)), int(0.8 * len(u.trajectory)) viscosity_helfand = ViscosityHelfand( u.atoms, temp_avg=temperature, linear_fit_window=(start, stop), ) viscosity_run_kwargs = viscosity_run_kwargs or {} viscosity_helfand.run(**viscosity_run_kwargs) viscosity_function_values = viscosity_helfand.results.timeseries.tolist() viscosity = viscosity_helfand.results.viscosity else: viscosity_function_values = None viscosity = None return cls( density=density, viscosity_function_values=viscosity_function_values, viscosity=viscosity, dielectric=eps, job_uuid=job_uuid, flow_uuid=flow_uuid, dielectric_run_kwargs=dielectric_run_kwargs, viscosity_run_kwargs=viscosity_run_kwargs, tags=tags, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openff/solvation.py0000644000175100001770000001632114673360562021172 0ustar00runnerdockerfrom typing import Optional, Any from typing_extensions import Annotated import pandas as pd from solvation_analysis.solute import Solute from pydantic import Field, BaseModel, PlainValidator, PlainSerializer, WithJsonSchema from io import StringIO def data_frame_validater(o: Any) -> pd.DataFrame: if isinstance(o, pd.DataFrame): return o elif isinstance(o, str): return pd.read_csv(StringIO(o)) raise ValueError(f"Invalid DataFrame: {o}") def data_frame_serializer(df: pd.DataFrame) -> str: return df.to_csv() DataFrame = Annotated[ pd.DataFrame, PlainValidator(data_frame_validater), PlainSerializer(data_frame_serializer), WithJsonSchema({"type": "string"}), ] # class SolvationDoc(ClassicalMDDoc, arbitrary_types_allowed=True): class SolvationDoc(BaseModel, arbitrary_types_allowed=True): solute_name: Optional[str] = Field(None, description="Name of the solute") solvent_names: Optional[list[str]] = Field( None, description="Names of the solvents" ) is_electrolyte: Optional[bool] = Field( None, description="Whether system is an electrolyte" ) # Solute.coordination coordination_numbers: Optional[dict[str, float]] = Field( None, description="A dictionary where keys are residue names and values are " "the mean coordination number of that residue.", ) # coordination_numbers_by_frame: Optional[DataFrame] = Field( # None, # description="Coordination number in each frame of the trajectory.", # ) coordinating_atoms: Optional[DataFrame] = Field( None, description="Fraction of each atom_type participating in solvation, " "calculated for each solvent.", ) coordination_vs_random: Optional[dict[str, float]] = Field( None, description="Coordination number relative to random coordination.", ) # Solute.networking # TODO: In the worst case, this could be extremely large. # Need to consider what else we might want from this object. # network_df: Optional[DataFrame] = Field( # None, # description="All solute-solvent networks in the system, indexed by the `frame` " # "and a 'network_ix'. Columns are the species name and res_ix.", # ) network_sizes: Optional[DataFrame] = Field( None, description="Sizes of all networks, indexed by frame. Column headers are " "network sizes, e.g. the integer number of solutes + solvents in the network." "The values in each column are the number of networks with that size in each " "frame.", ) solute_status: Optional[dict[str, float]] = Field( None, description="A dictionary where the keys are the “status” of the " "solute and the values are the fraction of solute with that " "status, averaged over all frames. “isolated” means that the solute not " "coordinated with any of the networking solvents, network size is 1. " "“paired” means the solute and is coordinated with a single networking " "solvent and that solvent is not coordinated to any other solutes, " "network size is 2. “networked” means that the solute is coordinated to " "more than one solvent or its solvent is coordinated to more than one " "solute, network size >= 3.", ) # solute_status_by_frame: Optional[DataFrame] = Field( # None, description="Solute status in each frame of the trajectory." # ) # Solute.pairing solvent_pairing: Optional[dict[str, float]] = Field( None, description="Fraction of each solvent coordinated to the solute." ) # pairing_by_frame: Optional[DataFrame] = Field( # None, description="Solvent pairing in each frame." # ) fraction_free_solvents: Optional[dict[str, float]] = Field( None, description="Fraction of each solvent not coordinated to solute." ) diluent_composition: Optional[dict[str, float]] = Field( None, description="Fraction of diluent constituted by each solvent." ) # diluent_composition_by_frame: Optional[DataFrame] = Field( # None, description="Diluent composition in each frame." # ) diluent_counts: Optional[DataFrame] = Field( None, description="Solvent counts in each frame." ) # Solute.residence residence_times: Optional[dict[str, float]] = Field( None, description="Average residence time of each solvent." "Calculated by 1/e cutoff on autocovariance function.", ) residence_times_fit: Optional[dict[str, float]] = Field( None, description="Average residence time of each solvent." "Calculated by fitting the autocovariance function to an exponential decay.", ) # Solute.speciation speciation_fraction: Optional[DataFrame] = Field( None, description="Fraction of shells of each type." ) solvent_co_occurrence: Optional[DataFrame] = Field( None, description="The actual co-occurrence of solvents divided by " "the expected co-occurrence in randomly distributed solvation shells." "i.e. given a molecule of solvent i in the shell, the probability of " "solvent j's presence relative to choosing a solvent at random " "from the pool of all coordinated solvents. ", ) job_uuid: Optional[str] = Field( None, description="The UUID of the flow that generated this data." ) flow_uuid: Optional[str] = Field( None, description="The UUID of the top level host from that job." ) @classmethod def from_solute( cls, solute: Solute, job_uuid: Optional[str] = None, flow_uuid: Optional[str] = None, ) -> "SolvationDoc": # as a dict props = { "solute_name": solute.solute_name, "solvent_names": list(solute.solvents.keys()), "is_electrolyte": True, "job_uuid": job_uuid, "flow_uuid": flow_uuid, } if hasattr(solute, "coordination"): props["coordination_numbers"] = solute.coordination.coordination_numbers props["coordinating_atoms"] = solute.coordination.coordinating_atoms props["coordination_vs_random"] = solute.coordination.coordination_vs_random if hasattr(solute, "pairing"): props["solvent_pairing"] = solute.pairing.solvent_pairing props["fraction_free_solvents"] = solute.pairing.fraction_free_solvents props["diluent_composition"] = solute.pairing.diluent_composition props["diluent_counts"] = solute.pairing.diluent_counts if hasattr(solute, "speciation"): props["speciation_fraction"] = solute.speciation.speciation_fraction props["solvent_co_occurrence"] = solute.speciation.solvent_co_occurrence if hasattr(solute, "networking"): props["network_sizes"] = solute.networking.network_sizes props["solute_status"] = solute.networking.solute_status if hasattr(solute, "residence"): props["residence_times"] = solute.residence.residence_times_cutoff props["residence_times_fit"] = solute.residence.residence_times_fit return SolvationDoc(**props) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openff/tasks.py0000644000175100001770000000654414673360562020307 0ustar00runnerdocker"""Schemas for classical MD package.""" from __future__ import annotations from dataclasses import dataclass from datetime import datetime from typing import Optional from typing_extensions import Annotated import zlib from pydantic import ( BaseModel, Field, PlainValidator, PlainSerializer, WithJsonSchema, ) from monty.json import MSONable from pymatgen.core import Structure from emmet.core.vasp.task_valid import TaskState # type: ignore[import-untyped] def compressed_str_validator(s: str) -> str: try: compressed_bytes = bytes.fromhex(s) decompressed_bytes = zlib.decompress(compressed_bytes) return decompressed_bytes.decode("utf-8") except: # noqa return s def compressed_str_serializer(s: str) -> str: decompressed_bytes = s.encode("utf-8") return zlib.compress(decompressed_bytes).hex() # this type will take a string and automatically compress and # decompress it when it is serialized and deserialized CompressedStr = Annotated[ str, PlainValidator(compressed_str_validator), PlainSerializer(compressed_str_serializer), WithJsonSchema({"type": "string"}), ] @dataclass class MoleculeSpec(MSONable): """A molecule schema to be output by OpenMMGenerators.""" name: str count: int charge_scaling: float charge_method: str openff_mol: str # a tk.Molecule object serialized with to_json class MDTaskDocument(BaseModel, extra="allow"): # type: ignore[call-arg] """Definition of the OpenMM task document.""" tags: Optional[list[str]] = Field( [], title="tag", description="Metadata tagged to a given task." ) dir_name: Optional[str] = Field(None, description="The directory for this MD task") state: Optional[TaskState] = Field(None, description="State of this calculation") job_uuids: Optional[list] = Field( None, description="The job_uuids for all contributing jobs, this will only" "have a value if the taskdoc is generated by a Flow.", ) calcs_reversed: Optional[list] = Field( None, title="Calcs reversed data", description="Detailed data for each MD calculation contributing to " "the task document.", ) interchange: Optional[CompressedStr] = Field( None, description="An interchange object serialized to json." ) mol_specs: Optional[list[MoleculeSpec]] = Field( None, description="Molecules within the system. Only makes sense " "for molecular systems.", ) structure: Optional[Structure] = Field( None, title="Structure", description="The final structure for the simulation. Saved only " "if specified by job.", ) force_field: Optional[str] = Field(None, description="The classical MD forcefield.") task_type: Optional[str] = Field(None, description="The type of calculation.") # task_label: Optional[str] = Field(None, description="A description of the task") # TODO: where does task_label get added last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this task document", ) class ClassicalMDTaskDocument(MDTaskDocument): """Definition of the OpenMM task document.""" mol_specs: Optional[list[MoleculeSpec]] = Field( None, description="Molecules within the system." ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0482903 emmet-core-0.84.2/emmet/core/openmm/0000755000175100001770000000000014673360566016621 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openmm/__init__.py0000644000175100001770000000022514673360562020725 0ustar00runnerdockerfrom emmet.core.openmm.tasks import ( Calculation, CalculationInput, CalculationOutput, OpenMMTaskDocument, OpenMMInterchange, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openmm/calculations.py0000644000175100001770000000501014673360562021644 0ustar00runnerdockerfrom typing import List, Optional, Union from datetime import datetime from pydantic import BaseModel, Field from emmet.core.openmm.tasks import Calculation class CalculationsDoc(BaseModel): """ A document for storing metadata from a list of OpenMM calculations. In each field, calculations are listed sequentially, in the order they were run. """ task_names: List[str] = Field(None, description="Names of tasks.") calc_types: List[str] = Field(None, description="Types of calculations.") elapsed_times: List[Union[float, None]] = Field( None, description="Elapsed time for calculations." ) steps: List[Union[float, None]] = Field( None, description="n_steps for calculations." ) step_sizes: List[Union[float, None]] = Field( None, description="Step sizes for each calculations." ) temperatures: List[Union[float, None]] = Field( None, description="Temperature for each calculations." ) pressures: List[Union[float, None]] = Field( None, description="Pressure for each calculations." ) friction_coefficients: List[Union[float, None]] = Field( None, description="Friction coefficients for each calculations.", ) completed_at: Optional[datetime] = Field( None, description="Timestamp for when the final calculation completed.", ) job_uuid: Optional[str] = Field( None, description="The UUID of the flow that generated this data." ) flow_uuid: Optional[str] = Field( None, description="The UUID of the top level host from that job." ) @classmethod def from_calcs_reversed( cls, calcs_reversed: List[Calculation], job_uuid: Optional[str] = None, flow_uuid: Optional[str] = None, ) -> "CalculationsDoc": calcs = calcs_reversed[::-1] return CalculationsDoc( task_names=[calc.task_name for calc in calcs], calc_types=[calc.calc_type for calc in calcs], elapsed_times=[calc.output.elapsed_time for calc in calcs], steps=[calc.input.n_steps for calc in calcs], step_sizes=[calc.input.step_size for calc in calcs], temperatures=[calc.input.temperature for calc in calcs], pressures=[calc.input.pressure for calc in calcs], friction_coefficients=[calc.input.friction_coefficient for calc in calcs], completed_at=calcs[-1].completed_at, job_uuid=job_uuid, flow_uuid=flow_uuid, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/openmm/tasks.py0000644000175100001770000002136014673360562020316 0ustar00runnerdocker"""Schemas for OpenMM tasks.""" from __future__ import annotations import io from pathlib import Path from typing import Optional, Union import pandas as pd # type: ignore[import-untyped] import openmm from openmm import XmlSerializer from openmm.app import Simulation from openmm.app.pdbfile import PDBFile from emmet.core.vasp.task_valid import TaskState # type: ignore[import-untyped] from pydantic import BaseModel, Field from emmet.core.openff import MDTaskDocument # type: ignore[import-untyped] from emmet.core.openff.tasks import CompressedStr # type: ignore[import-untyped] class CalculationInput(BaseModel, extra="allow"): # type: ignore[call-arg] """OpenMM input settings for a job, these are the attributes of the OpenMMMaker.""" n_steps: Optional[int] = Field( None, description="The number of simulation steps to run." ) step_size: Optional[float] = Field( None, description="The size of each simulation step (picoseconds)." ) temperature: Optional[float] = Field( None, description="The simulation temperature (kelvin)." ) pressure: Optional[float] = Field( None, description="The simulation pressure (atmospheres)." ) friction_coefficient: Optional[float] = Field( None, description=( "The friction coefficient for the integrator (inverse picoseconds)." ), ) platform_name: Optional[str] = Field( None, description=( "The name of the OpenMM platform to use, passed to " "Interchange.to_openmm_simulation." ), ) platform_properties: Optional[dict] = Field( None, description=( "Properties for the OpenMM platform, passed to " "Interchange.to_openmm_simulation." ), ) state_interval: Optional[int] = Field( None, description=( "State is saved every `state_interval` timesteps. For no state, set to 0." ), ) state_file_name: Optional[str] = Field( None, description="The name of the state file to save." ) traj_interval: Optional[int] = Field( None, description=( "The trajectory is saved every `traj_interval` timesteps. For no trajectory, set to 0." ), ) wrap_traj: Optional[bool] = Field( None, description="Whether to wrap trajectory coordinates." ) report_velocities: Optional[bool] = Field( None, description="Whether to report velocities in the trajectory file." ) traj_file_name: Optional[str] = Field( None, description="The name of the trajectory file to save." ) traj_file_type: Optional[str] = Field( None, description="The type of trajectory file to save.", ) embed_traj: Optional[bool] = Field( None, description="Whether to embed the trajectory blob in CalculationOutput.", ) class CalculationOutput(BaseModel): """OpenMM calculation output files and extracted data.""" dir_name: Optional[str] = Field( None, description="The directory for this OpenMM task" ) traj_file: Optional[str] = Field( None, description="Path to the trajectory file relative to `dir_name`" ) traj_blob: Optional[CompressedStr] = Field( None, description="Trajectory file bytes blob hex encoded to a string" ) state_file: Optional[str] = Field( None, description="Path to the state file relative to `dir_name`" ) steps_reported: Optional[list[int]] = Field( None, description="Steps where outputs are reported" ) time: Optional[list[float]] = Field(None, description="List of times") potential_energy: Optional[list[float]] = Field( None, description="List of potential energies" ) kinetic_energy: Optional[list[float]] = Field( None, description="List of kinetic energies" ) total_energy: Optional[list[float]] = Field( None, description="List of total energies" ) temperature: Optional[list[float]] = Field(None, description="List of temperatures") volume: Optional[list[float]] = Field(None, description="List of volumes") density: Optional[list[float]] = Field(None, description="List of densities") elapsed_time: Optional[float] = Field( None, description="Elapsed time for the calculation (seconds)." ) @classmethod def from_directory( cls, dir_name: Union[Path, str], state_file_name: str, traj_file_name: str, elapsed_time: Optional[float] = None, embed_traj: bool = False, ) -> CalculationOutput: """Extract data from the output files in the directory.""" state_file = Path(dir_name) / state_file_name column_name_map = { '#"Step"': "steps_reported", "Potential Energy (kJ/mole)": "potential_energy", "Kinetic Energy (kJ/mole)": "kinetic_energy", "Total Energy (kJ/mole)": "total_energy", "Temperature (K)": "temperature", "Box Volume (nm^3)": "volume", "Density (g/mL)": "density", } state_is_not_empty = state_file.exists() and state_file.stat().st_size > 0 if state_is_not_empty: data = pd.read_csv(state_file, header=0) data = data.rename(columns=column_name_map) data = data.filter(items=column_name_map.values()) attributes = data.to_dict(orient="list") else: attributes = {name: None for name in column_name_map.values()} state_file_name = None # type: ignore[assignment] traj_file = Path(dir_name) / traj_file_name traj_is_not_empty = traj_file.exists() and traj_file.stat().st_size > 0 traj_file_name = traj_file_name if traj_is_not_empty else None # type: ignore if traj_is_not_empty: if embed_traj: with open(traj_file, "rb") as f: traj_blob = f.read().hex() else: traj_blob = None else: traj_blob = None return CalculationOutput( dir_name=str(dir_name), elapsed_time=elapsed_time, traj_file=traj_file_name, state_file=state_file_name, traj_blob=traj_blob, **attributes, ) class Calculation(BaseModel): """All input and output data for an OpenMM calculation.""" dir_name: Optional[str] = Field( None, description="The directory for this OpenMM calculation" ) has_openmm_completed: Optional[Union[TaskState, bool]] = Field( None, description="Whether OpenMM completed the calculation successfully" ) input: Optional[CalculationInput] = Field( None, description="OpenMM input settings for the calculation" ) output: Optional[CalculationOutput] = Field( None, description="The OpenMM calculation output" ) completed_at: Optional[str] = Field( None, description="Timestamp for when the calculation was completed" ) task_name: Optional[str] = Field( None, description="Name of task given by custodian (e.g., relax1, relax2)" ) calc_type: Optional[str] = Field( None, description="Return calculation type (run type + task_type). or just new thing", ) class OpenMMTaskDocument(MDTaskDocument): """Definition of the OpenMM task document.""" calcs_reversed: Optional[list[Calculation]] = Field( None, title="Calcs reversed data", description="Detailed data for each OpenMM calculation contributing to the " "task document.", ) class OpenMMInterchange(BaseModel): """An object to sit in the place of the Interchance object and serialize the OpenMM system, topology, and state.""" system: str = Field(None, description="An XML file representing the OpenMM system.") state: str = Field( None, description="An XML file representing the OpenMM state.", ) topology: str = Field( None, description="An XML file representing an OpenMM topology object." "This must correspond to the atom ordering in the system.", ) def to_openmm_simulation( self, integrator: openmm.Integrator, platform: openmm.Platform, platformProperties: Optional[dict[str, str]] = None, ): system = XmlSerializer.deserialize(self.system) state = XmlSerializer.deserialize(self.state) with io.StringIO(self.topology) as s: pdb = PDBFile(s) topology = pdb.getTopology() simulation = Simulation( topology, system, integrator, platform, platformProperties or {}, ) simulation.context.setState(state) return simulation ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/optimade.py0000644000175100001770000001110114673360562017470 0ustar00runnerdockerimport string from datetime import datetime from monty.fractions import gcd from optimade.models import Species, StructureResourceAttributes from pymatgen.core.composition import Composition, formula_double_format from pymatgen.core.structure import Structure from emmet.core.base import EmmetBaseModel from emmet.core.mpid import MPID letters = "ABCDEFGHIJKLMNOPQRSTUVXYZ" def optimade_form(comp: Composition): symbols = sorted([str(e) for e in comp.keys()]) numbers = set([comp[s] for s in symbols if comp[s]]) reduced_form = [] for s in symbols: reduced_form.append(s) if comp[s] != 1 and len(numbers) > 1: reduced_form.append(str(int(comp[s]))) return "".join(reduced_form) def optimade_anonymous_form(comp: Composition): reduced = comp.element_composition if all(x == int(x) for x in comp.values()): reduced /= gcd(*(int(i) for i in comp.values())) anon = [] for e, amt in zip(string.ascii_uppercase, sorted(reduced.values(), reverse=True)): if amt == 1: amt_str = "" elif abs(amt % 1) < 1e-8: amt_str = str(int(amt)) else: amt_str = str(amt) anon.append(str(e)) anon.append(amt_str) return "".join(anon) def hill_formula(comp: Composition) -> str: """ :return: Hill formula. The Hill system (or Hill notation) is a system of writing empirical chemical formulas, molecular chemical formulas and components of a condensed formula such that the number of carbon atoms in a molecule is indicated first, the number of hydrogen atoms next, and then the number of all other chemical elements subsequently, in alphabetical order of the chemical symbols. When the formula contains no carbon, all the elements, including hydrogen, are listed alphabetically. """ c = comp.element_composition elements = sorted([el.symbol for el in c.keys()]) form_elements = [] if "C" in elements: form_elements.append("C") if "H" in elements: form_elements.append("H") form_elements.extend([el for el in elements if el != "C" and el != "H"]) else: form_elements = elements formula = [ f"{el}{formula_double_format(c[el]) if c[el] != 1 else ''}" for el in form_elements ] return "".join(formula) class OptimadeMaterialsDoc(StructureResourceAttributes, EmmetBaseModel): """ Optimade Structure resource with a few extra MP specific fields for materials Thermo calculations are stored as a nested dict, with keys corresponding to the functional used to perform stability calc, i.e., R2SCAN, GGA_GGA+U_R2SCAN, or GGA_GGA+U """ material_id: MPID chemical_system: str stability: dict @classmethod def from_structure( cls, material_id: MPID, structure: Structure, last_updated_structure: datetime, thermo_calcs: dict, **kwargs, ) -> StructureResourceAttributes: structure.remove_oxidation_states() return OptimadeMaterialsDoc( material_id=material_id, chemical_system=structure.composition.chemical_system, stability=thermo_calcs, elements=sorted(set([e.symbol for e in structure.composition.elements])), nelements=len(structure.composition.elements), elements_ratios=list(structure.composition.fractional_composition.values()), chemical_formula_descriptive=optimade_form(structure.composition), chemical_formula_reduced=optimade_form( structure.composition.get_reduced_composition_and_factor()[0] ), chemical_formula_anonymous=optimade_anonymous_form(structure.composition), chemical_formula_hill=hill_formula(structure.composition), dimension_types=[1, 1, 1], nperiodic_dimensions=3, lattice_vectors=structure.lattice.matrix.tolist(), cartesian_site_positions=[site.coords.tolist() for site in structure], nsites=len(structure), species=list( { site.species_string: Species( chemical_symbols=[site.species_string], concentration=[1.0], name=site.species_string, ) for site in structure }.values() ), species_at_sites=[site.species_string for site in structure], last_modified=last_updated_structure, structure_features=[], **kwargs, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/oxidation_states.py0000644000175100001770000000777514673360562021275 0ustar00runnerdockerimport logging from collections import defaultdict from typing import Dict, List, Optional import numpy as np from pydantic import Field from pymatgen.analysis.bond_valence import BVAnalyzer from pymatgen.core import Structure from pymatgen.core.periodic_table import Specie from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID class OxidationStateDoc(PropertyDoc): """Oxidation states computed from the structure""" property_name: str = "oxidation" structure: Structure = Field( ..., description="The structure used in the generation of the oxidation state data.", ) possible_species: List[str] = Field( description="Possible charged species in this material." ) possible_valences: List[float] = Field( description="List of valences for each site in this material." ) average_oxidation_states: Dict[str, float] = Field( description="Average oxidation states for each unique species." ) method: Optional[str] = Field( None, description="Method used to compute oxidation states." ) @classmethod def from_structure(cls, structure: Structure, material_id: MPID, **kwargs): # type: ignore[override] # TODO: add check for if it already has oxidation states, if so pass this along unchanged ("method": "manual") structure.remove_oxidation_states() # Null document d = { "possible_species": [], "possible_valences": [], "average_oxidation_states": {}, } # type: dict try: bva = BVAnalyzer() valences = bva.get_valences(structure) possible_species = { str(Specie(structure[idx].specie, oxidation_state=valence)) for idx, valence in enumerate(valences) } structure.add_oxidation_state_by_site(valences) # construct a dict of average oxi_states for use # by MP2020 corrections. The format should mirror # the output of the first element from Composition.oxi_state_guesses() # e.g. {'Li': 1.0, 'O': -2.0} site_oxidation_list = defaultdict(list) for site in structure: site_oxidation_list[site.specie.element].append(site.specie.oxi_state) oxi_state_dict = { str(el): np.mean(oxi_states) for el, oxi_states in site_oxidation_list.items() # type: ignore } d = { "possible_species": list(possible_species), "possible_valences": valences, "average_oxidation_states": oxi_state_dict, "method": "Bond Valence Analysis", } except Exception as e: logging.error("BVAnalyzer failed with: {}".format(e)) try: first_oxi_state_guess = structure.composition.oxi_state_guesses( max_sites=-50 )[0] valences = [ first_oxi_state_guess[site.species_string] for site in structure ] possible_species = { str(Specie(el, oxidation_state=valence)) for el, valence in first_oxi_state_guess.items() } structure.add_oxidation_state_by_site(valences) d = { "possible_species": list(possible_species), "possible_valences": valences, "average_oxidation_states": first_oxi_state_guess, "method": "Oxidation State Guess", } except Exception as e: logging.error("Oxidation state guess failed with: {}".format(e)) d["warnings"] = ["Oxidation state guessing failed."] d["state"] = "unsuccessful" return super().from_structure( meta_structure=structure, material_id=material_id, structure=structure, **d, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/phonon.py0000644000175100001770000003116714673360562017205 0ustar00runnerdockerfrom datetime import datetime from pydantic import field_validator, BaseModel, Field from emmet.core.mpid import MPID from pymatgen.phonon.bandstructure import PhononBandStructureSymmLine from pymatgen.phonon.dos import PhononDos as PhononDosObject from typing import List, Tuple, Optional from emmet.core.utils import DocEnum from pymatgen.core import Structure from emmet.core.math import Vector3D, Tensor4R from emmet.core.polar import DielectricDoc, BornEffectiveCharges, IRDielectric from emmet.core.structure import StructureMetadata from emmet.core.common import convert_datetime from typing_extensions import Literal class PhononBSDOSDoc(BaseModel): """ Phonon band structures and density of states data. """ material_id: Optional[MPID] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ph_bs: Optional[PhononBandStructureSymmLine] = Field( None, description="Phonon band structure object.", ) ph_dos: Optional[PhononDosObject] = Field( None, description="Phonon density of states object.", ) last_updated: Optional[datetime] = Field( None, description="Timestamp for the most recent calculation for this Material document.", ) # Make sure that the datetime field is properly formatted @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) class PhononWarnings(DocEnum): ASR = "ASR break", "acoustic sum rule max breaking is larger than 30 cm^-1." CNSR = "CNSR break", "charge neutrality sum rule max breaking is larger than 0.2." NEG_FREQ = ( "has negative frequencies", "phonon band structure has negative " "frequencies anywhere in the Brillouin zone.", ) SMALL_Q_NEG_FREQ = ( "has small q negative frequencies", "the phonon band structure has negative frequencies," " but these are small and very close to the Gamma point " "(usually related to numerical errors).", ) class PhononBandStructure(BaseModel): """ Document with a pymatgen serialized phonon band structure. """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) doc_type: Literal["bs"] = Field( "bs", description="The type of the document: a phonon band structure." ) band_structure: Optional[dict] = Field( None, description="Serialized version of a pymatgen " "PhononBandStructureSymmLine object.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class PhononDos(BaseModel): """ Document with a pymatgen serialized phonon density of states (DOS). """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) doc_type: Literal["dos"] = Field( "dos", description="The type of the document: a phonon density of states." ) dos: Optional[dict] = Field( None, description="Serialized version of a pymatgen CompletePhononDos object." ) dos_method: Optional[str] = Field( None, description="The method used to calculate the phonon DOS." ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class PhononWebsiteBS(BaseModel): """ Document with a serialized version of the phonon band structure suitable for the phononwebsite (http://henriquemiranda.github.io/phononwebsite/). """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) doc_type: Literal["phononwebsite"] = Field( "phononwebsite", description="The type of the document: a phonon band structure for the phononwebsite.", ) phononwebsite: Optional[dict] = Field( None, description="Phononwebsite dictionary to plot the animated " "phonon modes.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class Ddb(BaseModel): """ Document with a the string version of the DDB file produced by abinit. """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) doc_type: Literal["ddb"] = Field( "ddb", description="The type of the document: a DDB file." ) ddb: Optional[str] = Field(None, description="The string of the DDB file.") last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class ThermodynamicProperties(BaseModel): """ Definition of the thermodynamic properties extracted from the phonon frequencies. """ temperatures: List[float] = Field( ..., description="The list of temperatures at which the thermodynamic properties " "are calculated", ) cv: List[float] = Field( ..., description="The values of the constant-volume specific heat.", alias="heat_capacity", ) entropy: List[float] = Field( ..., description="The values of the vibrational entropy." ) class VibrationalEnergy(BaseModel): """ Definition of the vibrational contribution to the energy as function of the temperature. """ temperatures: List[float] = Field( ..., description="The list of temperatures at which the thermodynamic properties " "are calculated", ) internal_energy: List[float] = Field( ..., description="The values of the phonon contribution to the internal energy." ) helmholtz_free_energy: List[float] = Field( ..., description="The values of the Helmholtz free energy." ) zero_point_energy: float = Field( ..., description="The value of the zero point energy." ) class Phonon(StructureMetadata): """ Definition for a document with data produced by a phonon calculation. """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) structure: Structure = Field( ..., description="The relaxed structure for the phonon calculation." ) asr_break: Optional[float] = Field( None, description="The maximum breaking of the acoustic sum rule (ASR)." ) warnings: Optional[List[PhononWarnings]] = Field( None, description="List of warnings associated to the phonon calculation." ) dielectric: Optional[DielectricDoc] = Field( None, description="Dielectric properties obtained during a phonon calculations." ) becs: Optional[BornEffectiveCharges] = Field( None, description="Born effective charges obtained for a phonon calculation." ) ir_spectra: Optional[IRDielectric] = Field( None, description="The IRDielectricTensor." ) thermodynamic: Optional[ThermodynamicProperties] = Field( None, description="The thermodynamic properties extracted from the phonon " "frequencies.", ) vibrational_energy: Optional[VibrationalEnergy] = Field( None, description="The vibrational contributions to the total energy." ) last_updated: datetime = Field( description="Timestamp for when this document was last updated", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class AbinitPhonon(Phonon): """ Definition for a document with data produced from a phonon calculation with Abinit. """ abinit_input_vars: Optional[dict] = Field( None, description="Dict representation of the inputs used to obtain the phonon" "properties and the main general options (e.g. number of " "k-points, number of q-points).", ) class SoundVelocity(BaseModel): """ Definition for a document with the sound velocities of the acoustic modes close to Gamma, as obtained from a phonon calculation. """ material_id: str = Field( ..., description="The ID of this material, in the form: mp-******", ) structure: Structure = Field( ..., description="The relaxed structure for the phonon calculation." ) directions: List[Vector3D] = Field( ..., description="Q-points identifying the directions for the calculation" "of the speed of sound. In fractional coordinates.", ) labels: List[Optional[str]] = Field(..., description="labels of the directions.") sound_velocities: List[Vector3D] = Field( ..., description="Values of the sound velocities in SI units.", ) mode_types: List[Tuple[Optional[str], Optional[str], Optional[str]]] = Field( ..., description="The types of the modes ('transversal', 'longitudinal'). " "None if not correctly identified.", ) last_updated: datetime = Field( description="Timestamp for when this document was last updated", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) class ThermalDisplacement(BaseModel): """ Definition of a Document for the generalized density of states and mean square displacements related to phonon oscillations. """ material_id: str = Field( ..., description="The ID of this material, used as a universal reference across property documents." "This comes in the form: mp-******", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) created_at: datetime = Field( description="Timestamp for when this material document was first created", default_factory=datetime.utcnow, ) nsites: int = Field( ..., description="The number of sites in the structure.", ) nomega: int = Field( ..., description="The number of frequencies.", ) ntemp: int = Field( ..., description="The number of temperatures for which the displacements are calculated", ) temperatures: List[float] = Field( ..., description="The list of temperatures at which the thermodynamic properties " "are calculated", ) frequencies: List[float] = Field( ..., description="The list of frequencies for the generalized DOS" ) gdos_aijw: Tensor4R = Field( ..., description=" Generalized DOS in Cartesian coords, with shape (nsites, 3, 3, nomega)", ) amu: dict = Field( ..., description="Dictionary of the atomic masses in atomic units." ) structure: Structure = Field( ..., description="The relaxed structure for the phonon calculation." ) ucif_t: Tensor4R = Field( ..., description="Mean squared displacement U tensors as a function of T for T in tmesh in CIF format." "With shape (natom, 3, 3, ntemp) ", ) ucif_string_t300k: str = Field( ..., description="Mean squared displacement U tensors at T=300K in CIF string format.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/polar.py0000644000175100001770000001267614673360562017025 0ustar00runnerdocker""" Core definition for Polar property Document """ from typing import List, Optional from emmet.core.mpid import MPID import numpy as np from pydantic import BaseModel, Field from pymatgen.analysis.piezo import PiezoTensor as BasePiezoTensor from emmet.core.settings import EmmetSettings from emmet.core.material_property import PropertyDoc from emmet.core.math import Matrix3D from pymatgen.core.structure import Structure from pymatgen.core.tensors import Tensor SETTINGS = EmmetSettings() Vector = List[float] PiezoTensor = List[Vector] PiezoTensor.__doc__ = "Rank 3 real space tensor in Voigt notation" # type: ignore class DielectricDoc(PropertyDoc): """ A dielectric property block """ property_name: str = "dielectric" total: Matrix3D = Field(description="Total dielectric tensor.") ionic: Matrix3D = Field(description="Ionic contribution to dielectric tensor.") electronic: Matrix3D = Field( description="Electronic contribution to dielectric tensor." ) e_total: float = Field(description="Total electric permittivity.") e_ionic: float = Field( description="Electric permittivity from atomic rearrangement." ) e_electronic: float = Field( description="Electric permittivity due to electrons rearrangement." ) n: float = Field(description="Refractive index.") @classmethod def from_ionic_and_electronic( cls, material_id: MPID, ionic: Matrix3D, electronic: Matrix3D, structure: Structure, **kwargs, ): ionic_tensor = Tensor(ionic).convert_to_ieee(structure) electronic_tensor = Tensor(electronic).convert_to_ieee(structure) total = ionic_tensor + electronic_tensor return super().from_structure( meta_structure=structure, material_id=material_id, **{ "total": total.tolist(), "ionic": ionic_tensor.tolist(), "electronic": electronic_tensor.tolist(), "e_total": np.average(np.diagonal(total)), "e_ionic": np.average(np.diagonal(ionic_tensor)), "e_electronic": np.average(np.diagonal(electronic_tensor)), "n": np.sqrt(np.average(np.diagonal(electronic_tensor))), }, **kwargs, ) class PiezoelectricDoc(PropertyDoc): """ A dielectric package block """ property_name: str = "piezoelectric" total: PiezoTensor = Field(description="Total piezoelectric tensor in C/m²") ionic: PiezoTensor = Field( description="Ionic contribution to piezoelectric tensor in C/m²" ) electronic: PiezoTensor = Field( description="Electronic contribution to piezoelectric tensor in C/m²" ) e_ij_max: float = Field(description="Piezoelectric modulus") max_direction: List[int] = Field( description="Miller direction for maximum piezo response" ) strain_for_max: List[float] = Field( description="Normalized strain direction for maximum piezo repsonse" ) @classmethod def from_ionic_and_electronic( cls, material_id: MPID, ionic: PiezoTensor, electronic: PiezoTensor, structure: Structure, **kwargs, ): ionic_tensor = BasePiezoTensor.from_vasp_voigt(ionic) electronic_tensor = BasePiezoTensor.from_vasp_voigt(electronic) total: BasePiezoTensor = ionic_tensor + electronic_tensor # type: ignore[assignment] # Symmeterize Convert to IEEE orientation total = total.convert_to_ieee(structure) ionic_tensor = ionic_tensor.convert_to_ieee(structure) electronic_tensor = electronic_tensor.convert_to_ieee(structure) directions, charges, strains = np.linalg.svd(total.voigt, full_matrices=False) max_index = np.argmax(np.abs(charges)) max_direction = directions[max_index] # Allow a max miller index of 10 min_val = np.abs(max_direction) min_val = min_val[min_val > (np.max(min_val) / SETTINGS.MAX_PIEZO_MILLER)] min_val = np.min(min_val) return super().from_structure( meta_structure=structure, material_id=material_id, **{ "total": total.zeroed().voigt.tolist(), "ionic": ionic_tensor.zeroed().voigt.tolist(), "electronic": electronic_tensor.zeroed().voigt.tolist(), "e_ij_max": charges[max_index], "max_direction": tuple(np.round(max_direction / min_val)), "strain_for_max": tuple(strains[max_index]), }, **kwargs, ) class BornEffectiveCharges(BaseModel): """ A block for the Born effective charges """ value: Optional[List[Matrix3D]] = Field( None, description="Value of the Born effective charges." ) symmetrized_value: Optional[List[Matrix3D]] = Field( None, description="Value of the Born effective charges after symmetrization to obey the" "charge neutrality sum rule.", ) cnsr_break: Optional[float] = Field( None, description="The maximum breaking of the charge neutrality sum " "rule (CNSR) in the Born effective charges.", ) class IRDielectric(BaseModel): """ A block for the pymatgen IRDielectricTensor object """ ir_dielectric_tensor: Optional[dict] = Field( None, description="Serialized version of a pymatgen IRDielectricTensor object." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/provenance.py0000644000175100001770000001511714673360562020041 0ustar00runnerdocker""" Core definition of a Provenance Document """ import warnings from datetime import datetime from typing import Dict, List, Optional from pybtex.database import BibliographyData, parse_string from pybtex.errors import set_strict_mode from pydantic import field_validator, model_validator, BaseModel, Field from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID from emmet.core.utils import ValueEnum from emmet.core.common import convert_datetime from pymatgen.core.structure import Structure class Database(ValueEnum): """ Database identifiers for provenance IDs """ ICSD = "icsd" Pauling_Files = "pf" COD = "cod" class Author(BaseModel): """ Author information """ name: Optional[str] = Field(None) email: Optional[str] = Field(None) class History(BaseModel): """ History of the material provenance """ name: str url: str description: Optional[Dict] = Field( None, description="Dictionary of extra data for this history node." ) @model_validator(mode="before") @classmethod def str_to_dict(cls, values): if isinstance(values.get("description"), str): values["description"] = {"string": values.get("description")} return values class SNLAbout(BaseModel): """A data dictionary defining extra fields in a SNL""" references: str = Field( "", description="Bibtex reference strings for this material." ) authors: List[Author] = Field([], description="List of authors for this material.") remarks: List[str] = Field( [], description="List of remarks for the provenance of this material." ) tags: List[str] = Field([]) database_IDs: Dict[Database, List[str]] = Field( dict(), description="Database IDs corresponding to this material." ) history: List[History] = Field( [], description="List of history nodes specifying the transformations or orignation" " of this material for the entry closest matching the material input.", ) created_at: datetime = Field( default_factory=datetime.utcnow, description="The creation date for this SNL." ) @field_validator("created_at", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) class SNLDict(BaseModel): """Pydantic validated dictionary for SNL""" about: SNLAbout snl_id: str = Field(..., description="The SNL ID for this entry") class ProvenanceDoc(PropertyDoc): """ A provenance property block """ property_name: str = "provenance" created_at: datetime = Field( ..., description="creation date for the first structure corresponding to this material", ) references: List[str] = Field( [], description="Bibtex reference strings for this material" ) authors: List[Author] = Field([], description="List of authors for this material") remarks: List[str] = Field( [], description="List of remarks for the provenance of this material" ) tags: List[str] = Field([]) theoretical: bool = Field( True, description="If this material has any experimental provenance or not" ) database_IDs: Dict[Database, List[str]] = Field( dict(), description="Database IDs corresponding to this material" ) history: List[History] = Field( [], description="List of history nodes specifying the transformations or orignation" " of this material for the entry closest matching the material input", ) @field_validator("created_at", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) @field_validator("authors") @classmethod def remove_duplicate_authors(cls, authors): authors_dict = {entry.name.lower(): entry for entry in authors} return list(authors_dict.values()) @classmethod def from_SNLs( cls, material_id: MPID, structure: Structure, snls: List[SNLDict], **kwargs ) -> "ProvenanceDoc": """ Converts legacy Pymatgen SNLs into a single provenance document """ assert ( len(snls) > 0 ), "Error must provide a non-zero list of SNLs to convert from SNLs" # Choose earliest created_at created_at = min([snl.about.created_at for snl in snls]) # last_updated = max([snl.about.created_at for snl in snls]) # Choose earliest history history = sorted(snls, key=lambda snl: snl.about.created_at)[0].about.history # Aggregate all references into one dict to remove duplicates refs = {} for snl in snls: try: set_strict_mode(False) entries = parse_string(snl.about.references, bib_format="bibtex") refs.update(entries.entries) except Exception as e: warnings.warn( f"Failed parsing bibtex: {snl.about.references} due to {e}" ) bib_data = BibliographyData(entries=refs) references = [ref.to_string("bibtex") for ref in bib_data.entries.values()] # TODO: Maybe we should combine this robocrystallographer? # TODO: Refine these tags / remarks remarks = list(set([remark for snl in snls for remark in snl.about.remarks])) tags = [r for r in remarks if len(r) < 140] authors = [entry for snl in snls for entry in snl.about.authors] # Check if this entry is experimental exp_vals = [] for snl in snls: for entry in snl.about.history: if entry.description is not None: exp_vals.append(entry.description.get("experimental", False)) experimental = any(exp_vals) # Aggregate all the database IDs snl_ids = {snl.snl_id for snl in snls} db_ids = { Database(db_id): [snl_id for snl_id in snl_ids if db_id in snl_id] for db_id in map(str, Database) # type: ignore } # remove Nones and empty lists db_ids = {k: list(filter(None, v)) for k, v in db_ids.items()} db_ids = {k: v for k, v in db_ids.items() if len(v) > 0} fields = { "created_at": created_at, "references": references, "authors": authors, "remarks": remarks, "tags": tags, "database_IDs": db_ids, "theoretical": not experimental, "history": history, } return super().from_structure( material_id=material_id, meta_structure=structure, **fields, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qc_tasks.py0000644000175100001770000005272314673360562017515 0ustar00runnerdocker# mypy: ignore-errors """ Core definition of a Q-Chem Task Document """ from typing import Any, Dict, List, Optional import logging import re from collections import OrderedDict from pydantic import BaseModel, Field from custodian.qchem.jobs import QCJob from pymatgen.core.structure import Molecule from pymatgen.io.qchem.inputs import QCInput from monty.serialization import loadfn from typing import Type, TypeVar, Union from emmet.core.structure import MoleculeMetadata from pathlib import Path from emmet.core.qchem.calc_types import ( LevelOfTheory, CalcType, TaskType, ) from emmet.core.qchem.calculation import Calculation, CalculationInput from emmet.core.qchem.task import QChemStatus __author__ = ( "Evan Spotte-Smith , Rishabh D. Guha " ) logger = logging.getLogger(__name__) _T = TypeVar("_T", bound="TaskDoc") # _DERIVATIVE_FILES = ("GRAD", "HESS") class OutputDoc(BaseModel): initial_molecule: Molecule = Field(None, description="Input Molecule object") optimized_molecule: Optional[Molecule] = Field( None, description="Optimized Molecule object" ) # TODO: Discuss with Evan if these go here # species_hash: str = Field( # None, # description="Weisfeiler Lehman (WL) graph hash using the atom species as the graph node attribute.", # ) # coord_hash: str = Field( # None, # description="Weisfeiler Lehman (WL) graph hash using the atom coordinates as the graph node attribute.", # ) # last_updated: datetime = Field( # None, # description = "Timestamp for the most recent calculation for this QChem task document", # ) final_energy: float = Field( None, description="Final electronic energy for the calculation (units: Hartree)" ) enthalpy: Optional[float] = Field( None, description="Total enthalpy of the molecule (units: kcal/mol)" ) entropy: Optional[float] = Field( None, description="Total entropy of the molecule (units: cal/mol-K" ) dipoles: Optional[Dict[str, Any]] = Field( None, description="Dipolar information from the output" ) mulliken: Optional[List[Any]] = Field( None, description="Mulliken atomic partial charges and partial spins" ) resp: Optional[Union[List[float], List[Any]]] = Field( None, description="Restrained Electrostatic Potential (RESP) atomic partial charges", ) nbo: Optional[Dict[str, Any]] = Field( None, description="Natural Bonding Orbital (NBO) output" ) frequencies: Optional[Union[Dict[str, Any], List]] = Field( None, description="The list of calculated frequencies if job type is freq (units: cm^-1)", ) frequency_modes: Optional[Union[List, str]] = Field( None, description="The list of calculated frequency mode vectors if job type is freq", ) @classmethod def from_qchem_calc_doc(cls, calc_doc: Calculation) -> "OutputDoc": """ Create a summary of QChem calculation outputs from a QChem calculation document. Parameters ---------- calc_doc A QChem calculation document. kwargs Any other additional keyword arguments Returns -------- OutputDoc The calculation output summary """ return cls( initial_molecule=calc_doc.input.initial_molecule, optimized_molecule=calc_doc.output.optimized_molecule, # species_hash = self.species_hash, #The three entries post this needs to be checked again # coord_hash = self.coord_hash, # last_updated = self.last_updated, final_energy=calc_doc.output.final_energy, dipoles=calc_doc.output.dipoles, enthalpy=calc_doc.output.enthalpy, entropy=calc_doc.output.entropy, mulliken=calc_doc.output.mulliken, resp=calc_doc.output.resp, nbo=calc_doc.output.nbo_data, frequencies=calc_doc.output.frequencies, frequency_modes=calc_doc.output.frequency_modes, ) class InputDoc(BaseModel): initial_molecule: Molecule = Field( None, title="Input Structure", description="Input molecule and calc details for the QChem calculation", ) prev_rem_params: Optional[Dict[str, Any]] = Field( None, description="Parameters from a previous qchem calculation in the series", ) rem: Dict[str, Any] = Field( None, description="Parameters from the rem section of the current QChem calculation", ) level_of_theory: Optional[Union[str, LevelOfTheory]] = Field( None, description="Level of theory used in the qchem calculation" ) task_type: Optional[Union[str, TaskType]] = Field( None, description="The type of the QChem calculation : optimization, single point ... etc.", ) tags: Union[List[str], None] = Field( [], title="tag", description="Metadata tagged to a given task." ) solvation_lot_info: Optional[Union[Dict[str, Any], str]] = Field( None, description="Str or Dict representation of the solvent method used for the calculation", ) special_run_type: Optional[str] = Field( None, description="Special workflow name (if applicable)" ) smiles: Optional[str] = Field( None, description="Simplified molecular-input line-entry system (SMILES) string for the molecule involved " "in this calculation.", ) calc_type: Optional[Union[str, CalcType]] = Field( None, description="A combined dictionary representation of the task type along with the level of theory used", ) @classmethod def from_qchem_calc_doc(cls, calc_doc: Calculation) -> "InputDoc": """ Create qchem calculation input summary from a qchem calculation document. Parameters ---------- calc_doc A QChem calculation document. Returns -------- InputDoc A summary of the input molecule and corresponding calculation parameters """ try: lot_val = calc_doc.level_of_theory.value except AttributeError: lot_val = calc_doc.level_of_theory try: ct_val = calc_doc.calc_type.value except AttributeError: ct_val = calc_doc.calc_type # TODO : modify this to get the different variables from the task doc. return cls( initial_molecule=calc_doc.input.initial_molecule, rem=calc_doc.input.rem, level_of_theory=lot_val, task_type=calc_doc.task_type.value, tags=calc_doc.input.tags, solvation_lot_info=calc_doc.solvation_lot_info, # special_run_type = calc_doc.input.special_run_type, # smiles = calc_doc.input.smiles, calc_type=ct_val, ) class CustodianDoc(BaseModel): corrections: Optional[List[Any]] = Field( None, title="Custodian Corrections", description="List of custodian correction data for calculation.", ) job: Optional[Union[Dict[str, Any], QCJob]] = Field( None, title="Custodian Job Data", description="Job data logged by custodian.", ) # AnalysisDoc? Is there a scope for AnalysisDoc in QChem? class TaskDoc(MoleculeMetadata): """ Calculation-level details about QChem calculations that would eventually take over the TaskDocument implementation """ dir_name: Optional[Union[str, Path]] = Field( None, description="The directory for this QChem task" ) state: Optional[QChemStatus] = Field( None, description="State of this QChem calculation" ) calcs_reversed: Optional[List[Calculation]] = Field( None, title="Calcs reversed data", description="Detailed data for each QChem calculation contributing to the task document.", ) task_type: Optional[Union[CalcType, TaskType]] = Field( None, description="the type of QChem calculation" ) orig_inputs: Optional[Union[CalculationInput, Dict[str, Any]]] = Field( {}, description="Summary of the original Q-Chem inputs" ) input: Optional[InputDoc] = Field( None, description="The input molecule and calc parameters used to generate the current task document.", ) output: Optional[OutputDoc] = Field( None, description="The exact set of output parameters used to generate the current task document.", ) # TODO: Implement entry dict custodian: Optional[List[CustodianDoc]] = Field( None, title="Calcs reversed data", description="Detailed custodian data for each QChem calculation contributing to the task document.", ) critic2: Optional[Dict[str, Any]] = Field( None, description="Outputs from the critic2 calculation if performed" ) custom_smd: Optional[Union[str, Dict[str, Any]]] = Field( None, description="The seven solvent parameters necessary to define a custom_smd model", ) additional_fields: Optional[Dict[str, Any]] = Field( None, description="Any miscellaneous fields passed to the pydantic model" ) # TODO some sort of @validator s if necessary @classmethod def from_directory( cls: Type[_T], dir_name: Union[Path, str], validate_lot: bool = True, store_additional_json: bool = True, additional_fields: Dict[str, Any] = None, **qchem_calculation_kwargs, ) -> _T: """ Create a task document from a directory containing QChem files. Parameters ---------- dir_name The path to the folder containing the calculation outputs. validate_lot Flag for matching the basis and functional with the list of functionals consistent with MPCules. Defaults to True. Change to False if you want to create a TaskDoc with other basis sets and functionals. store_additional_json Whether to store additional json files in the calculation directory. additional_fields Dictionary of additional fields to add to output document. **qchem_calculation_kwargs Additional parsing options that will be passed to the :obj:`.Calculation.from_qchem_files` function. Returns ------- QChemTaskDoc A task document for the calculation """ logger.info(f"Getting task doc in: {dir_name}") additional_fields = {} if additional_fields is None else additional_fields dir_name = Path(dir_name) task_files = _find_qchem_files(dir_name) if len(task_files) == 0: raise FileNotFoundError("No QChem files found!") critic2 = {} custom_smd = {} calcs_reversed = [] for task_name, files in task_files.items(): if task_name == "orig": continue else: calc_doc = Calculation.from_qchem_files( dir_name, task_name, **files, **qchem_calculation_kwargs, validate_lot=validate_lot, ) calcs_reversed.append(calc_doc) # all_qchem_objects.append(qchem_objects) # Lists need to be reversed so that newest calc is the first calc, all_qchem_objects are also reversed to match calcs_reversed.reverse() # all_qchem_objects.reverse() custodian = _parse_custodian(dir_name) additional_json = None if store_additional_json: additional_json = _parse_additional_json(dir_name) for key, _ in additional_json.items(): if key == "processed_critic2": critic2["processed"] = additional_json["processed_critic2"] elif key == "cpreport": critic2["cp"] = additional_json["cpreport"] elif key == "YT": critic2["yt"] = additional_json["yt"] elif key == "bonding": critic2["bonding"] = additional_json["bonding"] elif key == "solvent_data": custom_smd = additional_json["solvent_data"] orig_inputs = ( CalculationInput.from_qcinput(_parse_orig_inputs(dir_name)) if _parse_orig_inputs(dir_name) else {} ) dir_name = get_uri(dir_name) # convert to full path # only store objects from last calculation # TODO: If vasp implementation makes this an option, change here as well qchem_objects = None included_objects = None if qchem_objects: included_objects = list(qchem_objects.keys()) # run_stats = _get_run_stats(calcs_reversed), Discuss whether this is something which is necessary in terms of QChem calcs doc = cls.from_molecule( meta_molecule=calcs_reversed[-1].input.initial_molecule, dir_name=dir_name, calcs_reversed=calcs_reversed, custodian=custodian, additional_json=additional_json, additional_fields=additional_fields, completed_at=calcs_reversed[0].completed_at, orig_inputs=orig_inputs, input=InputDoc.from_qchem_calc_doc(calcs_reversed[0]), output=OutputDoc.from_qchem_calc_doc(calcs_reversed[0]), state=_get_state(calcs_reversed), qchem_objects=qchem_objects, included_objects=included_objects, critic2=critic2, custom_smd=custom_smd, task_type=calcs_reversed[0].task_type, ) # doc = doc.copy(update=additional_fields) doc = doc.model_copy(update=additional_fields) return doc @staticmethod def get_entry( calcs_reversed: List[Calculation], task_id: Optional[str] = None ) -> Dict: """ Get a computed entry from a list of QChem calculation documents. Parameters ---------- calcs_reversed A list of QChem calculation documents in reverse order. task_id The job identifier Returns -------- Dict A dict of computed entries """ entry_dict = { "entry_id": task_id, "task_id": task_id, "charge": calcs_reversed[0].output.molecule.charge, "spin_multiplicity": calcs_reversed[0].output.molecule.spin_multiplicity, "level_of_theory": calcs_reversed[-1].input.level_of_theory, "solvent": calcs_reversed[-1].input.solv_spec, "lot_solvent": calcs_reversed[-1].input.lot_solv_combo, "custom_smd": calcs_reversed[-1].input.custom_smd, "task_type": calcs_reversed[-1].input.task_spec, "calc_type": calcs_reversed[-1].input.calc_spec, "tags": calcs_reversed[-1].input.tags, "molecule": calcs_reversed[0].output.molecule, "composition": calcs_reversed[0].output.molecule.composition, "formula": calcs_reversed[ 0 ].output.formula.composition.aplhabetical_formula, "energy": calcs_reversed[0].output.final_energy, "output": calcs_reversed[0].output.as_dict(), "critic2": calcs_reversed[ 0 ].output.critic, # TODO: Unclear about orig_inputs "last_updated": calcs_reversed[0].output.last_updated, } return entry_dict def get_uri(dir_name: Union[str, Path]) -> str: """ Return the URI path for a directory. This allows files hosted on different file servers to have distinct locations. Parameters ---------- dir_name : str or Path A directory name. Returns ------- str Full URI path, e.g., "fileserver.host.com:/full/payj/of/fir_name". """ import socket fullpath = Path(dir_name).absolute() hostname = socket.gethostname() try: hostname = socket.gethostbyaddr(hostname)[0] except (socket.gaierror, socket.herror): pass return f"{hostname}:{fullpath}" def _parse_custodian(dir_name: Path) -> Optional[Dict]: """ Parse custodian.json file. Calculations done using custodian have a custodian.json file which tracks the makers performed and any errors detected and fixed. Parameters ---------- dir_name Path to calculation directory. Returns -------- Optional[Dict] The information parsed from custodian.json file. """ filenames = tuple(dir_name.glob("custodian.json*")) if len(filenames) >= 1: return loadfn(filenames[0], cls=None) return None def _parse_orig_inputs( dir_name: Path, ) -> Dict[str, Any]: """ Parse original input files. Calculations using custodian generate a *.orig file for the inputs. This is useful to know how the calculation originally started. Parameters ---------- dir_name Path to calculation directory. Returns ------- Dict[str, Any] The original molecule, rem, solvent and other data. """ orig_inputs = {} orig_file_path = next(dir_name.glob("*.orig*"), None) if orig_file_path: orig_inputs = QCInput.from_file(orig_file_path) return orig_inputs def _parse_additional_json(dir_name: Path) -> Dict[str, Any]: """Parse additional json files in the directory.""" additional_json = {} for filename in dir_name.glob("*.json*"): key = filename.name.split(".")[0] if key not in ("custodian", "transformations"): if key not in additional_json: additional_json[key] = loadfn(filename, cls=None) return additional_json def _get_state(calcs_reversed: List[Calculation]) -> QChemStatus: """Get state from calculation documents of QChem tasks.""" all_calcs_completed = all( [c.has_qchem_completed == QChemStatus.SUCCESS for c in calcs_reversed] ) if all_calcs_completed: return QChemStatus.SUCCESS return QChemStatus.FAILED # def _get_run_stats(calcs_reversed: List[Calculation]) -> Dict[str, RunStatistics]: # """Get summary of runtime statistics for each calculation in this task.""" # run_stats = {} # total = dict( # average_memory=0.0, # max_memory=0.0, # elapsed_time=0.0, # system_time=0.0, # user_time=0.0, # total_time=0.0, # cores=0, # ) def _find_qchem_files( path: Union[str, Path], ) -> Dict[str, Any]: """ Find QChem files in a directory. Only the mol.qout file (or alternatively files with the task name as an extension, e.g., mol.qout.opt_0.gz, mol.qout.freq_1.gz, or something like this...) will be returned. Parameters ---------- path Path to a directory to search. Returns ------- Dict[str, Any] The filenames of the calculation outputs for each QChem task, given as a ordered dictionary of:: { task_name:{ "qchem_out_file": qcrun_filename, }, ... } If there is only 1 qout file task_name will be "standard" otherwise it will be the extension name like "opt_0" """ path = Path(path) task_files = OrderedDict() in_file_pattern = re.compile(r"^(?Pmol\.(qin|in)(?:\..+)?)(\.gz)?$") for file in path.iterdir(): if file.is_file(): in_match = in_file_pattern.match(file.name) # This block is for generalizing outputs coming from both atomate and manual qchem calculations if in_match: in_task_name = re.sub( r"(\.gz|gz)$", "", in_match.group("in_task_name").replace("mol.qin.", ""), ) in_task_name = in_task_name or "mol.qin" if in_task_name == "orig": task_files[in_task_name] = {"orig_input_file": file.name} elif in_task_name == "last": continue elif in_task_name == "mol.qin" or in_task_name == "mol.in": if in_task_name == "mol.qin": out_file = ( path / "mol.qout.gz" if (path / "mol.qout.gz").exists() else path / "mol.qout" ) else: out_file = ( path / "mol.out.gz" if (path / "mol.out.gz").exists() else path / "mol.out" ) task_files["standard"] = { "qcinput_file": file.name, "qcoutput_file": out_file.name, } # This block will exist only if calcs were run through atomate else: try: task_files[in_task_name] = { "qcinput_file": file.name, "qcoutput_file": Path( "mol.qout." + in_task_name + ".gz" ).name, } except FileNotFoundError: task_files[in_task_name] = { "qcinput_file": file.name, "qcoutput_file": "No qout files exist for this in file", } return task_files ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0492902 emmet-core-0.84.2/emmet/core/qchem/0000755000175100001770000000000014673360566016423 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/__init__.py0000644000175100001770000000000014673360562020516 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1726865782.05029 emmet-core-0.84.2/emmet/core/qchem/calc_types/0000755000175100001770000000000014673360566020551 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/__init__.py0000644000175100001770000000041314673360562022654 0ustar00runnerdocker"""Module defining Q-Chem calculation types.""" from emmet.core.qchem.calc_types.enums import CalcType, LevelOfTheory, TaskType from emmet.core.qchem.calc_types.utils import ( calc_type, level_of_theory, task_type, solvent, lot_solvent_string, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/calc_types.py0000644000175100001770000000133114673360562023243 0ustar00runnerdocker"""Task types and level of theory components for Q-Chem calculations""" from importlib.resources import files as import_resource_files from monty.serialization import loadfn __author__ = "Evan Spotte-Smith " _calc_type_config = loadfn( str(import_resource_files("emmet.core.qchem.calc_types") / "calc_types.yaml") ) # NB: this would be easier with setattr but the following is less opaque FUNCTIONAL_CLASSES = _calc_type_config.get("FUNCTIONAL_CLASSES") TASK_TYPES = _calc_type_config.get("TASK_TYPES") BASIS_SETS = _calc_type_config.get("BASIS_SETS") SOLVENT_MODELS = _calc_type_config.get("SOLVENT_MODELS") FUNCTIONALS = [rt for functionals in FUNCTIONAL_CLASSES.values() for rt in functionals] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/calc_types.yaml0000644000175100001770000000254714673360562023567 0ustar00runnerdocker# - Task Functional and calc types needed for QChem enums TASK_TYPES: - Single Point - Force - Geometry Optimization - Frequency Analysis - Frequency Flattening Geometry Optimization - Transition State Geometry Optimization - Frequency Flattening Transition State Geometry Optimization - Unknown FUNCTIONAL_CLASSES: gga: - PBE # - PBE-D3(BJ) # - BLYP # - BLYP-D3(BJ) - B97-D - B97-D3 # - mPW91 # - mPW91-D3(BJ) # - VV10 # - rVV10 meta-gga: # - M06-L # - M06-L-D3(0) # - SCAN # - SCAN-D3(BJ) # - TPSS # - TPSS-D3(BJ) - MN12-L # - MN12-L-D3(BJ) - B97M-V - B97M-rV hybrid-gga: # - PBE0 # - PBE0-D3(BJ) - B3LYP # - B3LYP-D3(BJ) # - CAM-B3LYP # - CAM-B3LYP-D3(0) # - mPW1PW91 # - mPW1PW91-D3(BJ) # - wB97X - wB97X-D - wB97X-D3 - wB97X-V hybrid-meta-gga: # - M06-2X # - M06-2X-D3(0) # - M06-HF # - M08-SO # - M11 # - MN15 # - BMK # - BMK-D3(BJ) # - TPSSh # - TPSSh-D3(BJ) # - SCAN0 # - mPWB1K # - mPWB1K-D3(BJ) - wB97M-V BASIS_SETS: - 6-31g* - def2-SVPD - def2-TZVP - def2-TZVPD - def2-TZVPP - def2-TZVPPD - def2-QZVPD - def2-QZVPPD # TODO: add ISOSVP and CMIRS once these are implemented in pymatgen and atomate/atomate2 SOLVENT_MODELS: - VACUUM - PCM - SMD ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/em_utils.py0000644000175100001770000001641614673360562022750 0ustar00runnerdocker""" Utilities to determine level of theory, task type, and calculation type for Q-Chem calculations in the pydantic Docs paradigm""" from typing import Optional from emmet.core.qchem.calc_types import LevelOfTheory, CalcType, TaskType from emmet.core.qchem.calculation import CalculationInput from emmet.core.qchem.calc_types.calc_types import ( FUNCTIONALS, BASIS_SETS, ) __author__ = ( "Evan Spotte-Smith , Rishabh Debraj Guha " ) # TODO: better way of translating names functional_synonyms = { "b97mv": "b97m-v", "b97mrv": "b97m-rv", "wb97xd": "wb97x-d", "wb97xd3": "wb97x-d3", "wb97xv": "wb97x-v", "wb97mv": "wb97m-v", } smd_synonyms = { "DIELECTRIC=7,230;N=1,410;ALPHA=0,000;BETA=0,859;GAMMA=36,830;PHI=0,000;PSI=0,000": "diglyme", "DIELECTRIC=18,500;N=1,415;ALPHA=0,000;BETA=0,735;GAMMA=20,200;PHI=0,000;PSI=0,000": "3:7 EC:EMC", } def level_of_theory(parameters: CalculationInput) -> LevelOfTheory: """ Returns the level of theory for a calculation, based on the input parameters given to Q-Chem Args: parameters: Dict of Q-Chem input parameters """ funct_raw = parameters.rem.get("method") basis_raw = parameters.rem.get("basis") if funct_raw is None or basis_raw is None: raise ValueError( 'Method and basis must be included in "rem" section ' "of parameters!" ) disp_corr = parameters.rem.get("dft_d") if disp_corr is None: funct_lower = funct_raw.lower() funct_lower = functional_synonyms.get(funct_lower, funct_lower) else: # Replace Q-Chem terms for D3 tails with more common expressions disp_corr = disp_corr.replace("_bj", "(bj)").replace("_zero", "(0)") funct_lower = f"{funct_raw}-{disp_corr}" basis_lower = basis_raw.lower() # --> TODO: replace with enums functional = [f for f in FUNCTIONALS if f.lower() == funct_lower] if not functional: raise ValueError(f"Unexpected functional {funct_lower}!") functional = functional[0] basis = [b for b in BASIS_SETS if b.lower() == basis_lower] if not basis: raise ValueError(f"Unexpected basis set {basis_lower}!") # <-- basis = basis[0] solvent_method = parameters.rem.get("solvent_method", "").lower() if solvent_method == "": solvation = "VACUUM" elif solvent_method in ["pcm", "cosmo"]: solvation = "PCM" # TODO: Add this once added into pymatgen and atomate # elif solvent_method == "isosvp": # if parameters.get("svp", {}).get("idefesr", 0): # solvation = "CMIRS" # else: # solvation = "ISOSVP" elif solvent_method == "smd": solvation = "SMD" else: raise ValueError(f"Unexpected implicit solvent method {solvent_method}!") lot = f"{functional}/{basis}/{solvation}" return LevelOfTheory(lot) def solvent(parameters: CalculationInput, custom_smd: Optional[str] = None) -> str: """ Returns the solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ lot = level_of_theory(parameters) solvation = lot.value.split("/")[-1] if solvation == "PCM": dielectric = float(parameters.get("solvent", {}).get("dielectric", 78.39)) dielectric_string = f"{dielectric:.2f}".replace(".", ",") return f"DIELECTRIC={dielectric_string}" # TODO: Add this once added into pymatgen and atomate # elif solvation == "ISOSVP": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # return f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # elif solvation == "CMIRS": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # a = parameters.get("pcm_nonels", {}).get("a") # b = parameters.get("pcm_nonels", {}).get("b") # c = parameters.get("pcm_nonels", {}).get("c") # d = parameters.get("pcm_nonels", {}).get("d") # solvrho = parameters.get("pcm_nonels", {}).get("solvrho") # gamma = parameters.get("pcm_nonels", {}).get("gamma") # # string = f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # for name, (piece, digits) in {"A": (a, 6), "B": (b, 6), "C": (c, 1), "D": (d, 3), # "SOLVRHO": (solvrho, 2), "GAMMA": (gamma, 1)}.items(): # if piece is None: # piecestring = "NONE" # else: # piecestring = f"{name}={round(float(piece), digits)}" # string += "," + piecestring # return string elif solvation == "SMD": solvent = parameters.get("smx", {}).get("solvent", "water") if solvent == "other": if custom_smd is None: raise ValueError( "SMD calculation with solvent=other requires custom_smd!" ) names = ["DIELECTRIC", "N", "ALPHA", "BETA", "GAMMA", "PHI", "PSI"] numbers = [float(x) for x in custom_smd.split(",")] string = "" for name, number in zip(names, numbers): string += f"{name}={number:.3f};" return string.rstrip(",").rstrip(";").replace(".", ",") else: return f"SOLVENT={solvent.upper()}" else: return "NONE" def lot_solvent_string( parameters: CalculationInput, custom_smd: Optional[str] = None ) -> str: """ Returns a string representation of the level of theory and solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ lot = level_of_theory(parameters).value solv = solvent(parameters, custom_smd=custom_smd) return f"{lot}({solv})" def task_type( parameters: CalculationInput, special_run_type: Optional[str] = None ) -> TaskType: if special_run_type == "frequency_flattener": return TaskType("Frequency Flattening Geometry Optimization") elif special_run_type == "ts_frequency_flattener": return TaskType("Frequency Flattening Transition State Geometry Optimization") if parameters.job_type == "sp": return TaskType("Single Point") elif parameters.job_type == "force": return TaskType("Force") elif parameters.job_type == "opt": return TaskType("Geometry Optimization") elif parameters.job_type == "ts": return TaskType("Transition State Geometry Optimization") elif parameters.job_type == "freq": return TaskType("Frequency Analysis") return TaskType("Unknown") def calc_type( parameters: CalculationInput, special_run_type: Optional[str] = None ) -> CalcType: """ Determines the calc type Args: inputs: inputs dict with an incar, kpoints, potcar, and poscar dictionaries parameters: Dictionary of VASP parameters from Vasprun.xml """ rt = level_of_theory(parameters).value tt = task_type(parameters, special_run_type=special_run_type).value return CalcType(f"{rt} {tt}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/enums.py0000644000175100001770000076106114673360562022261 0ustar00runnerdocker""" Autogenerated Enums for Q-Chem LevelOfTheory, TaskType, and CalcType. Do not edit this by hand to add or remove enums. Instead, edit dev_scripts/generate_enums.py and/or emmet/core/qchem/calc_types/calc_types.yaml """ from emmet.core.utils import ValueEnum class LevelOfTheory(ValueEnum): """Levels of theory for calculations in Q-Chem.""" B3LYP_6_31g_d_PCM = "B3LYP/6-31g*/PCM" B3LYP_6_31g_d_SMD = "B3LYP/6-31g*/SMD" B3LYP_6_31g_d_VACUUM = "B3LYP/6-31g*/VACUUM" B3LYP_def2_QZVPD_PCM = "B3LYP/def2-QZVPD/PCM" B3LYP_def2_QZVPD_SMD = "B3LYP/def2-QZVPD/SMD" B3LYP_def2_QZVPD_VACUUM = "B3LYP/def2-QZVPD/VACUUM" B3LYP_def2_QZVPPD_PCM = "B3LYP/def2-QZVPPD/PCM" B3LYP_def2_QZVPPD_SMD = "B3LYP/def2-QZVPPD/SMD" B3LYP_def2_QZVPPD_VACUUM = "B3LYP/def2-QZVPPD/VACUUM" B3LYP_def2_SVPD_PCM = "B3LYP/def2-SVPD/PCM" B3LYP_def2_SVPD_SMD = "B3LYP/def2-SVPD/SMD" B3LYP_def2_SVPD_VACUUM = "B3LYP/def2-SVPD/VACUUM" B3LYP_def2_TZVPD_PCM = "B3LYP/def2-TZVPD/PCM" B3LYP_def2_TZVPD_SMD = "B3LYP/def2-TZVPD/SMD" B3LYP_def2_TZVPD_VACUUM = "B3LYP/def2-TZVPD/VACUUM" B3LYP_def2_TZVPPD_PCM = "B3LYP/def2-TZVPPD/PCM" B3LYP_def2_TZVPPD_SMD = "B3LYP/def2-TZVPPD/SMD" B3LYP_def2_TZVPPD_VACUUM = "B3LYP/def2-TZVPPD/VACUUM" B3LYP_def2_TZVPP_PCM = "B3LYP/def2-TZVPP/PCM" B3LYP_def2_TZVPP_SMD = "B3LYP/def2-TZVPP/SMD" B3LYP_def2_TZVPP_VACUUM = "B3LYP/def2-TZVPP/VACUUM" B3LYP_def2_TZVP_PCM = "B3LYP/def2-TZVP/PCM" B3LYP_def2_TZVP_SMD = "B3LYP/def2-TZVP/SMD" B3LYP_def2_TZVP_VACUUM = "B3LYP/def2-TZVP/VACUUM" B97M_V_6_31g_d_PCM = "B97M-V/6-31g*/PCM" B97M_V_6_31g_d_SMD = "B97M-V/6-31g*/SMD" B97M_V_6_31g_d_VACUUM = "B97M-V/6-31g*/VACUUM" B97M_V_def2_QZVPD_PCM = "B97M-V/def2-QZVPD/PCM" B97M_V_def2_QZVPD_SMD = "B97M-V/def2-QZVPD/SMD" B97M_V_def2_QZVPD_VACUUM = "B97M-V/def2-QZVPD/VACUUM" B97M_V_def2_QZVPPD_PCM = "B97M-V/def2-QZVPPD/PCM" B97M_V_def2_QZVPPD_SMD = "B97M-V/def2-QZVPPD/SMD" B97M_V_def2_QZVPPD_VACUUM = "B97M-V/def2-QZVPPD/VACUUM" B97M_V_def2_SVPD_PCM = "B97M-V/def2-SVPD/PCM" B97M_V_def2_SVPD_SMD = "B97M-V/def2-SVPD/SMD" B97M_V_def2_SVPD_VACUUM = "B97M-V/def2-SVPD/VACUUM" B97M_V_def2_TZVPD_PCM = "B97M-V/def2-TZVPD/PCM" B97M_V_def2_TZVPD_SMD = "B97M-V/def2-TZVPD/SMD" B97M_V_def2_TZVPD_VACUUM = "B97M-V/def2-TZVPD/VACUUM" B97M_V_def2_TZVPPD_PCM = "B97M-V/def2-TZVPPD/PCM" B97M_V_def2_TZVPPD_SMD = "B97M-V/def2-TZVPPD/SMD" B97M_V_def2_TZVPPD_VACUUM = "B97M-V/def2-TZVPPD/VACUUM" B97M_V_def2_TZVPP_PCM = "B97M-V/def2-TZVPP/PCM" B97M_V_def2_TZVPP_SMD = "B97M-V/def2-TZVPP/SMD" B97M_V_def2_TZVPP_VACUUM = "B97M-V/def2-TZVPP/VACUUM" B97M_V_def2_TZVP_PCM = "B97M-V/def2-TZVP/PCM" B97M_V_def2_TZVP_SMD = "B97M-V/def2-TZVP/SMD" B97M_V_def2_TZVP_VACUUM = "B97M-V/def2-TZVP/VACUUM" B97M_rV_6_31g_d_PCM = "B97M-rV/6-31g*/PCM" B97M_rV_6_31g_d_SMD = "B97M-rV/6-31g*/SMD" B97M_rV_6_31g_d_VACUUM = "B97M-rV/6-31g*/VACUUM" B97M_rV_def2_QZVPD_PCM = "B97M-rV/def2-QZVPD/PCM" B97M_rV_def2_QZVPD_SMD = "B97M-rV/def2-QZVPD/SMD" B97M_rV_def2_QZVPD_VACUUM = "B97M-rV/def2-QZVPD/VACUUM" B97M_rV_def2_QZVPPD_PCM = "B97M-rV/def2-QZVPPD/PCM" B97M_rV_def2_QZVPPD_SMD = "B97M-rV/def2-QZVPPD/SMD" B97M_rV_def2_QZVPPD_VACUUM = "B97M-rV/def2-QZVPPD/VACUUM" B97M_rV_def2_SVPD_PCM = "B97M-rV/def2-SVPD/PCM" B97M_rV_def2_SVPD_SMD = "B97M-rV/def2-SVPD/SMD" B97M_rV_def2_SVPD_VACUUM = "B97M-rV/def2-SVPD/VACUUM" B97M_rV_def2_TZVPD_PCM = "B97M-rV/def2-TZVPD/PCM" B97M_rV_def2_TZVPD_SMD = "B97M-rV/def2-TZVPD/SMD" B97M_rV_def2_TZVPD_VACUUM = "B97M-rV/def2-TZVPD/VACUUM" B97M_rV_def2_TZVPPD_PCM = "B97M-rV/def2-TZVPPD/PCM" B97M_rV_def2_TZVPPD_SMD = "B97M-rV/def2-TZVPPD/SMD" B97M_rV_def2_TZVPPD_VACUUM = "B97M-rV/def2-TZVPPD/VACUUM" B97M_rV_def2_TZVPP_PCM = "B97M-rV/def2-TZVPP/PCM" B97M_rV_def2_TZVPP_SMD = "B97M-rV/def2-TZVPP/SMD" B97M_rV_def2_TZVPP_VACUUM = "B97M-rV/def2-TZVPP/VACUUM" B97M_rV_def2_TZVP_PCM = "B97M-rV/def2-TZVP/PCM" B97M_rV_def2_TZVP_SMD = "B97M-rV/def2-TZVP/SMD" B97M_rV_def2_TZVP_VACUUM = "B97M-rV/def2-TZVP/VACUUM" B97_D3_6_31g_d_PCM = "B97-D3/6-31g*/PCM" B97_D3_6_31g_d_SMD = "B97-D3/6-31g*/SMD" B97_D3_6_31g_d_VACUUM = "B97-D3/6-31g*/VACUUM" B97_D3_def2_QZVPD_PCM = "B97-D3/def2-QZVPD/PCM" B97_D3_def2_QZVPD_SMD = "B97-D3/def2-QZVPD/SMD" B97_D3_def2_QZVPD_VACUUM = "B97-D3/def2-QZVPD/VACUUM" B97_D3_def2_QZVPPD_PCM = "B97-D3/def2-QZVPPD/PCM" B97_D3_def2_QZVPPD_SMD = "B97-D3/def2-QZVPPD/SMD" B97_D3_def2_QZVPPD_VACUUM = "B97-D3/def2-QZVPPD/VACUUM" B97_D3_def2_SVPD_PCM = "B97-D3/def2-SVPD/PCM" B97_D3_def2_SVPD_SMD = "B97-D3/def2-SVPD/SMD" B97_D3_def2_SVPD_VACUUM = "B97-D3/def2-SVPD/VACUUM" B97_D3_def2_TZVPD_PCM = "B97-D3/def2-TZVPD/PCM" B97_D3_def2_TZVPD_SMD = "B97-D3/def2-TZVPD/SMD" B97_D3_def2_TZVPD_VACUUM = "B97-D3/def2-TZVPD/VACUUM" B97_D3_def2_TZVPPD_PCM = "B97-D3/def2-TZVPPD/PCM" B97_D3_def2_TZVPPD_SMD = "B97-D3/def2-TZVPPD/SMD" B97_D3_def2_TZVPPD_VACUUM = "B97-D3/def2-TZVPPD/VACUUM" B97_D3_def2_TZVPP_PCM = "B97-D3/def2-TZVPP/PCM" B97_D3_def2_TZVPP_SMD = "B97-D3/def2-TZVPP/SMD" B97_D3_def2_TZVPP_VACUUM = "B97-D3/def2-TZVPP/VACUUM" B97_D3_def2_TZVP_PCM = "B97-D3/def2-TZVP/PCM" B97_D3_def2_TZVP_SMD = "B97-D3/def2-TZVP/SMD" B97_D3_def2_TZVP_VACUUM = "B97-D3/def2-TZVP/VACUUM" B97_D_6_31g_d_PCM = "B97-D/6-31g*/PCM" B97_D_6_31g_d_SMD = "B97-D/6-31g*/SMD" B97_D_6_31g_d_VACUUM = "B97-D/6-31g*/VACUUM" B97_D_def2_QZVPD_PCM = "B97-D/def2-QZVPD/PCM" B97_D_def2_QZVPD_SMD = "B97-D/def2-QZVPD/SMD" B97_D_def2_QZVPD_VACUUM = "B97-D/def2-QZVPD/VACUUM" B97_D_def2_QZVPPD_PCM = "B97-D/def2-QZVPPD/PCM" B97_D_def2_QZVPPD_SMD = "B97-D/def2-QZVPPD/SMD" B97_D_def2_QZVPPD_VACUUM = "B97-D/def2-QZVPPD/VACUUM" B97_D_def2_SVPD_PCM = "B97-D/def2-SVPD/PCM" B97_D_def2_SVPD_SMD = "B97-D/def2-SVPD/SMD" B97_D_def2_SVPD_VACUUM = "B97-D/def2-SVPD/VACUUM" B97_D_def2_TZVPD_PCM = "B97-D/def2-TZVPD/PCM" B97_D_def2_TZVPD_SMD = "B97-D/def2-TZVPD/SMD" B97_D_def2_TZVPD_VACUUM = "B97-D/def2-TZVPD/VACUUM" B97_D_def2_TZVPPD_PCM = "B97-D/def2-TZVPPD/PCM" B97_D_def2_TZVPPD_SMD = "B97-D/def2-TZVPPD/SMD" B97_D_def2_TZVPPD_VACUUM = "B97-D/def2-TZVPPD/VACUUM" B97_D_def2_TZVPP_PCM = "B97-D/def2-TZVPP/PCM" B97_D_def2_TZVPP_SMD = "B97-D/def2-TZVPP/SMD" B97_D_def2_TZVPP_VACUUM = "B97-D/def2-TZVPP/VACUUM" B97_D_def2_TZVP_PCM = "B97-D/def2-TZVP/PCM" B97_D_def2_TZVP_SMD = "B97-D/def2-TZVP/SMD" B97_D_def2_TZVP_VACUUM = "B97-D/def2-TZVP/VACUUM" MN12_L_6_31g_d_PCM = "MN12-L/6-31g*/PCM" MN12_L_6_31g_d_SMD = "MN12-L/6-31g*/SMD" MN12_L_6_31g_d_VACUUM = "MN12-L/6-31g*/VACUUM" MN12_L_def2_QZVPD_PCM = "MN12-L/def2-QZVPD/PCM" MN12_L_def2_QZVPD_SMD = "MN12-L/def2-QZVPD/SMD" MN12_L_def2_QZVPD_VACUUM = "MN12-L/def2-QZVPD/VACUUM" MN12_L_def2_QZVPPD_PCM = "MN12-L/def2-QZVPPD/PCM" MN12_L_def2_QZVPPD_SMD = "MN12-L/def2-QZVPPD/SMD" MN12_L_def2_QZVPPD_VACUUM = "MN12-L/def2-QZVPPD/VACUUM" MN12_L_def2_SVPD_PCM = "MN12-L/def2-SVPD/PCM" MN12_L_def2_SVPD_SMD = "MN12-L/def2-SVPD/SMD" MN12_L_def2_SVPD_VACUUM = "MN12-L/def2-SVPD/VACUUM" MN12_L_def2_TZVPD_PCM = "MN12-L/def2-TZVPD/PCM" MN12_L_def2_TZVPD_SMD = "MN12-L/def2-TZVPD/SMD" MN12_L_def2_TZVPD_VACUUM = "MN12-L/def2-TZVPD/VACUUM" MN12_L_def2_TZVPPD_PCM = "MN12-L/def2-TZVPPD/PCM" MN12_L_def2_TZVPPD_SMD = "MN12-L/def2-TZVPPD/SMD" MN12_L_def2_TZVPPD_VACUUM = "MN12-L/def2-TZVPPD/VACUUM" MN12_L_def2_TZVPP_PCM = "MN12-L/def2-TZVPP/PCM" MN12_L_def2_TZVPP_SMD = "MN12-L/def2-TZVPP/SMD" MN12_L_def2_TZVPP_VACUUM = "MN12-L/def2-TZVPP/VACUUM" MN12_L_def2_TZVP_PCM = "MN12-L/def2-TZVP/PCM" MN12_L_def2_TZVP_SMD = "MN12-L/def2-TZVP/SMD" MN12_L_def2_TZVP_VACUUM = "MN12-L/def2-TZVP/VACUUM" PBE_6_31g_d_PCM = "PBE/6-31g*/PCM" PBE_6_31g_d_SMD = "PBE/6-31g*/SMD" PBE_6_31g_d_VACUUM = "PBE/6-31g*/VACUUM" PBE_def2_QZVPD_PCM = "PBE/def2-QZVPD/PCM" PBE_def2_QZVPD_SMD = "PBE/def2-QZVPD/SMD" PBE_def2_QZVPD_VACUUM = "PBE/def2-QZVPD/VACUUM" PBE_def2_QZVPPD_PCM = "PBE/def2-QZVPPD/PCM" PBE_def2_QZVPPD_SMD = "PBE/def2-QZVPPD/SMD" PBE_def2_QZVPPD_VACUUM = "PBE/def2-QZVPPD/VACUUM" PBE_def2_SVPD_PCM = "PBE/def2-SVPD/PCM" PBE_def2_SVPD_SMD = "PBE/def2-SVPD/SMD" PBE_def2_SVPD_VACUUM = "PBE/def2-SVPD/VACUUM" PBE_def2_TZVPD_PCM = "PBE/def2-TZVPD/PCM" PBE_def2_TZVPD_SMD = "PBE/def2-TZVPD/SMD" PBE_def2_TZVPD_VACUUM = "PBE/def2-TZVPD/VACUUM" PBE_def2_TZVPPD_PCM = "PBE/def2-TZVPPD/PCM" PBE_def2_TZVPPD_SMD = "PBE/def2-TZVPPD/SMD" PBE_def2_TZVPPD_VACUUM = "PBE/def2-TZVPPD/VACUUM" PBE_def2_TZVPP_PCM = "PBE/def2-TZVPP/PCM" PBE_def2_TZVPP_SMD = "PBE/def2-TZVPP/SMD" PBE_def2_TZVPP_VACUUM = "PBE/def2-TZVPP/VACUUM" PBE_def2_TZVP_PCM = "PBE/def2-TZVP/PCM" PBE_def2_TZVP_SMD = "PBE/def2-TZVP/SMD" PBE_def2_TZVP_VACUUM = "PBE/def2-TZVP/VACUUM" wB97M_V_6_31g_d_PCM = "wB97M-V/6-31g*/PCM" wB97M_V_6_31g_d_SMD = "wB97M-V/6-31g*/SMD" wB97M_V_6_31g_d_VACUUM = "wB97M-V/6-31g*/VACUUM" wB97M_V_def2_QZVPD_PCM = "wB97M-V/def2-QZVPD/PCM" wB97M_V_def2_QZVPD_SMD = "wB97M-V/def2-QZVPD/SMD" wB97M_V_def2_QZVPD_VACUUM = "wB97M-V/def2-QZVPD/VACUUM" wB97M_V_def2_QZVPPD_PCM = "wB97M-V/def2-QZVPPD/PCM" wB97M_V_def2_QZVPPD_SMD = "wB97M-V/def2-QZVPPD/SMD" wB97M_V_def2_QZVPPD_VACUUM = "wB97M-V/def2-QZVPPD/VACUUM" wB97M_V_def2_SVPD_PCM = "wB97M-V/def2-SVPD/PCM" wB97M_V_def2_SVPD_SMD = "wB97M-V/def2-SVPD/SMD" wB97M_V_def2_SVPD_VACUUM = "wB97M-V/def2-SVPD/VACUUM" wB97M_V_def2_TZVPD_PCM = "wB97M-V/def2-TZVPD/PCM" wB97M_V_def2_TZVPD_SMD = "wB97M-V/def2-TZVPD/SMD" wB97M_V_def2_TZVPD_VACUUM = "wB97M-V/def2-TZVPD/VACUUM" wB97M_V_def2_TZVPPD_PCM = "wB97M-V/def2-TZVPPD/PCM" wB97M_V_def2_TZVPPD_SMD = "wB97M-V/def2-TZVPPD/SMD" wB97M_V_def2_TZVPPD_VACUUM = "wB97M-V/def2-TZVPPD/VACUUM" wB97M_V_def2_TZVPP_PCM = "wB97M-V/def2-TZVPP/PCM" wB97M_V_def2_TZVPP_SMD = "wB97M-V/def2-TZVPP/SMD" wB97M_V_def2_TZVPP_VACUUM = "wB97M-V/def2-TZVPP/VACUUM" wB97M_V_def2_TZVP_PCM = "wB97M-V/def2-TZVP/PCM" wB97M_V_def2_TZVP_SMD = "wB97M-V/def2-TZVP/SMD" wB97M_V_def2_TZVP_VACUUM = "wB97M-V/def2-TZVP/VACUUM" wB97X_D3_6_31g_d_PCM = "wB97X-D3/6-31g*/PCM" wB97X_D3_6_31g_d_SMD = "wB97X-D3/6-31g*/SMD" wB97X_D3_6_31g_d_VACUUM = "wB97X-D3/6-31g*/VACUUM" wB97X_D3_def2_QZVPD_PCM = "wB97X-D3/def2-QZVPD/PCM" wB97X_D3_def2_QZVPD_SMD = "wB97X-D3/def2-QZVPD/SMD" wB97X_D3_def2_QZVPD_VACUUM = "wB97X-D3/def2-QZVPD/VACUUM" wB97X_D3_def2_QZVPPD_PCM = "wB97X-D3/def2-QZVPPD/PCM" wB97X_D3_def2_QZVPPD_SMD = "wB97X-D3/def2-QZVPPD/SMD" wB97X_D3_def2_QZVPPD_VACUUM = "wB97X-D3/def2-QZVPPD/VACUUM" wB97X_D3_def2_SVPD_PCM = "wB97X-D3/def2-SVPD/PCM" wB97X_D3_def2_SVPD_SMD = "wB97X-D3/def2-SVPD/SMD" wB97X_D3_def2_SVPD_VACUUM = "wB97X-D3/def2-SVPD/VACUUM" wB97X_D3_def2_TZVPD_PCM = "wB97X-D3/def2-TZVPD/PCM" wB97X_D3_def2_TZVPD_SMD = "wB97X-D3/def2-TZVPD/SMD" wB97X_D3_def2_TZVPD_VACUUM = "wB97X-D3/def2-TZVPD/VACUUM" wB97X_D3_def2_TZVPPD_PCM = "wB97X-D3/def2-TZVPPD/PCM" wB97X_D3_def2_TZVPPD_SMD = "wB97X-D3/def2-TZVPPD/SMD" wB97X_D3_def2_TZVPPD_VACUUM = "wB97X-D3/def2-TZVPPD/VACUUM" wB97X_D3_def2_TZVPP_PCM = "wB97X-D3/def2-TZVPP/PCM" wB97X_D3_def2_TZVPP_SMD = "wB97X-D3/def2-TZVPP/SMD" wB97X_D3_def2_TZVPP_VACUUM = "wB97X-D3/def2-TZVPP/VACUUM" wB97X_D3_def2_TZVP_PCM = "wB97X-D3/def2-TZVP/PCM" wB97X_D3_def2_TZVP_SMD = "wB97X-D3/def2-TZVP/SMD" wB97X_D3_def2_TZVP_VACUUM = "wB97X-D3/def2-TZVP/VACUUM" wB97X_D_6_31g_d_PCM = "wB97X-D/6-31g*/PCM" wB97X_D_6_31g_d_SMD = "wB97X-D/6-31g*/SMD" wB97X_D_6_31g_d_VACUUM = "wB97X-D/6-31g*/VACUUM" wB97X_D_def2_QZVPD_PCM = "wB97X-D/def2-QZVPD/PCM" wB97X_D_def2_QZVPD_SMD = "wB97X-D/def2-QZVPD/SMD" wB97X_D_def2_QZVPD_VACUUM = "wB97X-D/def2-QZVPD/VACUUM" wB97X_D_def2_QZVPPD_PCM = "wB97X-D/def2-QZVPPD/PCM" wB97X_D_def2_QZVPPD_SMD = "wB97X-D/def2-QZVPPD/SMD" wB97X_D_def2_QZVPPD_VACUUM = "wB97X-D/def2-QZVPPD/VACUUM" wB97X_D_def2_SVPD_PCM = "wB97X-D/def2-SVPD/PCM" wB97X_D_def2_SVPD_SMD = "wB97X-D/def2-SVPD/SMD" wB97X_D_def2_SVPD_VACUUM = "wB97X-D/def2-SVPD/VACUUM" wB97X_D_def2_TZVPD_PCM = "wB97X-D/def2-TZVPD/PCM" wB97X_D_def2_TZVPD_SMD = "wB97X-D/def2-TZVPD/SMD" wB97X_D_def2_TZVPD_VACUUM = "wB97X-D/def2-TZVPD/VACUUM" wB97X_D_def2_TZVPPD_PCM = "wB97X-D/def2-TZVPPD/PCM" wB97X_D_def2_TZVPPD_SMD = "wB97X-D/def2-TZVPPD/SMD" wB97X_D_def2_TZVPPD_VACUUM = "wB97X-D/def2-TZVPPD/VACUUM" wB97X_D_def2_TZVPP_PCM = "wB97X-D/def2-TZVPP/PCM" wB97X_D_def2_TZVPP_SMD = "wB97X-D/def2-TZVPP/SMD" wB97X_D_def2_TZVPP_VACUUM = "wB97X-D/def2-TZVPP/VACUUM" wB97X_D_def2_TZVP_PCM = "wB97X-D/def2-TZVP/PCM" wB97X_D_def2_TZVP_SMD = "wB97X-D/def2-TZVP/SMD" wB97X_D_def2_TZVP_VACUUM = "wB97X-D/def2-TZVP/VACUUM" wB97X_V_6_31g_d_PCM = "wB97X-V/6-31g*/PCM" wB97X_V_6_31g_d_SMD = "wB97X-V/6-31g*/SMD" wB97X_V_6_31g_d_VACUUM = "wB97X-V/6-31g*/VACUUM" wB97X_V_def2_QZVPD_PCM = "wB97X-V/def2-QZVPD/PCM" wB97X_V_def2_QZVPD_SMD = "wB97X-V/def2-QZVPD/SMD" wB97X_V_def2_QZVPD_VACUUM = "wB97X-V/def2-QZVPD/VACUUM" wB97X_V_def2_QZVPPD_PCM = "wB97X-V/def2-QZVPPD/PCM" wB97X_V_def2_QZVPPD_SMD = "wB97X-V/def2-QZVPPD/SMD" wB97X_V_def2_QZVPPD_VACUUM = "wB97X-V/def2-QZVPPD/VACUUM" wB97X_V_def2_SVPD_PCM = "wB97X-V/def2-SVPD/PCM" wB97X_V_def2_SVPD_SMD = "wB97X-V/def2-SVPD/SMD" wB97X_V_def2_SVPD_VACUUM = "wB97X-V/def2-SVPD/VACUUM" wB97X_V_def2_TZVPD_PCM = "wB97X-V/def2-TZVPD/PCM" wB97X_V_def2_TZVPD_SMD = "wB97X-V/def2-TZVPD/SMD" wB97X_V_def2_TZVPD_VACUUM = "wB97X-V/def2-TZVPD/VACUUM" wB97X_V_def2_TZVPPD_PCM = "wB97X-V/def2-TZVPPD/PCM" wB97X_V_def2_TZVPPD_SMD = "wB97X-V/def2-TZVPPD/SMD" wB97X_V_def2_TZVPPD_VACUUM = "wB97X-V/def2-TZVPPD/VACUUM" wB97X_V_def2_TZVPP_PCM = "wB97X-V/def2-TZVPP/PCM" wB97X_V_def2_TZVPP_SMD = "wB97X-V/def2-TZVPP/SMD" wB97X_V_def2_TZVPP_VACUUM = "wB97X-V/def2-TZVPP/VACUUM" wB97X_V_def2_TZVP_PCM = "wB97X-V/def2-TZVP/PCM" wB97X_V_def2_TZVP_SMD = "wB97X-V/def2-TZVP/SMD" wB97X_V_def2_TZVP_VACUUM = "wB97X-V/def2-TZVP/VACUUM" class TaskType(ValueEnum): """Calculation task types for Q-Chem.""" Force = "Force" Frequency_Analysis = "Frequency Analysis" Frequency_Flattening_Geometry_Optimization = ( "Frequency Flattening Geometry Optimization" ) Frequency_Flattening_Transition_State_Geometry_Optimization = ( "Frequency Flattening Transition State Geometry Optimization" ) Geometry_Optimization = "Geometry Optimization" Single_Point = "Single Point" Transition_State_Geometry_Optimization = "Transition State Geometry Optimization" Unknown = "Unknown" class CalcType(ValueEnum): """Calculation types (LOT + task type) for Q-Chem.""" B3LYP_6_31g_d_PCM_Force = "B3LYP/6-31g*/PCM Force" B3LYP_6_31g_d_PCM_Frequency_Analysis = "B3LYP/6-31g*/PCM Frequency Analysis" B3LYP_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/6-31g*/PCM Frequency Flattening Geometry Optimization" ) B3LYP_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) B3LYP_6_31g_d_PCM_Geometry_Optimization = "B3LYP/6-31g*/PCM Geometry Optimization" B3LYP_6_31g_d_PCM_Single_Point = "B3LYP/6-31g*/PCM Single Point" B3LYP_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/PCM Transition State Geometry Optimization" ) B3LYP_6_31g_d_PCM_Unknown = "B3LYP/6-31g*/PCM Unknown" B3LYP_6_31g_d_SMD_Force = "B3LYP/6-31g*/SMD Force" B3LYP_6_31g_d_SMD_Frequency_Analysis = "B3LYP/6-31g*/SMD Frequency Analysis" B3LYP_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/6-31g*/SMD Frequency Flattening Geometry Optimization" ) B3LYP_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) B3LYP_6_31g_d_SMD_Geometry_Optimization = "B3LYP/6-31g*/SMD Geometry Optimization" B3LYP_6_31g_d_SMD_Single_Point = "B3LYP/6-31g*/SMD Single Point" B3LYP_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/SMD Transition State Geometry Optimization" ) B3LYP_6_31g_d_SMD_Unknown = "B3LYP/6-31g*/SMD Unknown" B3LYP_6_31g_d_VACUUM_Force = "B3LYP/6-31g*/VACUUM Force" B3LYP_6_31g_d_VACUUM_Frequency_Analysis = "B3LYP/6-31g*/VACUUM Frequency Analysis" B3LYP_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_6_31g_d_VACUUM_Geometry_Optimization = ( "B3LYP/6-31g*/VACUUM Geometry Optimization" ) B3LYP_6_31g_d_VACUUM_Single_Point = "B3LYP/6-31g*/VACUUM Single Point" B3LYP_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/VACUUM Transition State Geometry Optimization" ) B3LYP_6_31g_d_VACUUM_Unknown = "B3LYP/6-31g*/VACUUM Unknown" B3LYP_def2_QZVPD_PCM_Force = "B3LYP/def2-QZVPD/PCM Force" B3LYP_def2_QZVPD_PCM_Frequency_Analysis = "B3LYP/def2-QZVPD/PCM Frequency Analysis" B3LYP_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-QZVPD/PCM Geometry Optimization" ) B3LYP_def2_QZVPD_PCM_Single_Point = "B3LYP/def2-QZVPD/PCM Single Point" B3LYP_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/PCM Transition State Geometry Optimization" ) B3LYP_def2_QZVPD_PCM_Unknown = "B3LYP/def2-QZVPD/PCM Unknown" B3LYP_def2_QZVPD_SMD_Force = "B3LYP/def2-QZVPD/SMD Force" B3LYP_def2_QZVPD_SMD_Frequency_Analysis = "B3LYP/def2-QZVPD/SMD Frequency Analysis" B3LYP_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-QZVPD/SMD Geometry Optimization" ) B3LYP_def2_QZVPD_SMD_Single_Point = "B3LYP/def2-QZVPD/SMD Single Point" B3LYP_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/SMD Transition State Geometry Optimization" ) B3LYP_def2_QZVPD_SMD_Unknown = "B3LYP/def2-QZVPD/SMD Unknown" B3LYP_def2_QZVPD_VACUUM_Force = "B3LYP/def2-QZVPD/VACUUM Force" B3LYP_def2_QZVPD_VACUUM_Frequency_Analysis = ( "B3LYP/def2-QZVPD/VACUUM Frequency Analysis" ) B3LYP_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-QZVPD/VACUUM Geometry Optimization" ) B3LYP_def2_QZVPD_VACUUM_Single_Point = "B3LYP/def2-QZVPD/VACUUM Single Point" B3LYP_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_QZVPD_VACUUM_Unknown = "B3LYP/def2-QZVPD/VACUUM Unknown" B3LYP_def2_QZVPPD_PCM_Force = "B3LYP/def2-QZVPPD/PCM Force" B3LYP_def2_QZVPPD_PCM_Frequency_Analysis = ( "B3LYP/def2-QZVPPD/PCM Frequency Analysis" ) B3LYP_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPPD_PCM_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/PCM Geometry Optimization" ) B3LYP_def2_QZVPPD_PCM_Single_Point = "B3LYP/def2-QZVPPD/PCM Single Point" B3LYP_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/PCM Transition State Geometry Optimization" ) B3LYP_def2_QZVPPD_PCM_Unknown = "B3LYP/def2-QZVPPD/PCM Unknown" B3LYP_def2_QZVPPD_SMD_Force = "B3LYP/def2-QZVPPD/SMD Force" B3LYP_def2_QZVPPD_SMD_Frequency_Analysis = ( "B3LYP/def2-QZVPPD/SMD Frequency Analysis" ) B3LYP_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPPD_SMD_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/SMD Geometry Optimization" ) B3LYP_def2_QZVPPD_SMD_Single_Point = "B3LYP/def2-QZVPPD/SMD Single Point" B3LYP_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/SMD Transition State Geometry Optimization" ) B3LYP_def2_QZVPPD_SMD_Unknown = "B3LYP/def2-QZVPPD/SMD Unknown" B3LYP_def2_QZVPPD_VACUUM_Force = "B3LYP/def2-QZVPPD/VACUUM Force" B3LYP_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "B3LYP/def2-QZVPPD/VACUUM Frequency Analysis" ) B3LYP_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/VACUUM Geometry Optimization" ) B3LYP_def2_QZVPPD_VACUUM_Single_Point = "B3LYP/def2-QZVPPD/VACUUM Single Point" B3LYP_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_QZVPPD_VACUUM_Unknown = "B3LYP/def2-QZVPPD/VACUUM Unknown" B3LYP_def2_SVPD_PCM_Force = "B3LYP/def2-SVPD/PCM Force" B3LYP_def2_SVPD_PCM_Frequency_Analysis = "B3LYP/def2-SVPD/PCM Frequency Analysis" B3LYP_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_SVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-SVPD/PCM Geometry Optimization" ) B3LYP_def2_SVPD_PCM_Single_Point = "B3LYP/def2-SVPD/PCM Single Point" B3LYP_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/PCM Transition State Geometry Optimization" ) B3LYP_def2_SVPD_PCM_Unknown = "B3LYP/def2-SVPD/PCM Unknown" B3LYP_def2_SVPD_SMD_Force = "B3LYP/def2-SVPD/SMD Force" B3LYP_def2_SVPD_SMD_Frequency_Analysis = "B3LYP/def2-SVPD/SMD Frequency Analysis" B3LYP_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_SVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-SVPD/SMD Geometry Optimization" ) B3LYP_def2_SVPD_SMD_Single_Point = "B3LYP/def2-SVPD/SMD Single Point" B3LYP_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/SMD Transition State Geometry Optimization" ) B3LYP_def2_SVPD_SMD_Unknown = "B3LYP/def2-SVPD/SMD Unknown" B3LYP_def2_SVPD_VACUUM_Force = "B3LYP/def2-SVPD/VACUUM Force" B3LYP_def2_SVPD_VACUUM_Frequency_Analysis = ( "B3LYP/def2-SVPD/VACUUM Frequency Analysis" ) B3LYP_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_SVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-SVPD/VACUUM Geometry Optimization" ) B3LYP_def2_SVPD_VACUUM_Single_Point = "B3LYP/def2-SVPD/VACUUM Single Point" B3LYP_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_SVPD_VACUUM_Unknown = "B3LYP/def2-SVPD/VACUUM Unknown" B3LYP_def2_TZVPD_PCM_Force = "B3LYP/def2-TZVPD/PCM Force" B3LYP_def2_TZVPD_PCM_Frequency_Analysis = "B3LYP/def2-TZVPD/PCM Frequency Analysis" B3LYP_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPD/PCM Geometry Optimization" ) B3LYP_def2_TZVPD_PCM_Single_Point = "B3LYP/def2-TZVPD/PCM Single Point" B3LYP_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/PCM Transition State Geometry Optimization" ) B3LYP_def2_TZVPD_PCM_Unknown = "B3LYP/def2-TZVPD/PCM Unknown" B3LYP_def2_TZVPD_SMD_Force = "B3LYP/def2-TZVPD/SMD Force" B3LYP_def2_TZVPD_SMD_Frequency_Analysis = "B3LYP/def2-TZVPD/SMD Frequency Analysis" B3LYP_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPD/SMD Geometry Optimization" ) B3LYP_def2_TZVPD_SMD_Single_Point = "B3LYP/def2-TZVPD/SMD Single Point" B3LYP_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/SMD Transition State Geometry Optimization" ) B3LYP_def2_TZVPD_SMD_Unknown = "B3LYP/def2-TZVPD/SMD Unknown" B3LYP_def2_TZVPD_VACUUM_Force = "B3LYP/def2-TZVPD/VACUUM Force" B3LYP_def2_TZVPD_VACUUM_Frequency_Analysis = ( "B3LYP/def2-TZVPD/VACUUM Frequency Analysis" ) B3LYP_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPD/VACUUM Geometry Optimization" ) B3LYP_def2_TZVPD_VACUUM_Single_Point = "B3LYP/def2-TZVPD/VACUUM Single Point" B3LYP_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_TZVPD_VACUUM_Unknown = "B3LYP/def2-TZVPD/VACUUM Unknown" B3LYP_def2_TZVPPD_PCM_Force = "B3LYP/def2-TZVPPD/PCM Force" B3LYP_def2_TZVPPD_PCM_Frequency_Analysis = ( "B3LYP/def2-TZVPPD/PCM Frequency Analysis" ) B3LYP_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPPD_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/PCM Geometry Optimization" ) B3LYP_def2_TZVPPD_PCM_Single_Point = "B3LYP/def2-TZVPPD/PCM Single Point" B3LYP_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/PCM Transition State Geometry Optimization" ) B3LYP_def2_TZVPPD_PCM_Unknown = "B3LYP/def2-TZVPPD/PCM Unknown" B3LYP_def2_TZVPPD_SMD_Force = "B3LYP/def2-TZVPPD/SMD Force" B3LYP_def2_TZVPPD_SMD_Frequency_Analysis = ( "B3LYP/def2-TZVPPD/SMD Frequency Analysis" ) B3LYP_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPPD_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/SMD Geometry Optimization" ) B3LYP_def2_TZVPPD_SMD_Single_Point = "B3LYP/def2-TZVPPD/SMD Single Point" B3LYP_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/SMD Transition State Geometry Optimization" ) B3LYP_def2_TZVPPD_SMD_Unknown = "B3LYP/def2-TZVPPD/SMD Unknown" B3LYP_def2_TZVPPD_VACUUM_Force = "B3LYP/def2-TZVPPD/VACUUM Force" B3LYP_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "B3LYP/def2-TZVPPD/VACUUM Frequency Analysis" ) B3LYP_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/VACUUM Geometry Optimization" ) B3LYP_def2_TZVPPD_VACUUM_Single_Point = "B3LYP/def2-TZVPPD/VACUUM Single Point" B3LYP_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_TZVPPD_VACUUM_Unknown = "B3LYP/def2-TZVPPD/VACUUM Unknown" B3LYP_def2_TZVPP_PCM_Force = "B3LYP/def2-TZVPP/PCM Force" B3LYP_def2_TZVPP_PCM_Frequency_Analysis = "B3LYP/def2-TZVPP/PCM Frequency Analysis" B3LYP_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPP_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPP/PCM Geometry Optimization" ) B3LYP_def2_TZVPP_PCM_Single_Point = "B3LYP/def2-TZVPP/PCM Single Point" B3LYP_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/PCM Transition State Geometry Optimization" ) B3LYP_def2_TZVPP_PCM_Unknown = "B3LYP/def2-TZVPP/PCM Unknown" B3LYP_def2_TZVPP_SMD_Force = "B3LYP/def2-TZVPP/SMD Force" B3LYP_def2_TZVPP_SMD_Frequency_Analysis = "B3LYP/def2-TZVPP/SMD Frequency Analysis" B3LYP_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPP_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPP/SMD Geometry Optimization" ) B3LYP_def2_TZVPP_SMD_Single_Point = "B3LYP/def2-TZVPP/SMD Single Point" B3LYP_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/SMD Transition State Geometry Optimization" ) B3LYP_def2_TZVPP_SMD_Unknown = "B3LYP/def2-TZVPP/SMD Unknown" B3LYP_def2_TZVPP_VACUUM_Force = "B3LYP/def2-TZVPP/VACUUM Force" B3LYP_def2_TZVPP_VACUUM_Frequency_Analysis = ( "B3LYP/def2-TZVPP/VACUUM Frequency Analysis" ) B3LYP_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPP/VACUUM Geometry Optimization" ) B3LYP_def2_TZVPP_VACUUM_Single_Point = "B3LYP/def2-TZVPP/VACUUM Single Point" B3LYP_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_TZVPP_VACUUM_Unknown = "B3LYP/def2-TZVPP/VACUUM Unknown" B3LYP_def2_TZVP_PCM_Force = "B3LYP/def2-TZVP/PCM Force" B3LYP_def2_TZVP_PCM_Frequency_Analysis = "B3LYP/def2-TZVP/PCM Frequency Analysis" B3LYP_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVP_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVP/PCM Geometry Optimization" ) B3LYP_def2_TZVP_PCM_Single_Point = "B3LYP/def2-TZVP/PCM Single Point" B3LYP_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/PCM Transition State Geometry Optimization" ) B3LYP_def2_TZVP_PCM_Unknown = "B3LYP/def2-TZVP/PCM Unknown" B3LYP_def2_TZVP_SMD_Force = "B3LYP/def2-TZVP/SMD Force" B3LYP_def2_TZVP_SMD_Frequency_Analysis = "B3LYP/def2-TZVP/SMD Frequency Analysis" B3LYP_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVP_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVP/SMD Geometry Optimization" ) B3LYP_def2_TZVP_SMD_Single_Point = "B3LYP/def2-TZVP/SMD Single Point" B3LYP_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/SMD Transition State Geometry Optimization" ) B3LYP_def2_TZVP_SMD_Unknown = "B3LYP/def2-TZVP/SMD Unknown" B3LYP_def2_TZVP_VACUUM_Force = "B3LYP/def2-TZVP/VACUUM Force" B3LYP_def2_TZVP_VACUUM_Frequency_Analysis = ( "B3LYP/def2-TZVP/VACUUM Frequency Analysis" ) B3LYP_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B3LYP/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) B3LYP_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B3LYP/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" B3LYP_def2_TZVP_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVP/VACUUM Geometry Optimization" ) B3LYP_def2_TZVP_VACUUM_Single_Point = "B3LYP/def2-TZVP/VACUUM Single Point" B3LYP_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/VACUUM Transition State Geometry Optimization" ) B3LYP_def2_TZVP_VACUUM_Unknown = "B3LYP/def2-TZVP/VACUUM Unknown" B97M_V_6_31g_d_PCM_Force = "B97M-V/6-31g*/PCM Force" B97M_V_6_31g_d_PCM_Frequency_Analysis = "B97M-V/6-31g*/PCM Frequency Analysis" B97M_V_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/6-31g*/PCM Frequency Flattening Geometry Optimization" ) B97M_V_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) B97M_V_6_31g_d_PCM_Geometry_Optimization = "B97M-V/6-31g*/PCM Geometry Optimization" B97M_V_6_31g_d_PCM_Single_Point = "B97M-V/6-31g*/PCM Single Point" B97M_V_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/PCM Transition State Geometry Optimization" ) B97M_V_6_31g_d_PCM_Unknown = "B97M-V/6-31g*/PCM Unknown" B97M_V_6_31g_d_SMD_Force = "B97M-V/6-31g*/SMD Force" B97M_V_6_31g_d_SMD_Frequency_Analysis = "B97M-V/6-31g*/SMD Frequency Analysis" B97M_V_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/6-31g*/SMD Frequency Flattening Geometry Optimization" ) B97M_V_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) B97M_V_6_31g_d_SMD_Geometry_Optimization = "B97M-V/6-31g*/SMD Geometry Optimization" B97M_V_6_31g_d_SMD_Single_Point = "B97M-V/6-31g*/SMD Single Point" B97M_V_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/SMD Transition State Geometry Optimization" ) B97M_V_6_31g_d_SMD_Unknown = "B97M-V/6-31g*/SMD Unknown" B97M_V_6_31g_d_VACUUM_Force = "B97M-V/6-31g*/VACUUM Force" B97M_V_6_31g_d_VACUUM_Frequency_Analysis = "B97M-V/6-31g*/VACUUM Frequency Analysis" B97M_V_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_6_31g_d_VACUUM_Geometry_Optimization = ( "B97M-V/6-31g*/VACUUM Geometry Optimization" ) B97M_V_6_31g_d_VACUUM_Single_Point = "B97M-V/6-31g*/VACUUM Single Point" B97M_V_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/VACUUM Transition State Geometry Optimization" ) B97M_V_6_31g_d_VACUUM_Unknown = "B97M-V/6-31g*/VACUUM Unknown" B97M_V_def2_QZVPD_PCM_Force = "B97M-V/def2-QZVPD/PCM Force" B97M_V_def2_QZVPD_PCM_Frequency_Analysis = ( "B97M-V/def2-QZVPD/PCM Frequency Analysis" ) B97M_V_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-QZVPD/PCM Geometry Optimization" ) B97M_V_def2_QZVPD_PCM_Single_Point = "B97M-V/def2-QZVPD/PCM Single Point" B97M_V_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/PCM Transition State Geometry Optimization" ) B97M_V_def2_QZVPD_PCM_Unknown = "B97M-V/def2-QZVPD/PCM Unknown" B97M_V_def2_QZVPD_SMD_Force = "B97M-V/def2-QZVPD/SMD Force" B97M_V_def2_QZVPD_SMD_Frequency_Analysis = ( "B97M-V/def2-QZVPD/SMD Frequency Analysis" ) B97M_V_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-QZVPD/SMD Geometry Optimization" ) B97M_V_def2_QZVPD_SMD_Single_Point = "B97M-V/def2-QZVPD/SMD Single Point" B97M_V_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/SMD Transition State Geometry Optimization" ) B97M_V_def2_QZVPD_SMD_Unknown = "B97M-V/def2-QZVPD/SMD Unknown" B97M_V_def2_QZVPD_VACUUM_Force = "B97M-V/def2-QZVPD/VACUUM Force" B97M_V_def2_QZVPD_VACUUM_Frequency_Analysis = ( "B97M-V/def2-QZVPD/VACUUM Frequency Analysis" ) B97M_V_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-QZVPD/VACUUM Geometry Optimization" ) B97M_V_def2_QZVPD_VACUUM_Single_Point = "B97M-V/def2-QZVPD/VACUUM Single Point" B97M_V_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_QZVPD_VACUUM_Unknown = "B97M-V/def2-QZVPD/VACUUM Unknown" B97M_V_def2_QZVPPD_PCM_Force = "B97M-V/def2-QZVPPD/PCM Force" B97M_V_def2_QZVPPD_PCM_Frequency_Analysis = ( "B97M-V/def2-QZVPPD/PCM Frequency Analysis" ) B97M_V_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/PCM Geometry Optimization" ) B97M_V_def2_QZVPPD_PCM_Single_Point = "B97M-V/def2-QZVPPD/PCM Single Point" B97M_V_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/PCM Transition State Geometry Optimization" ) B97M_V_def2_QZVPPD_PCM_Unknown = "B97M-V/def2-QZVPPD/PCM Unknown" B97M_V_def2_QZVPPD_SMD_Force = "B97M-V/def2-QZVPPD/SMD Force" B97M_V_def2_QZVPPD_SMD_Frequency_Analysis = ( "B97M-V/def2-QZVPPD/SMD Frequency Analysis" ) B97M_V_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/SMD Geometry Optimization" ) B97M_V_def2_QZVPPD_SMD_Single_Point = "B97M-V/def2-QZVPPD/SMD Single Point" B97M_V_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/SMD Transition State Geometry Optimization" ) B97M_V_def2_QZVPPD_SMD_Unknown = "B97M-V/def2-QZVPPD/SMD Unknown" B97M_V_def2_QZVPPD_VACUUM_Force = "B97M-V/def2-QZVPPD/VACUUM Force" B97M_V_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "B97M-V/def2-QZVPPD/VACUUM Frequency Analysis" ) B97M_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/VACUUM Geometry Optimization" ) B97M_V_def2_QZVPPD_VACUUM_Single_Point = "B97M-V/def2-QZVPPD/VACUUM Single Point" B97M_V_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_QZVPPD_VACUUM_Unknown = "B97M-V/def2-QZVPPD/VACUUM Unknown" B97M_V_def2_SVPD_PCM_Force = "B97M-V/def2-SVPD/PCM Force" B97M_V_def2_SVPD_PCM_Frequency_Analysis = "B97M-V/def2-SVPD/PCM Frequency Analysis" B97M_V_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_SVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-SVPD/PCM Geometry Optimization" ) B97M_V_def2_SVPD_PCM_Single_Point = "B97M-V/def2-SVPD/PCM Single Point" B97M_V_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/PCM Transition State Geometry Optimization" ) B97M_V_def2_SVPD_PCM_Unknown = "B97M-V/def2-SVPD/PCM Unknown" B97M_V_def2_SVPD_SMD_Force = "B97M-V/def2-SVPD/SMD Force" B97M_V_def2_SVPD_SMD_Frequency_Analysis = "B97M-V/def2-SVPD/SMD Frequency Analysis" B97M_V_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_SVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-SVPD/SMD Geometry Optimization" ) B97M_V_def2_SVPD_SMD_Single_Point = "B97M-V/def2-SVPD/SMD Single Point" B97M_V_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/SMD Transition State Geometry Optimization" ) B97M_V_def2_SVPD_SMD_Unknown = "B97M-V/def2-SVPD/SMD Unknown" B97M_V_def2_SVPD_VACUUM_Force = "B97M-V/def2-SVPD/VACUUM Force" B97M_V_def2_SVPD_VACUUM_Frequency_Analysis = ( "B97M-V/def2-SVPD/VACUUM Frequency Analysis" ) B97M_V_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-SVPD/VACUUM Geometry Optimization" ) B97M_V_def2_SVPD_VACUUM_Single_Point = "B97M-V/def2-SVPD/VACUUM Single Point" B97M_V_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_SVPD_VACUUM_Unknown = "B97M-V/def2-SVPD/VACUUM Unknown" B97M_V_def2_TZVPD_PCM_Force = "B97M-V/def2-TZVPD/PCM Force" B97M_V_def2_TZVPD_PCM_Frequency_Analysis = ( "B97M-V/def2-TZVPD/PCM Frequency Analysis" ) B97M_V_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPD/PCM Geometry Optimization" ) B97M_V_def2_TZVPD_PCM_Single_Point = "B97M-V/def2-TZVPD/PCM Single Point" B97M_V_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/PCM Transition State Geometry Optimization" ) B97M_V_def2_TZVPD_PCM_Unknown = "B97M-V/def2-TZVPD/PCM Unknown" B97M_V_def2_TZVPD_SMD_Force = "B97M-V/def2-TZVPD/SMD Force" B97M_V_def2_TZVPD_SMD_Frequency_Analysis = ( "B97M-V/def2-TZVPD/SMD Frequency Analysis" ) B97M_V_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPD/SMD Geometry Optimization" ) B97M_V_def2_TZVPD_SMD_Single_Point = "B97M-V/def2-TZVPD/SMD Single Point" B97M_V_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/SMD Transition State Geometry Optimization" ) B97M_V_def2_TZVPD_SMD_Unknown = "B97M-V/def2-TZVPD/SMD Unknown" B97M_V_def2_TZVPD_VACUUM_Force = "B97M-V/def2-TZVPD/VACUUM Force" B97M_V_def2_TZVPD_VACUUM_Frequency_Analysis = ( "B97M-V/def2-TZVPD/VACUUM Frequency Analysis" ) B97M_V_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPD/VACUUM Geometry Optimization" ) B97M_V_def2_TZVPD_VACUUM_Single_Point = "B97M-V/def2-TZVPD/VACUUM Single Point" B97M_V_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_TZVPD_VACUUM_Unknown = "B97M-V/def2-TZVPD/VACUUM Unknown" B97M_V_def2_TZVPPD_PCM_Force = "B97M-V/def2-TZVPPD/PCM Force" B97M_V_def2_TZVPPD_PCM_Frequency_Analysis = ( "B97M-V/def2-TZVPPD/PCM Frequency Analysis" ) B97M_V_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/PCM Geometry Optimization" ) B97M_V_def2_TZVPPD_PCM_Single_Point = "B97M-V/def2-TZVPPD/PCM Single Point" B97M_V_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/PCM Transition State Geometry Optimization" ) B97M_V_def2_TZVPPD_PCM_Unknown = "B97M-V/def2-TZVPPD/PCM Unknown" B97M_V_def2_TZVPPD_SMD_Force = "B97M-V/def2-TZVPPD/SMD Force" B97M_V_def2_TZVPPD_SMD_Frequency_Analysis = ( "B97M-V/def2-TZVPPD/SMD Frequency Analysis" ) B97M_V_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/SMD Geometry Optimization" ) B97M_V_def2_TZVPPD_SMD_Single_Point = "B97M-V/def2-TZVPPD/SMD Single Point" B97M_V_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/SMD Transition State Geometry Optimization" ) B97M_V_def2_TZVPPD_SMD_Unknown = "B97M-V/def2-TZVPPD/SMD Unknown" B97M_V_def2_TZVPPD_VACUUM_Force = "B97M-V/def2-TZVPPD/VACUUM Force" B97M_V_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "B97M-V/def2-TZVPPD/VACUUM Frequency Analysis" ) B97M_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/VACUUM Geometry Optimization" ) B97M_V_def2_TZVPPD_VACUUM_Single_Point = "B97M-V/def2-TZVPPD/VACUUM Single Point" B97M_V_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_TZVPPD_VACUUM_Unknown = "B97M-V/def2-TZVPPD/VACUUM Unknown" B97M_V_def2_TZVPP_PCM_Force = "B97M-V/def2-TZVPP/PCM Force" B97M_V_def2_TZVPP_PCM_Frequency_Analysis = ( "B97M-V/def2-TZVPP/PCM Frequency Analysis" ) B97M_V_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPP_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPP/PCM Geometry Optimization" ) B97M_V_def2_TZVPP_PCM_Single_Point = "B97M-V/def2-TZVPP/PCM Single Point" B97M_V_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/PCM Transition State Geometry Optimization" ) B97M_V_def2_TZVPP_PCM_Unknown = "B97M-V/def2-TZVPP/PCM Unknown" B97M_V_def2_TZVPP_SMD_Force = "B97M-V/def2-TZVPP/SMD Force" B97M_V_def2_TZVPP_SMD_Frequency_Analysis = ( "B97M-V/def2-TZVPP/SMD Frequency Analysis" ) B97M_V_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPP_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPP/SMD Geometry Optimization" ) B97M_V_def2_TZVPP_SMD_Single_Point = "B97M-V/def2-TZVPP/SMD Single Point" B97M_V_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/SMD Transition State Geometry Optimization" ) B97M_V_def2_TZVPP_SMD_Unknown = "B97M-V/def2-TZVPP/SMD Unknown" B97M_V_def2_TZVPP_VACUUM_Force = "B97M-V/def2-TZVPP/VACUUM Force" B97M_V_def2_TZVPP_VACUUM_Frequency_Analysis = ( "B97M-V/def2-TZVPP/VACUUM Frequency Analysis" ) B97M_V_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPP/VACUUM Geometry Optimization" ) B97M_V_def2_TZVPP_VACUUM_Single_Point = "B97M-V/def2-TZVPP/VACUUM Single Point" B97M_V_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_TZVPP_VACUUM_Unknown = "B97M-V/def2-TZVPP/VACUUM Unknown" B97M_V_def2_TZVP_PCM_Force = "B97M-V/def2-TZVP/PCM Force" B97M_V_def2_TZVP_PCM_Frequency_Analysis = "B97M-V/def2-TZVP/PCM Frequency Analysis" B97M_V_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVP_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVP/PCM Geometry Optimization" ) B97M_V_def2_TZVP_PCM_Single_Point = "B97M-V/def2-TZVP/PCM Single Point" B97M_V_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/PCM Transition State Geometry Optimization" ) B97M_V_def2_TZVP_PCM_Unknown = "B97M-V/def2-TZVP/PCM Unknown" B97M_V_def2_TZVP_SMD_Force = "B97M-V/def2-TZVP/SMD Force" B97M_V_def2_TZVP_SMD_Frequency_Analysis = "B97M-V/def2-TZVP/SMD Frequency Analysis" B97M_V_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVP_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVP/SMD Geometry Optimization" ) B97M_V_def2_TZVP_SMD_Single_Point = "B97M-V/def2-TZVP/SMD Single Point" B97M_V_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/SMD Transition State Geometry Optimization" ) B97M_V_def2_TZVP_SMD_Unknown = "B97M-V/def2-TZVP/SMD Unknown" B97M_V_def2_TZVP_VACUUM_Force = "B97M-V/def2-TZVP/VACUUM Force" B97M_V_def2_TZVP_VACUUM_Frequency_Analysis = ( "B97M-V/def2-TZVP/VACUUM Frequency Analysis" ) B97M_V_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-V/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) B97M_V_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-V/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVP/VACUUM Geometry Optimization" ) B97M_V_def2_TZVP_VACUUM_Single_Point = "B97M-V/def2-TZVP/VACUUM Single Point" B97M_V_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/VACUUM Transition State Geometry Optimization" ) B97M_V_def2_TZVP_VACUUM_Unknown = "B97M-V/def2-TZVP/VACUUM Unknown" B97M_rV_6_31g_d_PCM_Force = "B97M-rV/6-31g*/PCM Force" B97M_rV_6_31g_d_PCM_Frequency_Analysis = "B97M-rV/6-31g*/PCM Frequency Analysis" B97M_rV_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) B97M_rV_6_31g_d_PCM_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Geometry Optimization" ) B97M_rV_6_31g_d_PCM_Single_Point = "B97M-rV/6-31g*/PCM Single Point" B97M_rV_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Transition State Geometry Optimization" ) B97M_rV_6_31g_d_PCM_Unknown = "B97M-rV/6-31g*/PCM Unknown" B97M_rV_6_31g_d_SMD_Force = "B97M-rV/6-31g*/SMD Force" B97M_rV_6_31g_d_SMD_Frequency_Analysis = "B97M-rV/6-31g*/SMD Frequency Analysis" B97M_rV_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) B97M_rV_6_31g_d_SMD_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Geometry Optimization" ) B97M_rV_6_31g_d_SMD_Single_Point = "B97M-rV/6-31g*/SMD Single Point" B97M_rV_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Transition State Geometry Optimization" ) B97M_rV_6_31g_d_SMD_Unknown = "B97M-rV/6-31g*/SMD Unknown" B97M_rV_6_31g_d_VACUUM_Force = "B97M-rV/6-31g*/VACUUM Force" B97M_rV_6_31g_d_VACUUM_Frequency_Analysis = ( "B97M-rV/6-31g*/VACUUM Frequency Analysis" ) B97M_rV_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_6_31g_d_VACUUM_Geometry_Optimization = ( "B97M-rV/6-31g*/VACUUM Geometry Optimization" ) B97M_rV_6_31g_d_VACUUM_Single_Point = "B97M-rV/6-31g*/VACUUM Single Point" B97M_rV_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/VACUUM Transition State Geometry Optimization" ) B97M_rV_6_31g_d_VACUUM_Unknown = "B97M-rV/6-31g*/VACUUM Unknown" B97M_rV_def2_QZVPD_PCM_Force = "B97M-rV/def2-QZVPD/PCM Force" B97M_rV_def2_QZVPD_PCM_Frequency_Analysis = ( "B97M-rV/def2-QZVPD/PCM Frequency Analysis" ) B97M_rV_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/PCM Geometry Optimization" ) B97M_rV_def2_QZVPD_PCM_Single_Point = "B97M-rV/def2-QZVPD/PCM Single Point" B97M_rV_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/PCM Transition State Geometry Optimization" ) B97M_rV_def2_QZVPD_PCM_Unknown = "B97M-rV/def2-QZVPD/PCM Unknown" B97M_rV_def2_QZVPD_SMD_Force = "B97M-rV/def2-QZVPD/SMD Force" B97M_rV_def2_QZVPD_SMD_Frequency_Analysis = ( "B97M-rV/def2-QZVPD/SMD Frequency Analysis" ) B97M_rV_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/SMD Geometry Optimization" ) B97M_rV_def2_QZVPD_SMD_Single_Point = "B97M-rV/def2-QZVPD/SMD Single Point" B97M_rV_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/SMD Transition State Geometry Optimization" ) B97M_rV_def2_QZVPD_SMD_Unknown = "B97M-rV/def2-QZVPD/SMD Unknown" B97M_rV_def2_QZVPD_VACUUM_Force = "B97M-rV/def2-QZVPD/VACUUM Force" B97M_rV_def2_QZVPD_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-QZVPD/VACUUM Frequency Analysis" ) B97M_rV_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/VACUUM Geometry Optimization" ) B97M_rV_def2_QZVPD_VACUUM_Single_Point = "B97M-rV/def2-QZVPD/VACUUM Single Point" B97M_rV_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_QZVPD_VACUUM_Unknown = "B97M-rV/def2-QZVPD/VACUUM Unknown" B97M_rV_def2_QZVPPD_PCM_Force = "B97M-rV/def2-QZVPPD/PCM Force" B97M_rV_def2_QZVPPD_PCM_Frequency_Analysis = ( "B97M-rV/def2-QZVPPD/PCM Frequency Analysis" ) B97M_rV_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/PCM Geometry Optimization" ) B97M_rV_def2_QZVPPD_PCM_Single_Point = "B97M-rV/def2-QZVPPD/PCM Single Point" B97M_rV_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/PCM Transition State Geometry Optimization" ) B97M_rV_def2_QZVPPD_PCM_Unknown = "B97M-rV/def2-QZVPPD/PCM Unknown" B97M_rV_def2_QZVPPD_SMD_Force = "B97M-rV/def2-QZVPPD/SMD Force" B97M_rV_def2_QZVPPD_SMD_Frequency_Analysis = ( "B97M-rV/def2-QZVPPD/SMD Frequency Analysis" ) B97M_rV_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/SMD Geometry Optimization" ) B97M_rV_def2_QZVPPD_SMD_Single_Point = "B97M-rV/def2-QZVPPD/SMD Single Point" B97M_rV_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/SMD Transition State Geometry Optimization" ) B97M_rV_def2_QZVPPD_SMD_Unknown = "B97M-rV/def2-QZVPPD/SMD Unknown" B97M_rV_def2_QZVPPD_VACUUM_Force = "B97M-rV/def2-QZVPPD/VACUUM Force" B97M_rV_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-QZVPPD/VACUUM Frequency Analysis" ) B97M_rV_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/VACUUM Geometry Optimization" ) B97M_rV_def2_QZVPPD_VACUUM_Single_Point = "B97M-rV/def2-QZVPPD/VACUUM Single Point" B97M_rV_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_QZVPPD_VACUUM_Unknown = "B97M-rV/def2-QZVPPD/VACUUM Unknown" B97M_rV_def2_SVPD_PCM_Force = "B97M-rV/def2-SVPD/PCM Force" B97M_rV_def2_SVPD_PCM_Frequency_Analysis = ( "B97M-rV/def2-SVPD/PCM Frequency Analysis" ) B97M_rV_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_SVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-SVPD/PCM Geometry Optimization" ) B97M_rV_def2_SVPD_PCM_Single_Point = "B97M-rV/def2-SVPD/PCM Single Point" B97M_rV_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/PCM Transition State Geometry Optimization" ) B97M_rV_def2_SVPD_PCM_Unknown = "B97M-rV/def2-SVPD/PCM Unknown" B97M_rV_def2_SVPD_SMD_Force = "B97M-rV/def2-SVPD/SMD Force" B97M_rV_def2_SVPD_SMD_Frequency_Analysis = ( "B97M-rV/def2-SVPD/SMD Frequency Analysis" ) B97M_rV_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_SVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-SVPD/SMD Geometry Optimization" ) B97M_rV_def2_SVPD_SMD_Single_Point = "B97M-rV/def2-SVPD/SMD Single Point" B97M_rV_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/SMD Transition State Geometry Optimization" ) B97M_rV_def2_SVPD_SMD_Unknown = "B97M-rV/def2-SVPD/SMD Unknown" B97M_rV_def2_SVPD_VACUUM_Force = "B97M-rV/def2-SVPD/VACUUM Force" B97M_rV_def2_SVPD_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-SVPD/VACUUM Frequency Analysis" ) B97M_rV_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-SVPD/VACUUM Geometry Optimization" ) B97M_rV_def2_SVPD_VACUUM_Single_Point = "B97M-rV/def2-SVPD/VACUUM Single Point" B97M_rV_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_SVPD_VACUUM_Unknown = "B97M-rV/def2-SVPD/VACUUM Unknown" B97M_rV_def2_TZVPD_PCM_Force = "B97M-rV/def2-TZVPD/PCM Force" B97M_rV_def2_TZVPD_PCM_Frequency_Analysis = ( "B97M-rV/def2-TZVPD/PCM Frequency Analysis" ) B97M_rV_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/PCM Geometry Optimization" ) B97M_rV_def2_TZVPD_PCM_Single_Point = "B97M-rV/def2-TZVPD/PCM Single Point" B97M_rV_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/PCM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPD_PCM_Unknown = "B97M-rV/def2-TZVPD/PCM Unknown" B97M_rV_def2_TZVPD_SMD_Force = "B97M-rV/def2-TZVPD/SMD Force" B97M_rV_def2_TZVPD_SMD_Frequency_Analysis = ( "B97M-rV/def2-TZVPD/SMD Frequency Analysis" ) B97M_rV_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/SMD Geometry Optimization" ) B97M_rV_def2_TZVPD_SMD_Single_Point = "B97M-rV/def2-TZVPD/SMD Single Point" B97M_rV_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/SMD Transition State Geometry Optimization" ) B97M_rV_def2_TZVPD_SMD_Unknown = "B97M-rV/def2-TZVPD/SMD Unknown" B97M_rV_def2_TZVPD_VACUUM_Force = "B97M-rV/def2-TZVPD/VACUUM Force" B97M_rV_def2_TZVPD_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-TZVPD/VACUUM Frequency Analysis" ) B97M_rV_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/VACUUM Geometry Optimization" ) B97M_rV_def2_TZVPD_VACUUM_Single_Point = "B97M-rV/def2-TZVPD/VACUUM Single Point" B97M_rV_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPD_VACUUM_Unknown = "B97M-rV/def2-TZVPD/VACUUM Unknown" B97M_rV_def2_TZVPPD_PCM_Force = "B97M-rV/def2-TZVPPD/PCM Force" B97M_rV_def2_TZVPPD_PCM_Frequency_Analysis = ( "B97M-rV/def2-TZVPPD/PCM Frequency Analysis" ) B97M_rV_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/PCM Geometry Optimization" ) B97M_rV_def2_TZVPPD_PCM_Single_Point = "B97M-rV/def2-TZVPPD/PCM Single Point" B97M_rV_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/PCM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPPD_PCM_Unknown = "B97M-rV/def2-TZVPPD/PCM Unknown" B97M_rV_def2_TZVPPD_SMD_Force = "B97M-rV/def2-TZVPPD/SMD Force" B97M_rV_def2_TZVPPD_SMD_Frequency_Analysis = ( "B97M-rV/def2-TZVPPD/SMD Frequency Analysis" ) B97M_rV_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/SMD Geometry Optimization" ) B97M_rV_def2_TZVPPD_SMD_Single_Point = "B97M-rV/def2-TZVPPD/SMD Single Point" B97M_rV_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/SMD Transition State Geometry Optimization" ) B97M_rV_def2_TZVPPD_SMD_Unknown = "B97M-rV/def2-TZVPPD/SMD Unknown" B97M_rV_def2_TZVPPD_VACUUM_Force = "B97M-rV/def2-TZVPPD/VACUUM Force" B97M_rV_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-TZVPPD/VACUUM Frequency Analysis" ) B97M_rV_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/VACUUM Geometry Optimization" ) B97M_rV_def2_TZVPPD_VACUUM_Single_Point = "B97M-rV/def2-TZVPPD/VACUUM Single Point" B97M_rV_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPPD_VACUUM_Unknown = "B97M-rV/def2-TZVPPD/VACUUM Unknown" B97M_rV_def2_TZVPP_PCM_Force = "B97M-rV/def2-TZVPP/PCM Force" B97M_rV_def2_TZVPP_PCM_Frequency_Analysis = ( "B97M-rV/def2-TZVPP/PCM Frequency Analysis" ) B97M_rV_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPP_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/PCM Geometry Optimization" ) B97M_rV_def2_TZVPP_PCM_Single_Point = "B97M-rV/def2-TZVPP/PCM Single Point" B97M_rV_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/PCM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPP_PCM_Unknown = "B97M-rV/def2-TZVPP/PCM Unknown" B97M_rV_def2_TZVPP_SMD_Force = "B97M-rV/def2-TZVPP/SMD Force" B97M_rV_def2_TZVPP_SMD_Frequency_Analysis = ( "B97M-rV/def2-TZVPP/SMD Frequency Analysis" ) B97M_rV_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPP_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/SMD Geometry Optimization" ) B97M_rV_def2_TZVPP_SMD_Single_Point = "B97M-rV/def2-TZVPP/SMD Single Point" B97M_rV_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/SMD Transition State Geometry Optimization" ) B97M_rV_def2_TZVPP_SMD_Unknown = "B97M-rV/def2-TZVPP/SMD Unknown" B97M_rV_def2_TZVPP_VACUUM_Force = "B97M-rV/def2-TZVPP/VACUUM Force" B97M_rV_def2_TZVPP_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-TZVPP/VACUUM Frequency Analysis" ) B97M_rV_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/VACUUM Geometry Optimization" ) B97M_rV_def2_TZVPP_VACUUM_Single_Point = "B97M-rV/def2-TZVPP/VACUUM Single Point" B97M_rV_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_TZVPP_VACUUM_Unknown = "B97M-rV/def2-TZVPP/VACUUM Unknown" B97M_rV_def2_TZVP_PCM_Force = "B97M-rV/def2-TZVP/PCM Force" B97M_rV_def2_TZVP_PCM_Frequency_Analysis = ( "B97M-rV/def2-TZVP/PCM Frequency Analysis" ) B97M_rV_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVP_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVP/PCM Geometry Optimization" ) B97M_rV_def2_TZVP_PCM_Single_Point = "B97M-rV/def2-TZVP/PCM Single Point" B97M_rV_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/PCM Transition State Geometry Optimization" ) B97M_rV_def2_TZVP_PCM_Unknown = "B97M-rV/def2-TZVP/PCM Unknown" B97M_rV_def2_TZVP_SMD_Force = "B97M-rV/def2-TZVP/SMD Force" B97M_rV_def2_TZVP_SMD_Frequency_Analysis = ( "B97M-rV/def2-TZVP/SMD Frequency Analysis" ) B97M_rV_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVP_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVP/SMD Geometry Optimization" ) B97M_rV_def2_TZVP_SMD_Single_Point = "B97M-rV/def2-TZVP/SMD Single Point" B97M_rV_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/SMD Transition State Geometry Optimization" ) B97M_rV_def2_TZVP_SMD_Unknown = "B97M-rV/def2-TZVP/SMD Unknown" B97M_rV_def2_TZVP_VACUUM_Force = "B97M-rV/def2-TZVP/VACUUM Force" B97M_rV_def2_TZVP_VACUUM_Frequency_Analysis = ( "B97M-rV/def2-TZVP/VACUUM Frequency Analysis" ) B97M_rV_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97M-rV/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) B97M_rV_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97M-rV/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97M_rV_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVP/VACUUM Geometry Optimization" ) B97M_rV_def2_TZVP_VACUUM_Single_Point = "B97M-rV/def2-TZVP/VACUUM Single Point" B97M_rV_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/VACUUM Transition State Geometry Optimization" ) B97M_rV_def2_TZVP_VACUUM_Unknown = "B97M-rV/def2-TZVP/VACUUM Unknown" B97_D3_6_31g_d_PCM_Force = "B97-D3/6-31g*/PCM Force" B97_D3_6_31g_d_PCM_Frequency_Analysis = "B97-D3/6-31g*/PCM Frequency Analysis" B97_D3_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/6-31g*/PCM Frequency Flattening Geometry Optimization" ) B97_D3_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) B97_D3_6_31g_d_PCM_Geometry_Optimization = "B97-D3/6-31g*/PCM Geometry Optimization" B97_D3_6_31g_d_PCM_Single_Point = "B97-D3/6-31g*/PCM Single Point" B97_D3_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/PCM Transition State Geometry Optimization" ) B97_D3_6_31g_d_PCM_Unknown = "B97-D3/6-31g*/PCM Unknown" B97_D3_6_31g_d_SMD_Force = "B97-D3/6-31g*/SMD Force" B97_D3_6_31g_d_SMD_Frequency_Analysis = "B97-D3/6-31g*/SMD Frequency Analysis" B97_D3_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/6-31g*/SMD Frequency Flattening Geometry Optimization" ) B97_D3_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) B97_D3_6_31g_d_SMD_Geometry_Optimization = "B97-D3/6-31g*/SMD Geometry Optimization" B97_D3_6_31g_d_SMD_Single_Point = "B97-D3/6-31g*/SMD Single Point" B97_D3_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/SMD Transition State Geometry Optimization" ) B97_D3_6_31g_d_SMD_Unknown = "B97-D3/6-31g*/SMD Unknown" B97_D3_6_31g_d_VACUUM_Force = "B97-D3/6-31g*/VACUUM Force" B97_D3_6_31g_d_VACUUM_Frequency_Analysis = "B97-D3/6-31g*/VACUUM Frequency Analysis" B97_D3_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_6_31g_d_VACUUM_Geometry_Optimization = ( "B97-D3/6-31g*/VACUUM Geometry Optimization" ) B97_D3_6_31g_d_VACUUM_Single_Point = "B97-D3/6-31g*/VACUUM Single Point" B97_D3_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/VACUUM Transition State Geometry Optimization" ) B97_D3_6_31g_d_VACUUM_Unknown = "B97-D3/6-31g*/VACUUM Unknown" B97_D3_def2_QZVPD_PCM_Force = "B97-D3/def2-QZVPD/PCM Force" B97_D3_def2_QZVPD_PCM_Frequency_Analysis = ( "B97-D3/def2-QZVPD/PCM Frequency Analysis" ) B97_D3_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-QZVPD/PCM Geometry Optimization" ) B97_D3_def2_QZVPD_PCM_Single_Point = "B97-D3/def2-QZVPD/PCM Single Point" B97_D3_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/PCM Transition State Geometry Optimization" ) B97_D3_def2_QZVPD_PCM_Unknown = "B97-D3/def2-QZVPD/PCM Unknown" B97_D3_def2_QZVPD_SMD_Force = "B97-D3/def2-QZVPD/SMD Force" B97_D3_def2_QZVPD_SMD_Frequency_Analysis = ( "B97-D3/def2-QZVPD/SMD Frequency Analysis" ) B97_D3_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-QZVPD/SMD Geometry Optimization" ) B97_D3_def2_QZVPD_SMD_Single_Point = "B97-D3/def2-QZVPD/SMD Single Point" B97_D3_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/SMD Transition State Geometry Optimization" ) B97_D3_def2_QZVPD_SMD_Unknown = "B97-D3/def2-QZVPD/SMD Unknown" B97_D3_def2_QZVPD_VACUUM_Force = "B97-D3/def2-QZVPD/VACUUM Force" B97_D3_def2_QZVPD_VACUUM_Frequency_Analysis = ( "B97-D3/def2-QZVPD/VACUUM Frequency Analysis" ) B97_D3_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-QZVPD/VACUUM Geometry Optimization" ) B97_D3_def2_QZVPD_VACUUM_Single_Point = "B97-D3/def2-QZVPD/VACUUM Single Point" B97_D3_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_QZVPD_VACUUM_Unknown = "B97-D3/def2-QZVPD/VACUUM Unknown" B97_D3_def2_QZVPPD_PCM_Force = "B97-D3/def2-QZVPPD/PCM Force" B97_D3_def2_QZVPPD_PCM_Frequency_Analysis = ( "B97-D3/def2-QZVPPD/PCM Frequency Analysis" ) B97_D3_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/PCM Geometry Optimization" ) B97_D3_def2_QZVPPD_PCM_Single_Point = "B97-D3/def2-QZVPPD/PCM Single Point" B97_D3_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/PCM Transition State Geometry Optimization" ) B97_D3_def2_QZVPPD_PCM_Unknown = "B97-D3/def2-QZVPPD/PCM Unknown" B97_D3_def2_QZVPPD_SMD_Force = "B97-D3/def2-QZVPPD/SMD Force" B97_D3_def2_QZVPPD_SMD_Frequency_Analysis = ( "B97-D3/def2-QZVPPD/SMD Frequency Analysis" ) B97_D3_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/SMD Geometry Optimization" ) B97_D3_def2_QZVPPD_SMD_Single_Point = "B97-D3/def2-QZVPPD/SMD Single Point" B97_D3_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/SMD Transition State Geometry Optimization" ) B97_D3_def2_QZVPPD_SMD_Unknown = "B97-D3/def2-QZVPPD/SMD Unknown" B97_D3_def2_QZVPPD_VACUUM_Force = "B97-D3/def2-QZVPPD/VACUUM Force" B97_D3_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "B97-D3/def2-QZVPPD/VACUUM Frequency Analysis" ) B97_D3_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/VACUUM Geometry Optimization" ) B97_D3_def2_QZVPPD_VACUUM_Single_Point = "B97-D3/def2-QZVPPD/VACUUM Single Point" B97_D3_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_QZVPPD_VACUUM_Unknown = "B97-D3/def2-QZVPPD/VACUUM Unknown" B97_D3_def2_SVPD_PCM_Force = "B97-D3/def2-SVPD/PCM Force" B97_D3_def2_SVPD_PCM_Frequency_Analysis = "B97-D3/def2-SVPD/PCM Frequency Analysis" B97_D3_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_SVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-SVPD/PCM Geometry Optimization" ) B97_D3_def2_SVPD_PCM_Single_Point = "B97-D3/def2-SVPD/PCM Single Point" B97_D3_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/PCM Transition State Geometry Optimization" ) B97_D3_def2_SVPD_PCM_Unknown = "B97-D3/def2-SVPD/PCM Unknown" B97_D3_def2_SVPD_SMD_Force = "B97-D3/def2-SVPD/SMD Force" B97_D3_def2_SVPD_SMD_Frequency_Analysis = "B97-D3/def2-SVPD/SMD Frequency Analysis" B97_D3_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_SVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-SVPD/SMD Geometry Optimization" ) B97_D3_def2_SVPD_SMD_Single_Point = "B97-D3/def2-SVPD/SMD Single Point" B97_D3_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/SMD Transition State Geometry Optimization" ) B97_D3_def2_SVPD_SMD_Unknown = "B97-D3/def2-SVPD/SMD Unknown" B97_D3_def2_SVPD_VACUUM_Force = "B97-D3/def2-SVPD/VACUUM Force" B97_D3_def2_SVPD_VACUUM_Frequency_Analysis = ( "B97-D3/def2-SVPD/VACUUM Frequency Analysis" ) B97_D3_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-SVPD/VACUUM Geometry Optimization" ) B97_D3_def2_SVPD_VACUUM_Single_Point = "B97-D3/def2-SVPD/VACUUM Single Point" B97_D3_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_SVPD_VACUUM_Unknown = "B97-D3/def2-SVPD/VACUUM Unknown" B97_D3_def2_TZVPD_PCM_Force = "B97-D3/def2-TZVPD/PCM Force" B97_D3_def2_TZVPD_PCM_Frequency_Analysis = ( "B97-D3/def2-TZVPD/PCM Frequency Analysis" ) B97_D3_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPD/PCM Geometry Optimization" ) B97_D3_def2_TZVPD_PCM_Single_Point = "B97-D3/def2-TZVPD/PCM Single Point" B97_D3_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/PCM Transition State Geometry Optimization" ) B97_D3_def2_TZVPD_PCM_Unknown = "B97-D3/def2-TZVPD/PCM Unknown" B97_D3_def2_TZVPD_SMD_Force = "B97-D3/def2-TZVPD/SMD Force" B97_D3_def2_TZVPD_SMD_Frequency_Analysis = ( "B97-D3/def2-TZVPD/SMD Frequency Analysis" ) B97_D3_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPD/SMD Geometry Optimization" ) B97_D3_def2_TZVPD_SMD_Single_Point = "B97-D3/def2-TZVPD/SMD Single Point" B97_D3_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/SMD Transition State Geometry Optimization" ) B97_D3_def2_TZVPD_SMD_Unknown = "B97-D3/def2-TZVPD/SMD Unknown" B97_D3_def2_TZVPD_VACUUM_Force = "B97-D3/def2-TZVPD/VACUUM Force" B97_D3_def2_TZVPD_VACUUM_Frequency_Analysis = ( "B97-D3/def2-TZVPD/VACUUM Frequency Analysis" ) B97_D3_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPD/VACUUM Geometry Optimization" ) B97_D3_def2_TZVPD_VACUUM_Single_Point = "B97-D3/def2-TZVPD/VACUUM Single Point" B97_D3_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_TZVPD_VACUUM_Unknown = "B97-D3/def2-TZVPD/VACUUM Unknown" B97_D3_def2_TZVPPD_PCM_Force = "B97-D3/def2-TZVPPD/PCM Force" B97_D3_def2_TZVPPD_PCM_Frequency_Analysis = ( "B97-D3/def2-TZVPPD/PCM Frequency Analysis" ) B97_D3_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/PCM Geometry Optimization" ) B97_D3_def2_TZVPPD_PCM_Single_Point = "B97-D3/def2-TZVPPD/PCM Single Point" B97_D3_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/PCM Transition State Geometry Optimization" ) B97_D3_def2_TZVPPD_PCM_Unknown = "B97-D3/def2-TZVPPD/PCM Unknown" B97_D3_def2_TZVPPD_SMD_Force = "B97-D3/def2-TZVPPD/SMD Force" B97_D3_def2_TZVPPD_SMD_Frequency_Analysis = ( "B97-D3/def2-TZVPPD/SMD Frequency Analysis" ) B97_D3_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/SMD Geometry Optimization" ) B97_D3_def2_TZVPPD_SMD_Single_Point = "B97-D3/def2-TZVPPD/SMD Single Point" B97_D3_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/SMD Transition State Geometry Optimization" ) B97_D3_def2_TZVPPD_SMD_Unknown = "B97-D3/def2-TZVPPD/SMD Unknown" B97_D3_def2_TZVPPD_VACUUM_Force = "B97-D3/def2-TZVPPD/VACUUM Force" B97_D3_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "B97-D3/def2-TZVPPD/VACUUM Frequency Analysis" ) B97_D3_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/VACUUM Geometry Optimization" ) B97_D3_def2_TZVPPD_VACUUM_Single_Point = "B97-D3/def2-TZVPPD/VACUUM Single Point" B97_D3_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_TZVPPD_VACUUM_Unknown = "B97-D3/def2-TZVPPD/VACUUM Unknown" B97_D3_def2_TZVPP_PCM_Force = "B97-D3/def2-TZVPP/PCM Force" B97_D3_def2_TZVPP_PCM_Frequency_Analysis = ( "B97-D3/def2-TZVPP/PCM Frequency Analysis" ) B97_D3_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPP_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPP/PCM Geometry Optimization" ) B97_D3_def2_TZVPP_PCM_Single_Point = "B97-D3/def2-TZVPP/PCM Single Point" B97_D3_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/PCM Transition State Geometry Optimization" ) B97_D3_def2_TZVPP_PCM_Unknown = "B97-D3/def2-TZVPP/PCM Unknown" B97_D3_def2_TZVPP_SMD_Force = "B97-D3/def2-TZVPP/SMD Force" B97_D3_def2_TZVPP_SMD_Frequency_Analysis = ( "B97-D3/def2-TZVPP/SMD Frequency Analysis" ) B97_D3_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPP_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPP/SMD Geometry Optimization" ) B97_D3_def2_TZVPP_SMD_Single_Point = "B97-D3/def2-TZVPP/SMD Single Point" B97_D3_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/SMD Transition State Geometry Optimization" ) B97_D3_def2_TZVPP_SMD_Unknown = "B97-D3/def2-TZVPP/SMD Unknown" B97_D3_def2_TZVPP_VACUUM_Force = "B97-D3/def2-TZVPP/VACUUM Force" B97_D3_def2_TZVPP_VACUUM_Frequency_Analysis = ( "B97-D3/def2-TZVPP/VACUUM Frequency Analysis" ) B97_D3_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPP/VACUUM Geometry Optimization" ) B97_D3_def2_TZVPP_VACUUM_Single_Point = "B97-D3/def2-TZVPP/VACUUM Single Point" B97_D3_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_TZVPP_VACUUM_Unknown = "B97-D3/def2-TZVPP/VACUUM Unknown" B97_D3_def2_TZVP_PCM_Force = "B97-D3/def2-TZVP/PCM Force" B97_D3_def2_TZVP_PCM_Frequency_Analysis = "B97-D3/def2-TZVP/PCM Frequency Analysis" B97_D3_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVP_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVP/PCM Geometry Optimization" ) B97_D3_def2_TZVP_PCM_Single_Point = "B97-D3/def2-TZVP/PCM Single Point" B97_D3_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/PCM Transition State Geometry Optimization" ) B97_D3_def2_TZVP_PCM_Unknown = "B97-D3/def2-TZVP/PCM Unknown" B97_D3_def2_TZVP_SMD_Force = "B97-D3/def2-TZVP/SMD Force" B97_D3_def2_TZVP_SMD_Frequency_Analysis = "B97-D3/def2-TZVP/SMD Frequency Analysis" B97_D3_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVP_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVP/SMD Geometry Optimization" ) B97_D3_def2_TZVP_SMD_Single_Point = "B97-D3/def2-TZVP/SMD Single Point" B97_D3_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/SMD Transition State Geometry Optimization" ) B97_D3_def2_TZVP_SMD_Unknown = "B97-D3/def2-TZVP/SMD Unknown" B97_D3_def2_TZVP_VACUUM_Force = "B97-D3/def2-TZVP/VACUUM Force" B97_D3_def2_TZVP_VACUUM_Frequency_Analysis = ( "B97-D3/def2-TZVP/VACUUM Frequency Analysis" ) B97_D3_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D3/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) B97_D3_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D3/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D3_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVP/VACUUM Geometry Optimization" ) B97_D3_def2_TZVP_VACUUM_Single_Point = "B97-D3/def2-TZVP/VACUUM Single Point" B97_D3_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/VACUUM Transition State Geometry Optimization" ) B97_D3_def2_TZVP_VACUUM_Unknown = "B97-D3/def2-TZVP/VACUUM Unknown" B97_D_6_31g_d_PCM_Force = "B97-D/6-31g*/PCM Force" B97_D_6_31g_d_PCM_Frequency_Analysis = "B97-D/6-31g*/PCM Frequency Analysis" B97_D_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/6-31g*/PCM Frequency Flattening Geometry Optimization" ) B97_D_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) B97_D_6_31g_d_PCM_Geometry_Optimization = "B97-D/6-31g*/PCM Geometry Optimization" B97_D_6_31g_d_PCM_Single_Point = "B97-D/6-31g*/PCM Single Point" B97_D_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/PCM Transition State Geometry Optimization" ) B97_D_6_31g_d_PCM_Unknown = "B97-D/6-31g*/PCM Unknown" B97_D_6_31g_d_SMD_Force = "B97-D/6-31g*/SMD Force" B97_D_6_31g_d_SMD_Frequency_Analysis = "B97-D/6-31g*/SMD Frequency Analysis" B97_D_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/6-31g*/SMD Frequency Flattening Geometry Optimization" ) B97_D_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) B97_D_6_31g_d_SMD_Geometry_Optimization = "B97-D/6-31g*/SMD Geometry Optimization" B97_D_6_31g_d_SMD_Single_Point = "B97-D/6-31g*/SMD Single Point" B97_D_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/SMD Transition State Geometry Optimization" ) B97_D_6_31g_d_SMD_Unknown = "B97-D/6-31g*/SMD Unknown" B97_D_6_31g_d_VACUUM_Force = "B97-D/6-31g*/VACUUM Force" B97_D_6_31g_d_VACUUM_Frequency_Analysis = "B97-D/6-31g*/VACUUM Frequency Analysis" B97_D_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_6_31g_d_VACUUM_Geometry_Optimization = ( "B97-D/6-31g*/VACUUM Geometry Optimization" ) B97_D_6_31g_d_VACUUM_Single_Point = "B97-D/6-31g*/VACUUM Single Point" B97_D_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/VACUUM Transition State Geometry Optimization" ) B97_D_6_31g_d_VACUUM_Unknown = "B97-D/6-31g*/VACUUM Unknown" B97_D_def2_QZVPD_PCM_Force = "B97-D/def2-QZVPD/PCM Force" B97_D_def2_QZVPD_PCM_Frequency_Analysis = "B97-D/def2-QZVPD/PCM Frequency Analysis" B97_D_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPD_PCM_Geometry_Optimization = ( "B97-D/def2-QZVPD/PCM Geometry Optimization" ) B97_D_def2_QZVPD_PCM_Single_Point = "B97-D/def2-QZVPD/PCM Single Point" B97_D_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/PCM Transition State Geometry Optimization" ) B97_D_def2_QZVPD_PCM_Unknown = "B97-D/def2-QZVPD/PCM Unknown" B97_D_def2_QZVPD_SMD_Force = "B97-D/def2-QZVPD/SMD Force" B97_D_def2_QZVPD_SMD_Frequency_Analysis = "B97-D/def2-QZVPD/SMD Frequency Analysis" B97_D_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPD_SMD_Geometry_Optimization = ( "B97-D/def2-QZVPD/SMD Geometry Optimization" ) B97_D_def2_QZVPD_SMD_Single_Point = "B97-D/def2-QZVPD/SMD Single Point" B97_D_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/SMD Transition State Geometry Optimization" ) B97_D_def2_QZVPD_SMD_Unknown = "B97-D/def2-QZVPD/SMD Unknown" B97_D_def2_QZVPD_VACUUM_Force = "B97-D/def2-QZVPD/VACUUM Force" B97_D_def2_QZVPD_VACUUM_Frequency_Analysis = ( "B97-D/def2-QZVPD/VACUUM Frequency Analysis" ) B97_D_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-QZVPD/VACUUM Geometry Optimization" ) B97_D_def2_QZVPD_VACUUM_Single_Point = "B97-D/def2-QZVPD/VACUUM Single Point" B97_D_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) B97_D_def2_QZVPD_VACUUM_Unknown = "B97-D/def2-QZVPD/VACUUM Unknown" B97_D_def2_QZVPPD_PCM_Force = "B97-D/def2-QZVPPD/PCM Force" B97_D_def2_QZVPPD_PCM_Frequency_Analysis = ( "B97-D/def2-QZVPPD/PCM Frequency Analysis" ) B97_D_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97-D/def2-QZVPPD/PCM Geometry Optimization" ) B97_D_def2_QZVPPD_PCM_Single_Point = "B97-D/def2-QZVPPD/PCM Single Point" B97_D_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/PCM Transition State Geometry Optimization" ) B97_D_def2_QZVPPD_PCM_Unknown = "B97-D/def2-QZVPPD/PCM Unknown" B97_D_def2_QZVPPD_SMD_Force = "B97-D/def2-QZVPPD/SMD Force" B97_D_def2_QZVPPD_SMD_Frequency_Analysis = ( "B97-D/def2-QZVPPD/SMD Frequency Analysis" ) B97_D_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97-D/def2-QZVPPD/SMD Geometry Optimization" ) B97_D_def2_QZVPPD_SMD_Single_Point = "B97-D/def2-QZVPPD/SMD Single Point" B97_D_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/SMD Transition State Geometry Optimization" ) B97_D_def2_QZVPPD_SMD_Unknown = "B97-D/def2-QZVPPD/SMD Unknown" B97_D_def2_QZVPPD_VACUUM_Force = "B97-D/def2-QZVPPD/VACUUM Force" B97_D_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "B97-D/def2-QZVPPD/VACUUM Frequency Analysis" ) B97_D_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-QZVPPD/VACUUM Geometry Optimization" ) B97_D_def2_QZVPPD_VACUUM_Single_Point = "B97-D/def2-QZVPPD/VACUUM Single Point" B97_D_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) B97_D_def2_QZVPPD_VACUUM_Unknown = "B97-D/def2-QZVPPD/VACUUM Unknown" B97_D_def2_SVPD_PCM_Force = "B97-D/def2-SVPD/PCM Force" B97_D_def2_SVPD_PCM_Frequency_Analysis = "B97-D/def2-SVPD/PCM Frequency Analysis" B97_D_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_SVPD_PCM_Geometry_Optimization = ( "B97-D/def2-SVPD/PCM Geometry Optimization" ) B97_D_def2_SVPD_PCM_Single_Point = "B97-D/def2-SVPD/PCM Single Point" B97_D_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/PCM Transition State Geometry Optimization" ) B97_D_def2_SVPD_PCM_Unknown = "B97-D/def2-SVPD/PCM Unknown" B97_D_def2_SVPD_SMD_Force = "B97-D/def2-SVPD/SMD Force" B97_D_def2_SVPD_SMD_Frequency_Analysis = "B97-D/def2-SVPD/SMD Frequency Analysis" B97_D_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_SVPD_SMD_Geometry_Optimization = ( "B97-D/def2-SVPD/SMD Geometry Optimization" ) B97_D_def2_SVPD_SMD_Single_Point = "B97-D/def2-SVPD/SMD Single Point" B97_D_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/SMD Transition State Geometry Optimization" ) B97_D_def2_SVPD_SMD_Unknown = "B97-D/def2-SVPD/SMD Unknown" B97_D_def2_SVPD_VACUUM_Force = "B97-D/def2-SVPD/VACUUM Force" B97_D_def2_SVPD_VACUUM_Frequency_Analysis = ( "B97-D/def2-SVPD/VACUUM Frequency Analysis" ) B97_D_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-SVPD/VACUUM Geometry Optimization" ) B97_D_def2_SVPD_VACUUM_Single_Point = "B97-D/def2-SVPD/VACUUM Single Point" B97_D_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/VACUUM Transition State Geometry Optimization" ) B97_D_def2_SVPD_VACUUM_Unknown = "B97-D/def2-SVPD/VACUUM Unknown" B97_D_def2_TZVPD_PCM_Force = "B97-D/def2-TZVPD/PCM Force" B97_D_def2_TZVPD_PCM_Frequency_Analysis = "B97-D/def2-TZVPD/PCM Frequency Analysis" B97_D_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPD_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPD/PCM Geometry Optimization" ) B97_D_def2_TZVPD_PCM_Single_Point = "B97-D/def2-TZVPD/PCM Single Point" B97_D_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/PCM Transition State Geometry Optimization" ) B97_D_def2_TZVPD_PCM_Unknown = "B97-D/def2-TZVPD/PCM Unknown" B97_D_def2_TZVPD_SMD_Force = "B97-D/def2-TZVPD/SMD Force" B97_D_def2_TZVPD_SMD_Frequency_Analysis = "B97-D/def2-TZVPD/SMD Frequency Analysis" B97_D_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPD_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPD/SMD Geometry Optimization" ) B97_D_def2_TZVPD_SMD_Single_Point = "B97-D/def2-TZVPD/SMD Single Point" B97_D_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/SMD Transition State Geometry Optimization" ) B97_D_def2_TZVPD_SMD_Unknown = "B97-D/def2-TZVPD/SMD Unknown" B97_D_def2_TZVPD_VACUUM_Force = "B97-D/def2-TZVPD/VACUUM Force" B97_D_def2_TZVPD_VACUUM_Frequency_Analysis = ( "B97-D/def2-TZVPD/VACUUM Frequency Analysis" ) B97_D_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPD/VACUUM Geometry Optimization" ) B97_D_def2_TZVPD_VACUUM_Single_Point = "B97-D/def2-TZVPD/VACUUM Single Point" B97_D_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) B97_D_def2_TZVPD_VACUUM_Unknown = "B97-D/def2-TZVPD/VACUUM Unknown" B97_D_def2_TZVPPD_PCM_Force = "B97-D/def2-TZVPPD/PCM Force" B97_D_def2_TZVPPD_PCM_Frequency_Analysis = ( "B97-D/def2-TZVPPD/PCM Frequency Analysis" ) B97_D_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPPD/PCM Geometry Optimization" ) B97_D_def2_TZVPPD_PCM_Single_Point = "B97-D/def2-TZVPPD/PCM Single Point" B97_D_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/PCM Transition State Geometry Optimization" ) B97_D_def2_TZVPPD_PCM_Unknown = "B97-D/def2-TZVPPD/PCM Unknown" B97_D_def2_TZVPPD_SMD_Force = "B97-D/def2-TZVPPD/SMD Force" B97_D_def2_TZVPPD_SMD_Frequency_Analysis = ( "B97-D/def2-TZVPPD/SMD Frequency Analysis" ) B97_D_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPPD/SMD Geometry Optimization" ) B97_D_def2_TZVPPD_SMD_Single_Point = "B97-D/def2-TZVPPD/SMD Single Point" B97_D_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/SMD Transition State Geometry Optimization" ) B97_D_def2_TZVPPD_SMD_Unknown = "B97-D/def2-TZVPPD/SMD Unknown" B97_D_def2_TZVPPD_VACUUM_Force = "B97-D/def2-TZVPPD/VACUUM Force" B97_D_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "B97-D/def2-TZVPPD/VACUUM Frequency Analysis" ) B97_D_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPPD/VACUUM Geometry Optimization" ) B97_D_def2_TZVPPD_VACUUM_Single_Point = "B97-D/def2-TZVPPD/VACUUM Single Point" B97_D_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) B97_D_def2_TZVPPD_VACUUM_Unknown = "B97-D/def2-TZVPPD/VACUUM Unknown" B97_D_def2_TZVPP_PCM_Force = "B97-D/def2-TZVPP/PCM Force" B97_D_def2_TZVPP_PCM_Frequency_Analysis = "B97-D/def2-TZVPP/PCM Frequency Analysis" B97_D_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPP_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPP/PCM Geometry Optimization" ) B97_D_def2_TZVPP_PCM_Single_Point = "B97-D/def2-TZVPP/PCM Single Point" B97_D_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/PCM Transition State Geometry Optimization" ) B97_D_def2_TZVPP_PCM_Unknown = "B97-D/def2-TZVPP/PCM Unknown" B97_D_def2_TZVPP_SMD_Force = "B97-D/def2-TZVPP/SMD Force" B97_D_def2_TZVPP_SMD_Frequency_Analysis = "B97-D/def2-TZVPP/SMD Frequency Analysis" B97_D_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPP_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPP/SMD Geometry Optimization" ) B97_D_def2_TZVPP_SMD_Single_Point = "B97-D/def2-TZVPP/SMD Single Point" B97_D_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/SMD Transition State Geometry Optimization" ) B97_D_def2_TZVPP_SMD_Unknown = "B97-D/def2-TZVPP/SMD Unknown" B97_D_def2_TZVPP_VACUUM_Force = "B97-D/def2-TZVPP/VACUUM Force" B97_D_def2_TZVPP_VACUUM_Frequency_Analysis = ( "B97-D/def2-TZVPP/VACUUM Frequency Analysis" ) B97_D_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPP/VACUUM Geometry Optimization" ) B97_D_def2_TZVPP_VACUUM_Single_Point = "B97-D/def2-TZVPP/VACUUM Single Point" B97_D_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) B97_D_def2_TZVPP_VACUUM_Unknown = "B97-D/def2-TZVPP/VACUUM Unknown" B97_D_def2_TZVP_PCM_Force = "B97-D/def2-TZVP/PCM Force" B97_D_def2_TZVP_PCM_Frequency_Analysis = "B97-D/def2-TZVP/PCM Frequency Analysis" B97_D_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVP_PCM_Geometry_Optimization = ( "B97-D/def2-TZVP/PCM Geometry Optimization" ) B97_D_def2_TZVP_PCM_Single_Point = "B97-D/def2-TZVP/PCM Single Point" B97_D_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/PCM Transition State Geometry Optimization" ) B97_D_def2_TZVP_PCM_Unknown = "B97-D/def2-TZVP/PCM Unknown" B97_D_def2_TZVP_SMD_Force = "B97-D/def2-TZVP/SMD Force" B97_D_def2_TZVP_SMD_Frequency_Analysis = "B97-D/def2-TZVP/SMD Frequency Analysis" B97_D_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVP_SMD_Geometry_Optimization = ( "B97-D/def2-TZVP/SMD Geometry Optimization" ) B97_D_def2_TZVP_SMD_Single_Point = "B97-D/def2-TZVP/SMD Single Point" B97_D_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/SMD Transition State Geometry Optimization" ) B97_D_def2_TZVP_SMD_Unknown = "B97-D/def2-TZVP/SMD Unknown" B97_D_def2_TZVP_VACUUM_Force = "B97-D/def2-TZVP/VACUUM Force" B97_D_def2_TZVP_VACUUM_Frequency_Analysis = ( "B97-D/def2-TZVP/VACUUM Frequency Analysis" ) B97_D_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "B97-D/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) B97_D_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "B97-D/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" B97_D_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVP/VACUUM Geometry Optimization" ) B97_D_def2_TZVP_VACUUM_Single_Point = "B97-D/def2-TZVP/VACUUM Single Point" B97_D_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/VACUUM Transition State Geometry Optimization" ) B97_D_def2_TZVP_VACUUM_Unknown = "B97-D/def2-TZVP/VACUUM Unknown" MN12_L_6_31g_d_PCM_Force = "MN12-L/6-31g*/PCM Force" MN12_L_6_31g_d_PCM_Frequency_Analysis = "MN12-L/6-31g*/PCM Frequency Analysis" MN12_L_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/6-31g*/PCM Frequency Flattening Geometry Optimization" ) MN12_L_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "MN12-L/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) MN12_L_6_31g_d_PCM_Geometry_Optimization = "MN12-L/6-31g*/PCM Geometry Optimization" MN12_L_6_31g_d_PCM_Single_Point = "MN12-L/6-31g*/PCM Single Point" MN12_L_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/6-31g*/PCM Transition State Geometry Optimization" ) MN12_L_6_31g_d_PCM_Unknown = "MN12-L/6-31g*/PCM Unknown" MN12_L_6_31g_d_SMD_Force = "MN12-L/6-31g*/SMD Force" MN12_L_6_31g_d_SMD_Frequency_Analysis = "MN12-L/6-31g*/SMD Frequency Analysis" MN12_L_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/6-31g*/SMD Frequency Flattening Geometry Optimization" ) MN12_L_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "MN12-L/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) MN12_L_6_31g_d_SMD_Geometry_Optimization = "MN12-L/6-31g*/SMD Geometry Optimization" MN12_L_6_31g_d_SMD_Single_Point = "MN12-L/6-31g*/SMD Single Point" MN12_L_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/6-31g*/SMD Transition State Geometry Optimization" ) MN12_L_6_31g_d_SMD_Unknown = "MN12-L/6-31g*/SMD Unknown" MN12_L_6_31g_d_VACUUM_Force = "MN12-L/6-31g*/VACUUM Force" MN12_L_6_31g_d_VACUUM_Frequency_Analysis = "MN12-L/6-31g*/VACUUM Frequency Analysis" MN12_L_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_6_31g_d_VACUUM_Geometry_Optimization = ( "MN12-L/6-31g*/VACUUM Geometry Optimization" ) MN12_L_6_31g_d_VACUUM_Single_Point = "MN12-L/6-31g*/VACUUM Single Point" MN12_L_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/6-31g*/VACUUM Transition State Geometry Optimization" ) MN12_L_6_31g_d_VACUUM_Unknown = "MN12-L/6-31g*/VACUUM Unknown" MN12_L_def2_QZVPD_PCM_Force = "MN12-L/def2-QZVPD/PCM Force" MN12_L_def2_QZVPD_PCM_Frequency_Analysis = ( "MN12-L/def2-QZVPD/PCM Frequency Analysis" ) MN12_L_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPD_PCM_Geometry_Optimization = ( "MN12-L/def2-QZVPD/PCM Geometry Optimization" ) MN12_L_def2_QZVPD_PCM_Single_Point = "MN12-L/def2-QZVPD/PCM Single Point" MN12_L_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPD/PCM Transition State Geometry Optimization" ) MN12_L_def2_QZVPD_PCM_Unknown = "MN12-L/def2-QZVPD/PCM Unknown" MN12_L_def2_QZVPD_SMD_Force = "MN12-L/def2-QZVPD/SMD Force" MN12_L_def2_QZVPD_SMD_Frequency_Analysis = ( "MN12-L/def2-QZVPD/SMD Frequency Analysis" ) MN12_L_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPD_SMD_Geometry_Optimization = ( "MN12-L/def2-QZVPD/SMD Geometry Optimization" ) MN12_L_def2_QZVPD_SMD_Single_Point = "MN12-L/def2-QZVPD/SMD Single Point" MN12_L_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPD/SMD Transition State Geometry Optimization" ) MN12_L_def2_QZVPD_SMD_Unknown = "MN12-L/def2-QZVPD/SMD Unknown" MN12_L_def2_QZVPD_VACUUM_Force = "MN12-L/def2-QZVPD/VACUUM Force" MN12_L_def2_QZVPD_VACUUM_Frequency_Analysis = ( "MN12-L/def2-QZVPD/VACUUM Frequency Analysis" ) MN12_L_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPD_VACUUM_Geometry_Optimization = ( "MN12-L/def2-QZVPD/VACUUM Geometry Optimization" ) MN12_L_def2_QZVPD_VACUUM_Single_Point = "MN12-L/def2-QZVPD/VACUUM Single Point" MN12_L_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_QZVPD_VACUUM_Unknown = "MN12-L/def2-QZVPD/VACUUM Unknown" MN12_L_def2_QZVPPD_PCM_Force = "MN12-L/def2-QZVPPD/PCM Force" MN12_L_def2_QZVPPD_PCM_Frequency_Analysis = ( "MN12-L/def2-QZVPPD/PCM Frequency Analysis" ) MN12_L_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPPD_PCM_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/PCM Geometry Optimization" ) MN12_L_def2_QZVPPD_PCM_Single_Point = "MN12-L/def2-QZVPPD/PCM Single Point" MN12_L_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/PCM Transition State Geometry Optimization" ) MN12_L_def2_QZVPPD_PCM_Unknown = "MN12-L/def2-QZVPPD/PCM Unknown" MN12_L_def2_QZVPPD_SMD_Force = "MN12-L/def2-QZVPPD/SMD Force" MN12_L_def2_QZVPPD_SMD_Frequency_Analysis = ( "MN12-L/def2-QZVPPD/SMD Frequency Analysis" ) MN12_L_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPPD_SMD_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/SMD Geometry Optimization" ) MN12_L_def2_QZVPPD_SMD_Single_Point = "MN12-L/def2-QZVPPD/SMD Single Point" MN12_L_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/SMD Transition State Geometry Optimization" ) MN12_L_def2_QZVPPD_SMD_Unknown = "MN12-L/def2-QZVPPD/SMD Unknown" MN12_L_def2_QZVPPD_VACUUM_Force = "MN12-L/def2-QZVPPD/VACUUM Force" MN12_L_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "MN12-L/def2-QZVPPD/VACUUM Frequency Analysis" ) MN12_L_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/VACUUM Geometry Optimization" ) MN12_L_def2_QZVPPD_VACUUM_Single_Point = "MN12-L/def2-QZVPPD/VACUUM Single Point" MN12_L_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_QZVPPD_VACUUM_Unknown = "MN12-L/def2-QZVPPD/VACUUM Unknown" MN12_L_def2_SVPD_PCM_Force = "MN12-L/def2-SVPD/PCM Force" MN12_L_def2_SVPD_PCM_Frequency_Analysis = "MN12-L/def2-SVPD/PCM Frequency Analysis" MN12_L_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_SVPD_PCM_Geometry_Optimization = ( "MN12-L/def2-SVPD/PCM Geometry Optimization" ) MN12_L_def2_SVPD_PCM_Single_Point = "MN12-L/def2-SVPD/PCM Single Point" MN12_L_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-SVPD/PCM Transition State Geometry Optimization" ) MN12_L_def2_SVPD_PCM_Unknown = "MN12-L/def2-SVPD/PCM Unknown" MN12_L_def2_SVPD_SMD_Force = "MN12-L/def2-SVPD/SMD Force" MN12_L_def2_SVPD_SMD_Frequency_Analysis = "MN12-L/def2-SVPD/SMD Frequency Analysis" MN12_L_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_SVPD_SMD_Geometry_Optimization = ( "MN12-L/def2-SVPD/SMD Geometry Optimization" ) MN12_L_def2_SVPD_SMD_Single_Point = "MN12-L/def2-SVPD/SMD Single Point" MN12_L_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-SVPD/SMD Transition State Geometry Optimization" ) MN12_L_def2_SVPD_SMD_Unknown = "MN12-L/def2-SVPD/SMD Unknown" MN12_L_def2_SVPD_VACUUM_Force = "MN12-L/def2-SVPD/VACUUM Force" MN12_L_def2_SVPD_VACUUM_Frequency_Analysis = ( "MN12-L/def2-SVPD/VACUUM Frequency Analysis" ) MN12_L_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_SVPD_VACUUM_Geometry_Optimization = ( "MN12-L/def2-SVPD/VACUUM Geometry Optimization" ) MN12_L_def2_SVPD_VACUUM_Single_Point = "MN12-L/def2-SVPD/VACUUM Single Point" MN12_L_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-SVPD/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_SVPD_VACUUM_Unknown = "MN12-L/def2-SVPD/VACUUM Unknown" MN12_L_def2_TZVPD_PCM_Force = "MN12-L/def2-TZVPD/PCM Force" MN12_L_def2_TZVPD_PCM_Frequency_Analysis = ( "MN12-L/def2-TZVPD/PCM Frequency Analysis" ) MN12_L_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPD_PCM_Geometry_Optimization = ( "MN12-L/def2-TZVPD/PCM Geometry Optimization" ) MN12_L_def2_TZVPD_PCM_Single_Point = "MN12-L/def2-TZVPD/PCM Single Point" MN12_L_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPD/PCM Transition State Geometry Optimization" ) MN12_L_def2_TZVPD_PCM_Unknown = "MN12-L/def2-TZVPD/PCM Unknown" MN12_L_def2_TZVPD_SMD_Force = "MN12-L/def2-TZVPD/SMD Force" MN12_L_def2_TZVPD_SMD_Frequency_Analysis = ( "MN12-L/def2-TZVPD/SMD Frequency Analysis" ) MN12_L_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPD_SMD_Geometry_Optimization = ( "MN12-L/def2-TZVPD/SMD Geometry Optimization" ) MN12_L_def2_TZVPD_SMD_Single_Point = "MN12-L/def2-TZVPD/SMD Single Point" MN12_L_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPD/SMD Transition State Geometry Optimization" ) MN12_L_def2_TZVPD_SMD_Unknown = "MN12-L/def2-TZVPD/SMD Unknown" MN12_L_def2_TZVPD_VACUUM_Force = "MN12-L/def2-TZVPD/VACUUM Force" MN12_L_def2_TZVPD_VACUUM_Frequency_Analysis = ( "MN12-L/def2-TZVPD/VACUUM Frequency Analysis" ) MN12_L_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPD_VACUUM_Geometry_Optimization = ( "MN12-L/def2-TZVPD/VACUUM Geometry Optimization" ) MN12_L_def2_TZVPD_VACUUM_Single_Point = "MN12-L/def2-TZVPD/VACUUM Single Point" MN12_L_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_TZVPD_VACUUM_Unknown = "MN12-L/def2-TZVPD/VACUUM Unknown" MN12_L_def2_TZVPPD_PCM_Force = "MN12-L/def2-TZVPPD/PCM Force" MN12_L_def2_TZVPPD_PCM_Frequency_Analysis = ( "MN12-L/def2-TZVPPD/PCM Frequency Analysis" ) MN12_L_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPPD_PCM_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/PCM Geometry Optimization" ) MN12_L_def2_TZVPPD_PCM_Single_Point = "MN12-L/def2-TZVPPD/PCM Single Point" MN12_L_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/PCM Transition State Geometry Optimization" ) MN12_L_def2_TZVPPD_PCM_Unknown = "MN12-L/def2-TZVPPD/PCM Unknown" MN12_L_def2_TZVPPD_SMD_Force = "MN12-L/def2-TZVPPD/SMD Force" MN12_L_def2_TZVPPD_SMD_Frequency_Analysis = ( "MN12-L/def2-TZVPPD/SMD Frequency Analysis" ) MN12_L_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPPD_SMD_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/SMD Geometry Optimization" ) MN12_L_def2_TZVPPD_SMD_Single_Point = "MN12-L/def2-TZVPPD/SMD Single Point" MN12_L_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/SMD Transition State Geometry Optimization" ) MN12_L_def2_TZVPPD_SMD_Unknown = "MN12-L/def2-TZVPPD/SMD Unknown" MN12_L_def2_TZVPPD_VACUUM_Force = "MN12-L/def2-TZVPPD/VACUUM Force" MN12_L_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "MN12-L/def2-TZVPPD/VACUUM Frequency Analysis" ) MN12_L_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/VACUUM Geometry Optimization" ) MN12_L_def2_TZVPPD_VACUUM_Single_Point = "MN12-L/def2-TZVPPD/VACUUM Single Point" MN12_L_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_TZVPPD_VACUUM_Unknown = "MN12-L/def2-TZVPPD/VACUUM Unknown" MN12_L_def2_TZVPP_PCM_Force = "MN12-L/def2-TZVPP/PCM Force" MN12_L_def2_TZVPP_PCM_Frequency_Analysis = ( "MN12-L/def2-TZVPP/PCM Frequency Analysis" ) MN12_L_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPP_PCM_Geometry_Optimization = ( "MN12-L/def2-TZVPP/PCM Geometry Optimization" ) MN12_L_def2_TZVPP_PCM_Single_Point = "MN12-L/def2-TZVPP/PCM Single Point" MN12_L_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPP/PCM Transition State Geometry Optimization" ) MN12_L_def2_TZVPP_PCM_Unknown = "MN12-L/def2-TZVPP/PCM Unknown" MN12_L_def2_TZVPP_SMD_Force = "MN12-L/def2-TZVPP/SMD Force" MN12_L_def2_TZVPP_SMD_Frequency_Analysis = ( "MN12-L/def2-TZVPP/SMD Frequency Analysis" ) MN12_L_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPP_SMD_Geometry_Optimization = ( "MN12-L/def2-TZVPP/SMD Geometry Optimization" ) MN12_L_def2_TZVPP_SMD_Single_Point = "MN12-L/def2-TZVPP/SMD Single Point" MN12_L_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPP/SMD Transition State Geometry Optimization" ) MN12_L_def2_TZVPP_SMD_Unknown = "MN12-L/def2-TZVPP/SMD Unknown" MN12_L_def2_TZVPP_VACUUM_Force = "MN12-L/def2-TZVPP/VACUUM Force" MN12_L_def2_TZVPP_VACUUM_Frequency_Analysis = ( "MN12-L/def2-TZVPP/VACUUM Frequency Analysis" ) MN12_L_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVPP_VACUUM_Geometry_Optimization = ( "MN12-L/def2-TZVPP/VACUUM Geometry Optimization" ) MN12_L_def2_TZVPP_VACUUM_Single_Point = "MN12-L/def2-TZVPP/VACUUM Single Point" MN12_L_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_TZVPP_VACUUM_Unknown = "MN12-L/def2-TZVPP/VACUUM Unknown" MN12_L_def2_TZVP_PCM_Force = "MN12-L/def2-TZVP/PCM Force" MN12_L_def2_TZVP_PCM_Frequency_Analysis = "MN12-L/def2-TZVP/PCM Frequency Analysis" MN12_L_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVP_PCM_Geometry_Optimization = ( "MN12-L/def2-TZVP/PCM Geometry Optimization" ) MN12_L_def2_TZVP_PCM_Single_Point = "MN12-L/def2-TZVP/PCM Single Point" MN12_L_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVP/PCM Transition State Geometry Optimization" ) MN12_L_def2_TZVP_PCM_Unknown = "MN12-L/def2-TZVP/PCM Unknown" MN12_L_def2_TZVP_SMD_Force = "MN12-L/def2-TZVP/SMD Force" MN12_L_def2_TZVP_SMD_Frequency_Analysis = "MN12-L/def2-TZVP/SMD Frequency Analysis" MN12_L_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVP_SMD_Geometry_Optimization = ( "MN12-L/def2-TZVP/SMD Geometry Optimization" ) MN12_L_def2_TZVP_SMD_Single_Point = "MN12-L/def2-TZVP/SMD Single Point" MN12_L_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVP/SMD Transition State Geometry Optimization" ) MN12_L_def2_TZVP_SMD_Unknown = "MN12-L/def2-TZVP/SMD Unknown" MN12_L_def2_TZVP_VACUUM_Force = "MN12-L/def2-TZVP/VACUUM Force" MN12_L_def2_TZVP_VACUUM_Frequency_Analysis = ( "MN12-L/def2-TZVP/VACUUM Frequency Analysis" ) MN12_L_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "MN12-L/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) MN12_L_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "MN12-L/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" MN12_L_def2_TZVP_VACUUM_Geometry_Optimization = ( "MN12-L/def2-TZVP/VACUUM Geometry Optimization" ) MN12_L_def2_TZVP_VACUUM_Single_Point = "MN12-L/def2-TZVP/VACUUM Single Point" MN12_L_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "MN12-L/def2-TZVP/VACUUM Transition State Geometry Optimization" ) MN12_L_def2_TZVP_VACUUM_Unknown = "MN12-L/def2-TZVP/VACUUM Unknown" PBE_6_31g_d_PCM_Force = "PBE/6-31g*/PCM Force" PBE_6_31g_d_PCM_Frequency_Analysis = "PBE/6-31g*/PCM Frequency Analysis" PBE_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/6-31g*/PCM Frequency Flattening Geometry Optimization" ) PBE_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_6_31g_d_PCM_Geometry_Optimization = "PBE/6-31g*/PCM Geometry Optimization" PBE_6_31g_d_PCM_Single_Point = "PBE/6-31g*/PCM Single Point" PBE_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/PCM Transition State Geometry Optimization" ) PBE_6_31g_d_PCM_Unknown = "PBE/6-31g*/PCM Unknown" PBE_6_31g_d_SMD_Force = "PBE/6-31g*/SMD Force" PBE_6_31g_d_SMD_Frequency_Analysis = "PBE/6-31g*/SMD Frequency Analysis" PBE_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/6-31g*/SMD Frequency Flattening Geometry Optimization" ) PBE_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_6_31g_d_SMD_Geometry_Optimization = "PBE/6-31g*/SMD Geometry Optimization" PBE_6_31g_d_SMD_Single_Point = "PBE/6-31g*/SMD Single Point" PBE_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/SMD Transition State Geometry Optimization" ) PBE_6_31g_d_SMD_Unknown = "PBE/6-31g*/SMD Unknown" PBE_6_31g_d_VACUUM_Force = "PBE/6-31g*/VACUUM Force" PBE_6_31g_d_VACUUM_Frequency_Analysis = "PBE/6-31g*/VACUUM Frequency Analysis" PBE_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) PBE_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" ) PBE_6_31g_d_VACUUM_Geometry_Optimization = "PBE/6-31g*/VACUUM Geometry Optimization" PBE_6_31g_d_VACUUM_Single_Point = "PBE/6-31g*/VACUUM Single Point" PBE_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/VACUUM Transition State Geometry Optimization" ) PBE_6_31g_d_VACUUM_Unknown = "PBE/6-31g*/VACUUM Unknown" PBE_def2_QZVPD_PCM_Force = "PBE/def2-QZVPD/PCM Force" PBE_def2_QZVPD_PCM_Frequency_Analysis = "PBE/def2-QZVPD/PCM Frequency Analysis" PBE_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_QZVPD_PCM_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Geometry Optimization" ) PBE_def2_QZVPD_PCM_Single_Point = "PBE/def2-QZVPD/PCM Single Point" PBE_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Transition State Geometry Optimization" ) PBE_def2_QZVPD_PCM_Unknown = "PBE/def2-QZVPD/PCM Unknown" PBE_def2_QZVPD_SMD_Force = "PBE/def2-QZVPD/SMD Force" PBE_def2_QZVPD_SMD_Frequency_Analysis = "PBE/def2-QZVPD/SMD Frequency Analysis" PBE_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_QZVPD_SMD_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Geometry Optimization" ) PBE_def2_QZVPD_SMD_Single_Point = "PBE/def2-QZVPD/SMD Single Point" PBE_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Transition State Geometry Optimization" ) PBE_def2_QZVPD_SMD_Unknown = "PBE/def2-QZVPD/SMD Unknown" PBE_def2_QZVPD_VACUUM_Force = "PBE/def2-QZVPD/VACUUM Force" PBE_def2_QZVPD_VACUUM_Frequency_Analysis = ( "PBE/def2-QZVPD/VACUUM Frequency Analysis" ) PBE_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_QZVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-QZVPD/VACUUM Geometry Optimization" ) PBE_def2_QZVPD_VACUUM_Single_Point = "PBE/def2-QZVPD/VACUUM Single Point" PBE_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) PBE_def2_QZVPD_VACUUM_Unknown = "PBE/def2-QZVPD/VACUUM Unknown" PBE_def2_QZVPPD_PCM_Force = "PBE/def2-QZVPPD/PCM Force" PBE_def2_QZVPPD_PCM_Frequency_Analysis = "PBE/def2-QZVPPD/PCM Frequency Analysis" PBE_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" PBE_def2_QZVPPD_PCM_Geometry_Optimization = ( "PBE/def2-QZVPPD/PCM Geometry Optimization" ) PBE_def2_QZVPPD_PCM_Single_Point = "PBE/def2-QZVPPD/PCM Single Point" PBE_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/PCM Transition State Geometry Optimization" ) PBE_def2_QZVPPD_PCM_Unknown = "PBE/def2-QZVPPD/PCM Unknown" PBE_def2_QZVPPD_SMD_Force = "PBE/def2-QZVPPD/SMD Force" PBE_def2_QZVPPD_SMD_Frequency_Analysis = "PBE/def2-QZVPPD/SMD Frequency Analysis" PBE_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" PBE_def2_QZVPPD_SMD_Geometry_Optimization = ( "PBE/def2-QZVPPD/SMD Geometry Optimization" ) PBE_def2_QZVPPD_SMD_Single_Point = "PBE/def2-QZVPPD/SMD Single Point" PBE_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/SMD Transition State Geometry Optimization" ) PBE_def2_QZVPPD_SMD_Unknown = "PBE/def2-QZVPPD/SMD Unknown" PBE_def2_QZVPPD_VACUUM_Force = "PBE/def2-QZVPPD/VACUUM Force" PBE_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "PBE/def2-QZVPPD/VACUUM Frequency Analysis" ) PBE_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "PBE/def2-QZVPPD/VACUUM Geometry Optimization" ) PBE_def2_QZVPPD_VACUUM_Single_Point = "PBE/def2-QZVPPD/VACUUM Single Point" PBE_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) PBE_def2_QZVPPD_VACUUM_Unknown = "PBE/def2-QZVPPD/VACUUM Unknown" PBE_def2_SVPD_PCM_Force = "PBE/def2-SVPD/PCM Force" PBE_def2_SVPD_PCM_Frequency_Analysis = "PBE/def2-SVPD/PCM Frequency Analysis" PBE_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_SVPD_PCM_Geometry_Optimization = "PBE/def2-SVPD/PCM Geometry Optimization" PBE_def2_SVPD_PCM_Single_Point = "PBE/def2-SVPD/PCM Single Point" PBE_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/PCM Transition State Geometry Optimization" ) PBE_def2_SVPD_PCM_Unknown = "PBE/def2-SVPD/PCM Unknown" PBE_def2_SVPD_SMD_Force = "PBE/def2-SVPD/SMD Force" PBE_def2_SVPD_SMD_Frequency_Analysis = "PBE/def2-SVPD/SMD Frequency Analysis" PBE_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_SVPD_SMD_Geometry_Optimization = "PBE/def2-SVPD/SMD Geometry Optimization" PBE_def2_SVPD_SMD_Single_Point = "PBE/def2-SVPD/SMD Single Point" PBE_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/SMD Transition State Geometry Optimization" ) PBE_def2_SVPD_SMD_Unknown = "PBE/def2-SVPD/SMD Unknown" PBE_def2_SVPD_VACUUM_Force = "PBE/def2-SVPD/VACUUM Force" PBE_def2_SVPD_VACUUM_Frequency_Analysis = "PBE/def2-SVPD/VACUUM Frequency Analysis" PBE_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_SVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-SVPD/VACUUM Geometry Optimization" ) PBE_def2_SVPD_VACUUM_Single_Point = "PBE/def2-SVPD/VACUUM Single Point" PBE_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/VACUUM Transition State Geometry Optimization" ) PBE_def2_SVPD_VACUUM_Unknown = "PBE/def2-SVPD/VACUUM Unknown" PBE_def2_TZVPD_PCM_Force = "PBE/def2-TZVPD/PCM Force" PBE_def2_TZVPD_PCM_Frequency_Analysis = "PBE/def2-TZVPD/PCM Frequency Analysis" PBE_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVPD_PCM_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Geometry Optimization" ) PBE_def2_TZVPD_PCM_Single_Point = "PBE/def2-TZVPD/PCM Single Point" PBE_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Transition State Geometry Optimization" ) PBE_def2_TZVPD_PCM_Unknown = "PBE/def2-TZVPD/PCM Unknown" PBE_def2_TZVPD_SMD_Force = "PBE/def2-TZVPD/SMD Force" PBE_def2_TZVPD_SMD_Frequency_Analysis = "PBE/def2-TZVPD/SMD Frequency Analysis" PBE_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVPD_SMD_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Geometry Optimization" ) PBE_def2_TZVPD_SMD_Single_Point = "PBE/def2-TZVPD/SMD Single Point" PBE_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Transition State Geometry Optimization" ) PBE_def2_TZVPD_SMD_Unknown = "PBE/def2-TZVPD/SMD Unknown" PBE_def2_TZVPD_VACUUM_Force = "PBE/def2-TZVPD/VACUUM Force" PBE_def2_TZVPD_VACUUM_Frequency_Analysis = ( "PBE/def2-TZVPD/VACUUM Frequency Analysis" ) PBE_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPD/VACUUM Geometry Optimization" ) PBE_def2_TZVPD_VACUUM_Single_Point = "PBE/def2-TZVPD/VACUUM Single Point" PBE_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) PBE_def2_TZVPD_VACUUM_Unknown = "PBE/def2-TZVPD/VACUUM Unknown" PBE_def2_TZVPPD_PCM_Force = "PBE/def2-TZVPPD/PCM Force" PBE_def2_TZVPPD_PCM_Frequency_Analysis = "PBE/def2-TZVPPD/PCM Frequency Analysis" PBE_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVPPD_PCM_Geometry_Optimization = ( "PBE/def2-TZVPPD/PCM Geometry Optimization" ) PBE_def2_TZVPPD_PCM_Single_Point = "PBE/def2-TZVPPD/PCM Single Point" PBE_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/PCM Transition State Geometry Optimization" ) PBE_def2_TZVPPD_PCM_Unknown = "PBE/def2-TZVPPD/PCM Unknown" PBE_def2_TZVPPD_SMD_Force = "PBE/def2-TZVPPD/SMD Force" PBE_def2_TZVPPD_SMD_Frequency_Analysis = "PBE/def2-TZVPPD/SMD Frequency Analysis" PBE_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVPPD_SMD_Geometry_Optimization = ( "PBE/def2-TZVPPD/SMD Geometry Optimization" ) PBE_def2_TZVPPD_SMD_Single_Point = "PBE/def2-TZVPPD/SMD Single Point" PBE_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/SMD Transition State Geometry Optimization" ) PBE_def2_TZVPPD_SMD_Unknown = "PBE/def2-TZVPPD/SMD Unknown" PBE_def2_TZVPPD_VACUUM_Force = "PBE/def2-TZVPPD/VACUUM Force" PBE_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "PBE/def2-TZVPPD/VACUUM Frequency Analysis" ) PBE_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPPD/VACUUM Geometry Optimization" ) PBE_def2_TZVPPD_VACUUM_Single_Point = "PBE/def2-TZVPPD/VACUUM Single Point" PBE_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) PBE_def2_TZVPPD_VACUUM_Unknown = "PBE/def2-TZVPPD/VACUUM Unknown" PBE_def2_TZVPP_PCM_Force = "PBE/def2-TZVPP/PCM Force" PBE_def2_TZVPP_PCM_Frequency_Analysis = "PBE/def2-TZVPP/PCM Frequency Analysis" PBE_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVPP_PCM_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Geometry Optimization" ) PBE_def2_TZVPP_PCM_Single_Point = "PBE/def2-TZVPP/PCM Single Point" PBE_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Transition State Geometry Optimization" ) PBE_def2_TZVPP_PCM_Unknown = "PBE/def2-TZVPP/PCM Unknown" PBE_def2_TZVPP_SMD_Force = "PBE/def2-TZVPP/SMD Force" PBE_def2_TZVPP_SMD_Frequency_Analysis = "PBE/def2-TZVPP/SMD Frequency Analysis" PBE_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVPP_SMD_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Geometry Optimization" ) PBE_def2_TZVPP_SMD_Single_Point = "PBE/def2-TZVPP/SMD Single Point" PBE_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Transition State Geometry Optimization" ) PBE_def2_TZVPP_SMD_Unknown = "PBE/def2-TZVPP/SMD Unknown" PBE_def2_TZVPP_VACUUM_Force = "PBE/def2-TZVPP/VACUUM Force" PBE_def2_TZVPP_VACUUM_Frequency_Analysis = ( "PBE/def2-TZVPP/VACUUM Frequency Analysis" ) PBE_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVPP_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPP/VACUUM Geometry Optimization" ) PBE_def2_TZVPP_VACUUM_Single_Point = "PBE/def2-TZVPP/VACUUM Single Point" PBE_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) PBE_def2_TZVPP_VACUUM_Unknown = "PBE/def2-TZVPP/VACUUM Unknown" PBE_def2_TZVP_PCM_Force = "PBE/def2-TZVP/PCM Force" PBE_def2_TZVP_PCM_Frequency_Analysis = "PBE/def2-TZVP/PCM Frequency Analysis" PBE_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVP_PCM_Geometry_Optimization = "PBE/def2-TZVP/PCM Geometry Optimization" PBE_def2_TZVP_PCM_Single_Point = "PBE/def2-TZVP/PCM Single Point" PBE_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/PCM Transition State Geometry Optimization" ) PBE_def2_TZVP_PCM_Unknown = "PBE/def2-TZVP/PCM Unknown" PBE_def2_TZVP_SMD_Force = "PBE/def2-TZVP/SMD Force" PBE_def2_TZVP_SMD_Frequency_Analysis = "PBE/def2-TZVP/SMD Frequency Analysis" PBE_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) PBE_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" ) PBE_def2_TZVP_SMD_Geometry_Optimization = "PBE/def2-TZVP/SMD Geometry Optimization" PBE_def2_TZVP_SMD_Single_Point = "PBE/def2-TZVP/SMD Single Point" PBE_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/SMD Transition State Geometry Optimization" ) PBE_def2_TZVP_SMD_Unknown = "PBE/def2-TZVP/SMD Unknown" PBE_def2_TZVP_VACUUM_Force = "PBE/def2-TZVP/VACUUM Force" PBE_def2_TZVP_VACUUM_Frequency_Analysis = "PBE/def2-TZVP/VACUUM Frequency Analysis" PBE_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "PBE/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) PBE_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "PBE/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" PBE_def2_TZVP_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVP/VACUUM Geometry Optimization" ) PBE_def2_TZVP_VACUUM_Single_Point = "PBE/def2-TZVP/VACUUM Single Point" PBE_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/VACUUM Transition State Geometry Optimization" ) PBE_def2_TZVP_VACUUM_Unknown = "PBE/def2-TZVP/VACUUM Unknown" wB97M_V_6_31g_d_PCM_Force = "wB97M-V/6-31g*/PCM Force" wB97M_V_6_31g_d_PCM_Frequency_Analysis = "wB97M-V/6-31g*/PCM Frequency Analysis" wB97M_V_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) wB97M_V_6_31g_d_PCM_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Geometry Optimization" ) wB97M_V_6_31g_d_PCM_Single_Point = "wB97M-V/6-31g*/PCM Single Point" wB97M_V_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Transition State Geometry Optimization" ) wB97M_V_6_31g_d_PCM_Unknown = "wB97M-V/6-31g*/PCM Unknown" wB97M_V_6_31g_d_SMD_Force = "wB97M-V/6-31g*/SMD Force" wB97M_V_6_31g_d_SMD_Frequency_Analysis = "wB97M-V/6-31g*/SMD Frequency Analysis" wB97M_V_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) wB97M_V_6_31g_d_SMD_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Geometry Optimization" ) wB97M_V_6_31g_d_SMD_Single_Point = "wB97M-V/6-31g*/SMD Single Point" wB97M_V_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Transition State Geometry Optimization" ) wB97M_V_6_31g_d_SMD_Unknown = "wB97M-V/6-31g*/SMD Unknown" wB97M_V_6_31g_d_VACUUM_Force = "wB97M-V/6-31g*/VACUUM Force" wB97M_V_6_31g_d_VACUUM_Frequency_Analysis = ( "wB97M-V/6-31g*/VACUUM Frequency Analysis" ) wB97M_V_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97M-V/6-31g*/VACUUM Geometry Optimization" ) wB97M_V_6_31g_d_VACUUM_Single_Point = "wB97M-V/6-31g*/VACUUM Single Point" wB97M_V_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/VACUUM Transition State Geometry Optimization" ) wB97M_V_6_31g_d_VACUUM_Unknown = "wB97M-V/6-31g*/VACUUM Unknown" wB97M_V_def2_QZVPD_PCM_Force = "wB97M-V/def2-QZVPD/PCM Force" wB97M_V_def2_QZVPD_PCM_Frequency_Analysis = ( "wB97M-V/def2-QZVPD/PCM Frequency Analysis" ) wB97M_V_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/PCM Geometry Optimization" ) wB97M_V_def2_QZVPD_PCM_Single_Point = "wB97M-V/def2-QZVPD/PCM Single Point" wB97M_V_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/PCM Transition State Geometry Optimization" ) wB97M_V_def2_QZVPD_PCM_Unknown = "wB97M-V/def2-QZVPD/PCM Unknown" wB97M_V_def2_QZVPD_SMD_Force = "wB97M-V/def2-QZVPD/SMD Force" wB97M_V_def2_QZVPD_SMD_Frequency_Analysis = ( "wB97M-V/def2-QZVPD/SMD Frequency Analysis" ) wB97M_V_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/SMD Geometry Optimization" ) wB97M_V_def2_QZVPD_SMD_Single_Point = "wB97M-V/def2-QZVPD/SMD Single Point" wB97M_V_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/SMD Transition State Geometry Optimization" ) wB97M_V_def2_QZVPD_SMD_Unknown = "wB97M-V/def2-QZVPD/SMD Unknown" wB97M_V_def2_QZVPD_VACUUM_Force = "wB97M-V/def2-QZVPD/VACUUM Force" wB97M_V_def2_QZVPD_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-QZVPD/VACUUM Frequency Analysis" ) wB97M_V_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/VACUUM Geometry Optimization" ) wB97M_V_def2_QZVPD_VACUUM_Single_Point = "wB97M-V/def2-QZVPD/VACUUM Single Point" wB97M_V_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_QZVPD_VACUUM_Unknown = "wB97M-V/def2-QZVPD/VACUUM Unknown" wB97M_V_def2_QZVPPD_PCM_Force = "wB97M-V/def2-QZVPPD/PCM Force" wB97M_V_def2_QZVPPD_PCM_Frequency_Analysis = ( "wB97M-V/def2-QZVPPD/PCM Frequency Analysis" ) wB97M_V_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/PCM Geometry Optimization" ) wB97M_V_def2_QZVPPD_PCM_Single_Point = "wB97M-V/def2-QZVPPD/PCM Single Point" wB97M_V_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/PCM Transition State Geometry Optimization" ) wB97M_V_def2_QZVPPD_PCM_Unknown = "wB97M-V/def2-QZVPPD/PCM Unknown" wB97M_V_def2_QZVPPD_SMD_Force = "wB97M-V/def2-QZVPPD/SMD Force" wB97M_V_def2_QZVPPD_SMD_Frequency_Analysis = ( "wB97M-V/def2-QZVPPD/SMD Frequency Analysis" ) wB97M_V_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/SMD Geometry Optimization" ) wB97M_V_def2_QZVPPD_SMD_Single_Point = "wB97M-V/def2-QZVPPD/SMD Single Point" wB97M_V_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/SMD Transition State Geometry Optimization" ) wB97M_V_def2_QZVPPD_SMD_Unknown = "wB97M-V/def2-QZVPPD/SMD Unknown" wB97M_V_def2_QZVPPD_VACUUM_Force = "wB97M-V/def2-QZVPPD/VACUUM Force" wB97M_V_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-QZVPPD/VACUUM Frequency Analysis" ) wB97M_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/VACUUM Geometry Optimization" ) wB97M_V_def2_QZVPPD_VACUUM_Single_Point = "wB97M-V/def2-QZVPPD/VACUUM Single Point" wB97M_V_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_QZVPPD_VACUUM_Unknown = "wB97M-V/def2-QZVPPD/VACUUM Unknown" wB97M_V_def2_SVPD_PCM_Force = "wB97M-V/def2-SVPD/PCM Force" wB97M_V_def2_SVPD_PCM_Frequency_Analysis = ( "wB97M-V/def2-SVPD/PCM Frequency Analysis" ) wB97M_V_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_SVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-SVPD/PCM Geometry Optimization" ) wB97M_V_def2_SVPD_PCM_Single_Point = "wB97M-V/def2-SVPD/PCM Single Point" wB97M_V_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/PCM Transition State Geometry Optimization" ) wB97M_V_def2_SVPD_PCM_Unknown = "wB97M-V/def2-SVPD/PCM Unknown" wB97M_V_def2_SVPD_SMD_Force = "wB97M-V/def2-SVPD/SMD Force" wB97M_V_def2_SVPD_SMD_Frequency_Analysis = ( "wB97M-V/def2-SVPD/SMD Frequency Analysis" ) wB97M_V_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_SVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-SVPD/SMD Geometry Optimization" ) wB97M_V_def2_SVPD_SMD_Single_Point = "wB97M-V/def2-SVPD/SMD Single Point" wB97M_V_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/SMD Transition State Geometry Optimization" ) wB97M_V_def2_SVPD_SMD_Unknown = "wB97M-V/def2-SVPD/SMD Unknown" wB97M_V_def2_SVPD_VACUUM_Force = "wB97M-V/def2-SVPD/VACUUM Force" wB97M_V_def2_SVPD_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-SVPD/VACUUM Frequency Analysis" ) wB97M_V_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-SVPD/VACUUM Geometry Optimization" ) wB97M_V_def2_SVPD_VACUUM_Single_Point = "wB97M-V/def2-SVPD/VACUUM Single Point" wB97M_V_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_SVPD_VACUUM_Unknown = "wB97M-V/def2-SVPD/VACUUM Unknown" wB97M_V_def2_TZVPD_PCM_Force = "wB97M-V/def2-TZVPD/PCM Force" wB97M_V_def2_TZVPD_PCM_Frequency_Analysis = ( "wB97M-V/def2-TZVPD/PCM Frequency Analysis" ) wB97M_V_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/PCM Geometry Optimization" ) wB97M_V_def2_TZVPD_PCM_Single_Point = "wB97M-V/def2-TZVPD/PCM Single Point" wB97M_V_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/PCM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPD_PCM_Unknown = "wB97M-V/def2-TZVPD/PCM Unknown" wB97M_V_def2_TZVPD_SMD_Force = "wB97M-V/def2-TZVPD/SMD Force" wB97M_V_def2_TZVPD_SMD_Frequency_Analysis = ( "wB97M-V/def2-TZVPD/SMD Frequency Analysis" ) wB97M_V_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/SMD Geometry Optimization" ) wB97M_V_def2_TZVPD_SMD_Single_Point = "wB97M-V/def2-TZVPD/SMD Single Point" wB97M_V_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/SMD Transition State Geometry Optimization" ) wB97M_V_def2_TZVPD_SMD_Unknown = "wB97M-V/def2-TZVPD/SMD Unknown" wB97M_V_def2_TZVPD_VACUUM_Force = "wB97M-V/def2-TZVPD/VACUUM Force" wB97M_V_def2_TZVPD_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-TZVPD/VACUUM Frequency Analysis" ) wB97M_V_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/VACUUM Geometry Optimization" ) wB97M_V_def2_TZVPD_VACUUM_Single_Point = "wB97M-V/def2-TZVPD/VACUUM Single Point" wB97M_V_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPD_VACUUM_Unknown = "wB97M-V/def2-TZVPD/VACUUM Unknown" wB97M_V_def2_TZVPPD_PCM_Force = "wB97M-V/def2-TZVPPD/PCM Force" wB97M_V_def2_TZVPPD_PCM_Frequency_Analysis = ( "wB97M-V/def2-TZVPPD/PCM Frequency Analysis" ) wB97M_V_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/PCM Geometry Optimization" ) wB97M_V_def2_TZVPPD_PCM_Single_Point = "wB97M-V/def2-TZVPPD/PCM Single Point" wB97M_V_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/PCM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPPD_PCM_Unknown = "wB97M-V/def2-TZVPPD/PCM Unknown" wB97M_V_def2_TZVPPD_SMD_Force = "wB97M-V/def2-TZVPPD/SMD Force" wB97M_V_def2_TZVPPD_SMD_Frequency_Analysis = ( "wB97M-V/def2-TZVPPD/SMD Frequency Analysis" ) wB97M_V_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/SMD Geometry Optimization" ) wB97M_V_def2_TZVPPD_SMD_Single_Point = "wB97M-V/def2-TZVPPD/SMD Single Point" wB97M_V_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/SMD Transition State Geometry Optimization" ) wB97M_V_def2_TZVPPD_SMD_Unknown = "wB97M-V/def2-TZVPPD/SMD Unknown" wB97M_V_def2_TZVPPD_VACUUM_Force = "wB97M-V/def2-TZVPPD/VACUUM Force" wB97M_V_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-TZVPPD/VACUUM Frequency Analysis" ) wB97M_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/VACUUM Geometry Optimization" ) wB97M_V_def2_TZVPPD_VACUUM_Single_Point = "wB97M-V/def2-TZVPPD/VACUUM Single Point" wB97M_V_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPPD_VACUUM_Unknown = "wB97M-V/def2-TZVPPD/VACUUM Unknown" wB97M_V_def2_TZVPP_PCM_Force = "wB97M-V/def2-TZVPP/PCM Force" wB97M_V_def2_TZVPP_PCM_Frequency_Analysis = ( "wB97M-V/def2-TZVPP/PCM Frequency Analysis" ) wB97M_V_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/PCM Geometry Optimization" ) wB97M_V_def2_TZVPP_PCM_Single_Point = "wB97M-V/def2-TZVPP/PCM Single Point" wB97M_V_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/PCM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPP_PCM_Unknown = "wB97M-V/def2-TZVPP/PCM Unknown" wB97M_V_def2_TZVPP_SMD_Force = "wB97M-V/def2-TZVPP/SMD Force" wB97M_V_def2_TZVPP_SMD_Frequency_Analysis = ( "wB97M-V/def2-TZVPP/SMD Frequency Analysis" ) wB97M_V_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/SMD Geometry Optimization" ) wB97M_V_def2_TZVPP_SMD_Single_Point = "wB97M-V/def2-TZVPP/SMD Single Point" wB97M_V_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/SMD Transition State Geometry Optimization" ) wB97M_V_def2_TZVPP_SMD_Unknown = "wB97M-V/def2-TZVPP/SMD Unknown" wB97M_V_def2_TZVPP_VACUUM_Force = "wB97M-V/def2-TZVPP/VACUUM Force" wB97M_V_def2_TZVPP_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-TZVPP/VACUUM Frequency Analysis" ) wB97M_V_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/VACUUM Geometry Optimization" ) wB97M_V_def2_TZVPP_VACUUM_Single_Point = "wB97M-V/def2-TZVPP/VACUUM Single Point" wB97M_V_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_TZVPP_VACUUM_Unknown = "wB97M-V/def2-TZVPP/VACUUM Unknown" wB97M_V_def2_TZVP_PCM_Force = "wB97M-V/def2-TZVP/PCM Force" wB97M_V_def2_TZVP_PCM_Frequency_Analysis = ( "wB97M-V/def2-TZVP/PCM Frequency Analysis" ) wB97M_V_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVP_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVP/PCM Geometry Optimization" ) wB97M_V_def2_TZVP_PCM_Single_Point = "wB97M-V/def2-TZVP/PCM Single Point" wB97M_V_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/PCM Transition State Geometry Optimization" ) wB97M_V_def2_TZVP_PCM_Unknown = "wB97M-V/def2-TZVP/PCM Unknown" wB97M_V_def2_TZVP_SMD_Force = "wB97M-V/def2-TZVP/SMD Force" wB97M_V_def2_TZVP_SMD_Frequency_Analysis = ( "wB97M-V/def2-TZVP/SMD Frequency Analysis" ) wB97M_V_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVP_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVP/SMD Geometry Optimization" ) wB97M_V_def2_TZVP_SMD_Single_Point = "wB97M-V/def2-TZVP/SMD Single Point" wB97M_V_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/SMD Transition State Geometry Optimization" ) wB97M_V_def2_TZVP_SMD_Unknown = "wB97M-V/def2-TZVP/SMD Unknown" wB97M_V_def2_TZVP_VACUUM_Force = "wB97M-V/def2-TZVP/VACUUM Force" wB97M_V_def2_TZVP_VACUUM_Frequency_Analysis = ( "wB97M-V/def2-TZVP/VACUUM Frequency Analysis" ) wB97M_V_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97M-V/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) wB97M_V_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97M-V/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97M_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVP/VACUUM Geometry Optimization" ) wB97M_V_def2_TZVP_VACUUM_Single_Point = "wB97M-V/def2-TZVP/VACUUM Single Point" wB97M_V_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/VACUUM Transition State Geometry Optimization" ) wB97M_V_def2_TZVP_VACUUM_Unknown = "wB97M-V/def2-TZVP/VACUUM Unknown" wB97X_D3_6_31g_d_PCM_Force = "wB97X-D3/6-31g*/PCM Force" wB97X_D3_6_31g_d_PCM_Frequency_Analysis = "wB97X-D3/6-31g*/PCM Frequency Analysis" wB97X_D3_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/6-31g*/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-D3/6-31g*/PCM Geometry Optimization" ) wB97X_D3_6_31g_d_PCM_Single_Point = "wB97X-D3/6-31g*/PCM Single Point" wB97X_D3_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/PCM Transition State Geometry Optimization" ) wB97X_D3_6_31g_d_PCM_Unknown = "wB97X-D3/6-31g*/PCM Unknown" wB97X_D3_6_31g_d_SMD_Force = "wB97X-D3/6-31g*/SMD Force" wB97X_D3_6_31g_d_SMD_Frequency_Analysis = "wB97X-D3/6-31g*/SMD Frequency Analysis" wB97X_D3_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/6-31g*/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-D3/6-31g*/SMD Geometry Optimization" ) wB97X_D3_6_31g_d_SMD_Single_Point = "wB97X-D3/6-31g*/SMD Single Point" wB97X_D3_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/SMD Transition State Geometry Optimization" ) wB97X_D3_6_31g_d_SMD_Unknown = "wB97X-D3/6-31g*/SMD Unknown" wB97X_D3_6_31g_d_VACUUM_Force = "wB97X-D3/6-31g*/VACUUM Force" wB97X_D3_6_31g_d_VACUUM_Frequency_Analysis = ( "wB97X-D3/6-31g*/VACUUM Frequency Analysis" ) wB97X_D3_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-D3/6-31g*/VACUUM Geometry Optimization" ) wB97X_D3_6_31g_d_VACUUM_Single_Point = "wB97X-D3/6-31g*/VACUUM Single Point" wB97X_D3_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/VACUUM Transition State Geometry Optimization" ) wB97X_D3_6_31g_d_VACUUM_Unknown = "wB97X-D3/6-31g*/VACUUM Unknown" wB97X_D3_def2_QZVPD_PCM_Force = "wB97X-D3/def2-QZVPD/PCM Force" wB97X_D3_def2_QZVPD_PCM_Frequency_Analysis = ( "wB97X-D3/def2-QZVPD/PCM Frequency Analysis" ) wB97X_D3_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/PCM Geometry Optimization" ) wB97X_D3_def2_QZVPD_PCM_Single_Point = "wB97X-D3/def2-QZVPD/PCM Single Point" wB97X_D3_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPD_PCM_Unknown = "wB97X-D3/def2-QZVPD/PCM Unknown" wB97X_D3_def2_QZVPD_SMD_Force = "wB97X-D3/def2-QZVPD/SMD Force" wB97X_D3_def2_QZVPD_SMD_Frequency_Analysis = ( "wB97X-D3/def2-QZVPD/SMD Frequency Analysis" ) wB97X_D3_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/SMD Geometry Optimization" ) wB97X_D3_def2_QZVPD_SMD_Single_Point = "wB97X-D3/def2-QZVPD/SMD Single Point" wB97X_D3_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPD_SMD_Unknown = "wB97X-D3/def2-QZVPD/SMD Unknown" wB97X_D3_def2_QZVPD_VACUUM_Force = "wB97X-D3/def2-QZVPD/VACUUM Force" wB97X_D3_def2_QZVPD_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-QZVPD/VACUUM Frequency Analysis" ) wB97X_D3_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/VACUUM Geometry Optimization" ) wB97X_D3_def2_QZVPD_VACUUM_Single_Point = "wB97X-D3/def2-QZVPD/VACUUM Single Point" wB97X_D3_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPD_VACUUM_Unknown = "wB97X-D3/def2-QZVPD/VACUUM Unknown" wB97X_D3_def2_QZVPPD_PCM_Force = "wB97X-D3/def2-QZVPPD/PCM Force" wB97X_D3_def2_QZVPPD_PCM_Frequency_Analysis = ( "wB97X-D3/def2-QZVPPD/PCM Frequency Analysis" ) wB97X_D3_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/PCM Geometry Optimization" ) wB97X_D3_def2_QZVPPD_PCM_Single_Point = "wB97X-D3/def2-QZVPPD/PCM Single Point" wB97X_D3_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPPD_PCM_Unknown = "wB97X-D3/def2-QZVPPD/PCM Unknown" wB97X_D3_def2_QZVPPD_SMD_Force = "wB97X-D3/def2-QZVPPD/SMD Force" wB97X_D3_def2_QZVPPD_SMD_Frequency_Analysis = ( "wB97X-D3/def2-QZVPPD/SMD Frequency Analysis" ) wB97X_D3_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/SMD Geometry Optimization" ) wB97X_D3_def2_QZVPPD_SMD_Single_Point = "wB97X-D3/def2-QZVPPD/SMD Single Point" wB97X_D3_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPPD_SMD_Unknown = "wB97X-D3/def2-QZVPPD/SMD Unknown" wB97X_D3_def2_QZVPPD_VACUUM_Force = "wB97X-D3/def2-QZVPPD/VACUUM Force" wB97X_D3_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-QZVPPD/VACUUM Frequency Analysis" ) wB97X_D3_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/VACUUM Geometry Optimization" ) wB97X_D3_def2_QZVPPD_VACUUM_Single_Point = ( "wB97X-D3/def2-QZVPPD/VACUUM Single Point" ) wB97X_D3_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_QZVPPD_VACUUM_Unknown = "wB97X-D3/def2-QZVPPD/VACUUM Unknown" wB97X_D3_def2_SVPD_PCM_Force = "wB97X-D3/def2-SVPD/PCM Force" wB97X_D3_def2_SVPD_PCM_Frequency_Analysis = ( "wB97X-D3/def2-SVPD/PCM Frequency Analysis" ) wB97X_D3_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/PCM Geometry Optimization" ) wB97X_D3_def2_SVPD_PCM_Single_Point = "wB97X-D3/def2-SVPD/PCM Single Point" wB97X_D3_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_SVPD_PCM_Unknown = "wB97X-D3/def2-SVPD/PCM Unknown" wB97X_D3_def2_SVPD_SMD_Force = "wB97X-D3/def2-SVPD/SMD Force" wB97X_D3_def2_SVPD_SMD_Frequency_Analysis = ( "wB97X-D3/def2-SVPD/SMD Frequency Analysis" ) wB97X_D3_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/SMD Geometry Optimization" ) wB97X_D3_def2_SVPD_SMD_Single_Point = "wB97X-D3/def2-SVPD/SMD Single Point" wB97X_D3_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_SVPD_SMD_Unknown = "wB97X-D3/def2-SVPD/SMD Unknown" wB97X_D3_def2_SVPD_VACUUM_Force = "wB97X-D3/def2-SVPD/VACUUM Force" wB97X_D3_def2_SVPD_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-SVPD/VACUUM Frequency Analysis" ) wB97X_D3_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/VACUUM Geometry Optimization" ) wB97X_D3_def2_SVPD_VACUUM_Single_Point = "wB97X-D3/def2-SVPD/VACUUM Single Point" wB97X_D3_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_SVPD_VACUUM_Unknown = "wB97X-D3/def2-SVPD/VACUUM Unknown" wB97X_D3_def2_TZVPD_PCM_Force = "wB97X-D3/def2-TZVPD/PCM Force" wB97X_D3_def2_TZVPD_PCM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPD/PCM Frequency Analysis" ) wB97X_D3_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/PCM Geometry Optimization" ) wB97X_D3_def2_TZVPD_PCM_Single_Point = "wB97X-D3/def2-TZVPD/PCM Single Point" wB97X_D3_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPD_PCM_Unknown = "wB97X-D3/def2-TZVPD/PCM Unknown" wB97X_D3_def2_TZVPD_SMD_Force = "wB97X-D3/def2-TZVPD/SMD Force" wB97X_D3_def2_TZVPD_SMD_Frequency_Analysis = ( "wB97X-D3/def2-TZVPD/SMD Frequency Analysis" ) wB97X_D3_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/SMD Geometry Optimization" ) wB97X_D3_def2_TZVPD_SMD_Single_Point = "wB97X-D3/def2-TZVPD/SMD Single Point" wB97X_D3_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPD_SMD_Unknown = "wB97X-D3/def2-TZVPD/SMD Unknown" wB97X_D3_def2_TZVPD_VACUUM_Force = "wB97X-D3/def2-TZVPD/VACUUM Force" wB97X_D3_def2_TZVPD_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPD/VACUUM Frequency Analysis" ) wB97X_D3_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/VACUUM Geometry Optimization" ) wB97X_D3_def2_TZVPD_VACUUM_Single_Point = "wB97X-D3/def2-TZVPD/VACUUM Single Point" wB97X_D3_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPD_VACUUM_Unknown = "wB97X-D3/def2-TZVPD/VACUUM Unknown" wB97X_D3_def2_TZVPPD_PCM_Force = "wB97X-D3/def2-TZVPPD/PCM Force" wB97X_D3_def2_TZVPPD_PCM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPPD/PCM Frequency Analysis" ) wB97X_D3_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/PCM Geometry Optimization" ) wB97X_D3_def2_TZVPPD_PCM_Single_Point = "wB97X-D3/def2-TZVPPD/PCM Single Point" wB97X_D3_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPPD_PCM_Unknown = "wB97X-D3/def2-TZVPPD/PCM Unknown" wB97X_D3_def2_TZVPPD_SMD_Force = "wB97X-D3/def2-TZVPPD/SMD Force" wB97X_D3_def2_TZVPPD_SMD_Frequency_Analysis = ( "wB97X-D3/def2-TZVPPD/SMD Frequency Analysis" ) wB97X_D3_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/SMD Geometry Optimization" ) wB97X_D3_def2_TZVPPD_SMD_Single_Point = "wB97X-D3/def2-TZVPPD/SMD Single Point" wB97X_D3_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPPD_SMD_Unknown = "wB97X-D3/def2-TZVPPD/SMD Unknown" wB97X_D3_def2_TZVPPD_VACUUM_Force = "wB97X-D3/def2-TZVPPD/VACUUM Force" wB97X_D3_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPPD/VACUUM Frequency Analysis" ) wB97X_D3_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/VACUUM Geometry Optimization" ) wB97X_D3_def2_TZVPPD_VACUUM_Single_Point = ( "wB97X-D3/def2-TZVPPD/VACUUM Single Point" ) wB97X_D3_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPPD_VACUUM_Unknown = "wB97X-D3/def2-TZVPPD/VACUUM Unknown" wB97X_D3_def2_TZVPP_PCM_Force = "wB97X-D3/def2-TZVPP/PCM Force" wB97X_D3_def2_TZVPP_PCM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPP/PCM Frequency Analysis" ) wB97X_D3_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/PCM Geometry Optimization" ) wB97X_D3_def2_TZVPP_PCM_Single_Point = "wB97X-D3/def2-TZVPP/PCM Single Point" wB97X_D3_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPP_PCM_Unknown = "wB97X-D3/def2-TZVPP/PCM Unknown" wB97X_D3_def2_TZVPP_SMD_Force = "wB97X-D3/def2-TZVPP/SMD Force" wB97X_D3_def2_TZVPP_SMD_Frequency_Analysis = ( "wB97X-D3/def2-TZVPP/SMD Frequency Analysis" ) wB97X_D3_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/SMD Geometry Optimization" ) wB97X_D3_def2_TZVPP_SMD_Single_Point = "wB97X-D3/def2-TZVPP/SMD Single Point" wB97X_D3_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPP_SMD_Unknown = "wB97X-D3/def2-TZVPP/SMD Unknown" wB97X_D3_def2_TZVPP_VACUUM_Force = "wB97X-D3/def2-TZVPP/VACUUM Force" wB97X_D3_def2_TZVPP_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-TZVPP/VACUUM Frequency Analysis" ) wB97X_D3_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/VACUUM Geometry Optimization" ) wB97X_D3_def2_TZVPP_VACUUM_Single_Point = "wB97X-D3/def2-TZVPP/VACUUM Single Point" wB97X_D3_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVPP_VACUUM_Unknown = "wB97X-D3/def2-TZVPP/VACUUM Unknown" wB97X_D3_def2_TZVP_PCM_Force = "wB97X-D3/def2-TZVP/PCM Force" wB97X_D3_def2_TZVP_PCM_Frequency_Analysis = ( "wB97X-D3/def2-TZVP/PCM Frequency Analysis" ) wB97X_D3_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/PCM Geometry Optimization" ) wB97X_D3_def2_TZVP_PCM_Single_Point = "wB97X-D3/def2-TZVP/PCM Single Point" wB97X_D3_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/PCM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVP_PCM_Unknown = "wB97X-D3/def2-TZVP/PCM Unknown" wB97X_D3_def2_TZVP_SMD_Force = "wB97X-D3/def2-TZVP/SMD Force" wB97X_D3_def2_TZVP_SMD_Frequency_Analysis = ( "wB97X-D3/def2-TZVP/SMD Frequency Analysis" ) wB97X_D3_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/SMD Geometry Optimization" ) wB97X_D3_def2_TZVP_SMD_Single_Point = "wB97X-D3/def2-TZVP/SMD Single Point" wB97X_D3_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/SMD Transition State Geometry Optimization" ) wB97X_D3_def2_TZVP_SMD_Unknown = "wB97X-D3/def2-TZVP/SMD Unknown" wB97X_D3_def2_TZVP_VACUUM_Force = "wB97X-D3/def2-TZVP/VACUUM Force" wB97X_D3_def2_TZVP_VACUUM_Frequency_Analysis = ( "wB97X-D3/def2-TZVP/VACUUM Frequency Analysis" ) wB97X_D3_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D3_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D3/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D3_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/VACUUM Geometry Optimization" ) wB97X_D3_def2_TZVP_VACUUM_Single_Point = "wB97X-D3/def2-TZVP/VACUUM Single Point" wB97X_D3_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/VACUUM Transition State Geometry Optimization" ) wB97X_D3_def2_TZVP_VACUUM_Unknown = "wB97X-D3/def2-TZVP/VACUUM Unknown" wB97X_D_6_31g_d_PCM_Force = "wB97X-D/6-31g*/PCM Force" wB97X_D_6_31g_d_PCM_Frequency_Analysis = "wB97X-D/6-31g*/PCM Frequency Analysis" wB97X_D_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) wB97X_D_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Geometry Optimization" ) wB97X_D_6_31g_d_PCM_Single_Point = "wB97X-D/6-31g*/PCM Single Point" wB97X_D_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Transition State Geometry Optimization" ) wB97X_D_6_31g_d_PCM_Unknown = "wB97X-D/6-31g*/PCM Unknown" wB97X_D_6_31g_d_SMD_Force = "wB97X-D/6-31g*/SMD Force" wB97X_D_6_31g_d_SMD_Frequency_Analysis = "wB97X-D/6-31g*/SMD Frequency Analysis" wB97X_D_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) wB97X_D_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Geometry Optimization" ) wB97X_D_6_31g_d_SMD_Single_Point = "wB97X-D/6-31g*/SMD Single Point" wB97X_D_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Transition State Geometry Optimization" ) wB97X_D_6_31g_d_SMD_Unknown = "wB97X-D/6-31g*/SMD Unknown" wB97X_D_6_31g_d_VACUUM_Force = "wB97X-D/6-31g*/VACUUM Force" wB97X_D_6_31g_d_VACUUM_Frequency_Analysis = ( "wB97X-D/6-31g*/VACUUM Frequency Analysis" ) wB97X_D_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-D/6-31g*/VACUUM Geometry Optimization" ) wB97X_D_6_31g_d_VACUUM_Single_Point = "wB97X-D/6-31g*/VACUUM Single Point" wB97X_D_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/VACUUM Transition State Geometry Optimization" ) wB97X_D_6_31g_d_VACUUM_Unknown = "wB97X-D/6-31g*/VACUUM Unknown" wB97X_D_def2_QZVPD_PCM_Force = "wB97X-D/def2-QZVPD/PCM Force" wB97X_D_def2_QZVPD_PCM_Frequency_Analysis = ( "wB97X-D/def2-QZVPD/PCM Frequency Analysis" ) wB97X_D_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/PCM Geometry Optimization" ) wB97X_D_def2_QZVPD_PCM_Single_Point = "wB97X-D/def2-QZVPD/PCM Single Point" wB97X_D_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/PCM Transition State Geometry Optimization" ) wB97X_D_def2_QZVPD_PCM_Unknown = "wB97X-D/def2-QZVPD/PCM Unknown" wB97X_D_def2_QZVPD_SMD_Force = "wB97X-D/def2-QZVPD/SMD Force" wB97X_D_def2_QZVPD_SMD_Frequency_Analysis = ( "wB97X-D/def2-QZVPD/SMD Frequency Analysis" ) wB97X_D_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/SMD Geometry Optimization" ) wB97X_D_def2_QZVPD_SMD_Single_Point = "wB97X-D/def2-QZVPD/SMD Single Point" wB97X_D_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/SMD Transition State Geometry Optimization" ) wB97X_D_def2_QZVPD_SMD_Unknown = "wB97X-D/def2-QZVPD/SMD Unknown" wB97X_D_def2_QZVPD_VACUUM_Force = "wB97X-D/def2-QZVPD/VACUUM Force" wB97X_D_def2_QZVPD_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-QZVPD/VACUUM Frequency Analysis" ) wB97X_D_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/VACUUM Geometry Optimization" ) wB97X_D_def2_QZVPD_VACUUM_Single_Point = "wB97X-D/def2-QZVPD/VACUUM Single Point" wB97X_D_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_QZVPD_VACUUM_Unknown = "wB97X-D/def2-QZVPD/VACUUM Unknown" wB97X_D_def2_QZVPPD_PCM_Force = "wB97X-D/def2-QZVPPD/PCM Force" wB97X_D_def2_QZVPPD_PCM_Frequency_Analysis = ( "wB97X-D/def2-QZVPPD/PCM Frequency Analysis" ) wB97X_D_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/PCM Geometry Optimization" ) wB97X_D_def2_QZVPPD_PCM_Single_Point = "wB97X-D/def2-QZVPPD/PCM Single Point" wB97X_D_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/PCM Transition State Geometry Optimization" ) wB97X_D_def2_QZVPPD_PCM_Unknown = "wB97X-D/def2-QZVPPD/PCM Unknown" wB97X_D_def2_QZVPPD_SMD_Force = "wB97X-D/def2-QZVPPD/SMD Force" wB97X_D_def2_QZVPPD_SMD_Frequency_Analysis = ( "wB97X-D/def2-QZVPPD/SMD Frequency Analysis" ) wB97X_D_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/SMD Geometry Optimization" ) wB97X_D_def2_QZVPPD_SMD_Single_Point = "wB97X-D/def2-QZVPPD/SMD Single Point" wB97X_D_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/SMD Transition State Geometry Optimization" ) wB97X_D_def2_QZVPPD_SMD_Unknown = "wB97X-D/def2-QZVPPD/SMD Unknown" wB97X_D_def2_QZVPPD_VACUUM_Force = "wB97X-D/def2-QZVPPD/VACUUM Force" wB97X_D_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-QZVPPD/VACUUM Frequency Analysis" ) wB97X_D_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/VACUUM Geometry Optimization" ) wB97X_D_def2_QZVPPD_VACUUM_Single_Point = "wB97X-D/def2-QZVPPD/VACUUM Single Point" wB97X_D_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_QZVPPD_VACUUM_Unknown = "wB97X-D/def2-QZVPPD/VACUUM Unknown" wB97X_D_def2_SVPD_PCM_Force = "wB97X-D/def2-SVPD/PCM Force" wB97X_D_def2_SVPD_PCM_Frequency_Analysis = ( "wB97X-D/def2-SVPD/PCM Frequency Analysis" ) wB97X_D_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-SVPD/PCM Geometry Optimization" ) wB97X_D_def2_SVPD_PCM_Single_Point = "wB97X-D/def2-SVPD/PCM Single Point" wB97X_D_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/PCM Transition State Geometry Optimization" ) wB97X_D_def2_SVPD_PCM_Unknown = "wB97X-D/def2-SVPD/PCM Unknown" wB97X_D_def2_SVPD_SMD_Force = "wB97X-D/def2-SVPD/SMD Force" wB97X_D_def2_SVPD_SMD_Frequency_Analysis = ( "wB97X-D/def2-SVPD/SMD Frequency Analysis" ) wB97X_D_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-SVPD/SMD Geometry Optimization" ) wB97X_D_def2_SVPD_SMD_Single_Point = "wB97X-D/def2-SVPD/SMD Single Point" wB97X_D_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/SMD Transition State Geometry Optimization" ) wB97X_D_def2_SVPD_SMD_Unknown = "wB97X-D/def2-SVPD/SMD Unknown" wB97X_D_def2_SVPD_VACUUM_Force = "wB97X-D/def2-SVPD/VACUUM Force" wB97X_D_def2_SVPD_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-SVPD/VACUUM Frequency Analysis" ) wB97X_D_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-SVPD/VACUUM Geometry Optimization" ) wB97X_D_def2_SVPD_VACUUM_Single_Point = "wB97X-D/def2-SVPD/VACUUM Single Point" wB97X_D_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_SVPD_VACUUM_Unknown = "wB97X-D/def2-SVPD/VACUUM Unknown" wB97X_D_def2_TZVPD_PCM_Force = "wB97X-D/def2-TZVPD/PCM Force" wB97X_D_def2_TZVPD_PCM_Frequency_Analysis = ( "wB97X-D/def2-TZVPD/PCM Frequency Analysis" ) wB97X_D_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/PCM Geometry Optimization" ) wB97X_D_def2_TZVPD_PCM_Single_Point = "wB97X-D/def2-TZVPD/PCM Single Point" wB97X_D_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/PCM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPD_PCM_Unknown = "wB97X-D/def2-TZVPD/PCM Unknown" wB97X_D_def2_TZVPD_SMD_Force = "wB97X-D/def2-TZVPD/SMD Force" wB97X_D_def2_TZVPD_SMD_Frequency_Analysis = ( "wB97X-D/def2-TZVPD/SMD Frequency Analysis" ) wB97X_D_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/SMD Geometry Optimization" ) wB97X_D_def2_TZVPD_SMD_Single_Point = "wB97X-D/def2-TZVPD/SMD Single Point" wB97X_D_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/SMD Transition State Geometry Optimization" ) wB97X_D_def2_TZVPD_SMD_Unknown = "wB97X-D/def2-TZVPD/SMD Unknown" wB97X_D_def2_TZVPD_VACUUM_Force = "wB97X-D/def2-TZVPD/VACUUM Force" wB97X_D_def2_TZVPD_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-TZVPD/VACUUM Frequency Analysis" ) wB97X_D_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/VACUUM Geometry Optimization" ) wB97X_D_def2_TZVPD_VACUUM_Single_Point = "wB97X-D/def2-TZVPD/VACUUM Single Point" wB97X_D_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPD_VACUUM_Unknown = "wB97X-D/def2-TZVPD/VACUUM Unknown" wB97X_D_def2_TZVPPD_PCM_Force = "wB97X-D/def2-TZVPPD/PCM Force" wB97X_D_def2_TZVPPD_PCM_Frequency_Analysis = ( "wB97X-D/def2-TZVPPD/PCM Frequency Analysis" ) wB97X_D_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/PCM Geometry Optimization" ) wB97X_D_def2_TZVPPD_PCM_Single_Point = "wB97X-D/def2-TZVPPD/PCM Single Point" wB97X_D_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/PCM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPPD_PCM_Unknown = "wB97X-D/def2-TZVPPD/PCM Unknown" wB97X_D_def2_TZVPPD_SMD_Force = "wB97X-D/def2-TZVPPD/SMD Force" wB97X_D_def2_TZVPPD_SMD_Frequency_Analysis = ( "wB97X-D/def2-TZVPPD/SMD Frequency Analysis" ) wB97X_D_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/SMD Geometry Optimization" ) wB97X_D_def2_TZVPPD_SMD_Single_Point = "wB97X-D/def2-TZVPPD/SMD Single Point" wB97X_D_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/SMD Transition State Geometry Optimization" ) wB97X_D_def2_TZVPPD_SMD_Unknown = "wB97X-D/def2-TZVPPD/SMD Unknown" wB97X_D_def2_TZVPPD_VACUUM_Force = "wB97X-D/def2-TZVPPD/VACUUM Force" wB97X_D_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-TZVPPD/VACUUM Frequency Analysis" ) wB97X_D_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/VACUUM Geometry Optimization" ) wB97X_D_def2_TZVPPD_VACUUM_Single_Point = "wB97X-D/def2-TZVPPD/VACUUM Single Point" wB97X_D_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPPD_VACUUM_Unknown = "wB97X-D/def2-TZVPPD/VACUUM Unknown" wB97X_D_def2_TZVPP_PCM_Force = "wB97X-D/def2-TZVPP/PCM Force" wB97X_D_def2_TZVPP_PCM_Frequency_Analysis = ( "wB97X-D/def2-TZVPP/PCM Frequency Analysis" ) wB97X_D_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/PCM Geometry Optimization" ) wB97X_D_def2_TZVPP_PCM_Single_Point = "wB97X-D/def2-TZVPP/PCM Single Point" wB97X_D_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/PCM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPP_PCM_Unknown = "wB97X-D/def2-TZVPP/PCM Unknown" wB97X_D_def2_TZVPP_SMD_Force = "wB97X-D/def2-TZVPP/SMD Force" wB97X_D_def2_TZVPP_SMD_Frequency_Analysis = ( "wB97X-D/def2-TZVPP/SMD Frequency Analysis" ) wB97X_D_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/SMD Geometry Optimization" ) wB97X_D_def2_TZVPP_SMD_Single_Point = "wB97X-D/def2-TZVPP/SMD Single Point" wB97X_D_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/SMD Transition State Geometry Optimization" ) wB97X_D_def2_TZVPP_SMD_Unknown = "wB97X-D/def2-TZVPP/SMD Unknown" wB97X_D_def2_TZVPP_VACUUM_Force = "wB97X-D/def2-TZVPP/VACUUM Force" wB97X_D_def2_TZVPP_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-TZVPP/VACUUM Frequency Analysis" ) wB97X_D_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/VACUUM Geometry Optimization" ) wB97X_D_def2_TZVPP_VACUUM_Single_Point = "wB97X-D/def2-TZVPP/VACUUM Single Point" wB97X_D_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_TZVPP_VACUUM_Unknown = "wB97X-D/def2-TZVPP/VACUUM Unknown" wB97X_D_def2_TZVP_PCM_Force = "wB97X-D/def2-TZVP/PCM Force" wB97X_D_def2_TZVP_PCM_Frequency_Analysis = ( "wB97X-D/def2-TZVP/PCM Frequency Analysis" ) wB97X_D_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVP/PCM Geometry Optimization" ) wB97X_D_def2_TZVP_PCM_Single_Point = "wB97X-D/def2-TZVP/PCM Single Point" wB97X_D_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/PCM Transition State Geometry Optimization" ) wB97X_D_def2_TZVP_PCM_Unknown = "wB97X-D/def2-TZVP/PCM Unknown" wB97X_D_def2_TZVP_SMD_Force = "wB97X-D/def2-TZVP/SMD Force" wB97X_D_def2_TZVP_SMD_Frequency_Analysis = ( "wB97X-D/def2-TZVP/SMD Frequency Analysis" ) wB97X_D_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVP/SMD Geometry Optimization" ) wB97X_D_def2_TZVP_SMD_Single_Point = "wB97X-D/def2-TZVP/SMD Single Point" wB97X_D_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/SMD Transition State Geometry Optimization" ) wB97X_D_def2_TZVP_SMD_Unknown = "wB97X-D/def2-TZVP/SMD Unknown" wB97X_D_def2_TZVP_VACUUM_Force = "wB97X-D/def2-TZVP/VACUUM Force" wB97X_D_def2_TZVP_VACUUM_Frequency_Analysis = ( "wB97X-D/def2-TZVP/VACUUM Frequency Analysis" ) wB97X_D_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-D/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_D_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-D/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_D_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVP/VACUUM Geometry Optimization" ) wB97X_D_def2_TZVP_VACUUM_Single_Point = "wB97X-D/def2-TZVP/VACUUM Single Point" wB97X_D_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/VACUUM Transition State Geometry Optimization" ) wB97X_D_def2_TZVP_VACUUM_Unknown = "wB97X-D/def2-TZVP/VACUUM Unknown" wB97X_V_6_31g_d_PCM_Force = "wB97X-V/6-31g*/PCM Force" wB97X_V_6_31g_d_PCM_Frequency_Analysis = "wB97X-V/6-31g*/PCM Frequency Analysis" wB97X_V_6_31g_d_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_6_31g_d_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Frequency Flattening Transition State Geometry Optimization" ) wB97X_V_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Geometry Optimization" ) wB97X_V_6_31g_d_PCM_Single_Point = "wB97X-V/6-31g*/PCM Single Point" wB97X_V_6_31g_d_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Transition State Geometry Optimization" ) wB97X_V_6_31g_d_PCM_Unknown = "wB97X-V/6-31g*/PCM Unknown" wB97X_V_6_31g_d_SMD_Force = "wB97X-V/6-31g*/SMD Force" wB97X_V_6_31g_d_SMD_Frequency_Analysis = "wB97X-V/6-31g*/SMD Frequency Analysis" wB97X_V_6_31g_d_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_6_31g_d_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Frequency Flattening Transition State Geometry Optimization" ) wB97X_V_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Geometry Optimization" ) wB97X_V_6_31g_d_SMD_Single_Point = "wB97X-V/6-31g*/SMD Single Point" wB97X_V_6_31g_d_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Transition State Geometry Optimization" ) wB97X_V_6_31g_d_SMD_Unknown = "wB97X-V/6-31g*/SMD Unknown" wB97X_V_6_31g_d_VACUUM_Force = "wB97X-V/6-31g*/VACUUM Force" wB97X_V_6_31g_d_VACUUM_Frequency_Analysis = ( "wB97X-V/6-31g*/VACUUM Frequency Analysis" ) wB97X_V_6_31g_d_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/6-31g*/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_6_31g_d_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/6-31g*/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-V/6-31g*/VACUUM Geometry Optimization" ) wB97X_V_6_31g_d_VACUUM_Single_Point = "wB97X-V/6-31g*/VACUUM Single Point" wB97X_V_6_31g_d_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/VACUUM Transition State Geometry Optimization" ) wB97X_V_6_31g_d_VACUUM_Unknown = "wB97X-V/6-31g*/VACUUM Unknown" wB97X_V_def2_QZVPD_PCM_Force = "wB97X-V/def2-QZVPD/PCM Force" wB97X_V_def2_QZVPD_PCM_Frequency_Analysis = ( "wB97X-V/def2-QZVPD/PCM Frequency Analysis" ) wB97X_V_def2_QZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/PCM Geometry Optimization" ) wB97X_V_def2_QZVPD_PCM_Single_Point = "wB97X-V/def2-QZVPD/PCM Single Point" wB97X_V_def2_QZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/PCM Transition State Geometry Optimization" ) wB97X_V_def2_QZVPD_PCM_Unknown = "wB97X-V/def2-QZVPD/PCM Unknown" wB97X_V_def2_QZVPD_SMD_Force = "wB97X-V/def2-QZVPD/SMD Force" wB97X_V_def2_QZVPD_SMD_Frequency_Analysis = ( "wB97X-V/def2-QZVPD/SMD Frequency Analysis" ) wB97X_V_def2_QZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/SMD Geometry Optimization" ) wB97X_V_def2_QZVPD_SMD_Single_Point = "wB97X-V/def2-QZVPD/SMD Single Point" wB97X_V_def2_QZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/SMD Transition State Geometry Optimization" ) wB97X_V_def2_QZVPD_SMD_Unknown = "wB97X-V/def2-QZVPD/SMD Unknown" wB97X_V_def2_QZVPD_VACUUM_Force = "wB97X-V/def2-QZVPD/VACUUM Force" wB97X_V_def2_QZVPD_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-QZVPD/VACUUM Frequency Analysis" ) wB97X_V_def2_QZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/VACUUM Geometry Optimization" ) wB97X_V_def2_QZVPD_VACUUM_Single_Point = "wB97X-V/def2-QZVPD/VACUUM Single Point" wB97X_V_def2_QZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_QZVPD_VACUUM_Unknown = "wB97X-V/def2-QZVPD/VACUUM Unknown" wB97X_V_def2_QZVPPD_PCM_Force = "wB97X-V/def2-QZVPPD/PCM Force" wB97X_V_def2_QZVPPD_PCM_Frequency_Analysis = ( "wB97X-V/def2-QZVPPD/PCM Frequency Analysis" ) wB97X_V_def2_QZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/PCM Geometry Optimization" ) wB97X_V_def2_QZVPPD_PCM_Single_Point = "wB97X-V/def2-QZVPPD/PCM Single Point" wB97X_V_def2_QZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/PCM Transition State Geometry Optimization" ) wB97X_V_def2_QZVPPD_PCM_Unknown = "wB97X-V/def2-QZVPPD/PCM Unknown" wB97X_V_def2_QZVPPD_SMD_Force = "wB97X-V/def2-QZVPPD/SMD Force" wB97X_V_def2_QZVPPD_SMD_Frequency_Analysis = ( "wB97X-V/def2-QZVPPD/SMD Frequency Analysis" ) wB97X_V_def2_QZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/SMD Geometry Optimization" ) wB97X_V_def2_QZVPPD_SMD_Single_Point = "wB97X-V/def2-QZVPPD/SMD Single Point" wB97X_V_def2_QZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/SMD Transition State Geometry Optimization" ) wB97X_V_def2_QZVPPD_SMD_Unknown = "wB97X-V/def2-QZVPPD/SMD Unknown" wB97X_V_def2_QZVPPD_VACUUM_Force = "wB97X-V/def2-QZVPPD/VACUUM Force" wB97X_V_def2_QZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-QZVPPD/VACUUM Frequency Analysis" ) wB97X_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_QZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-QZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/VACUUM Geometry Optimization" ) wB97X_V_def2_QZVPPD_VACUUM_Single_Point = "wB97X-V/def2-QZVPPD/VACUUM Single Point" wB97X_V_def2_QZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_QZVPPD_VACUUM_Unknown = "wB97X-V/def2-QZVPPD/VACUUM Unknown" wB97X_V_def2_SVPD_PCM_Force = "wB97X-V/def2-SVPD/PCM Force" wB97X_V_def2_SVPD_PCM_Frequency_Analysis = ( "wB97X-V/def2-SVPD/PCM Frequency Analysis" ) wB97X_V_def2_SVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-SVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_SVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-SVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-SVPD/PCM Geometry Optimization" ) wB97X_V_def2_SVPD_PCM_Single_Point = "wB97X-V/def2-SVPD/PCM Single Point" wB97X_V_def2_SVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/PCM Transition State Geometry Optimization" ) wB97X_V_def2_SVPD_PCM_Unknown = "wB97X-V/def2-SVPD/PCM Unknown" wB97X_V_def2_SVPD_SMD_Force = "wB97X-V/def2-SVPD/SMD Force" wB97X_V_def2_SVPD_SMD_Frequency_Analysis = ( "wB97X-V/def2-SVPD/SMD Frequency Analysis" ) wB97X_V_def2_SVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-SVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_SVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-SVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-SVPD/SMD Geometry Optimization" ) wB97X_V_def2_SVPD_SMD_Single_Point = "wB97X-V/def2-SVPD/SMD Single Point" wB97X_V_def2_SVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/SMD Transition State Geometry Optimization" ) wB97X_V_def2_SVPD_SMD_Unknown = "wB97X-V/def2-SVPD/SMD Unknown" wB97X_V_def2_SVPD_VACUUM_Force = "wB97X-V/def2-SVPD/VACUUM Force" wB97X_V_def2_SVPD_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-SVPD/VACUUM Frequency Analysis" ) wB97X_V_def2_SVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-SVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_SVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-SVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-SVPD/VACUUM Geometry Optimization" ) wB97X_V_def2_SVPD_VACUUM_Single_Point = "wB97X-V/def2-SVPD/VACUUM Single Point" wB97X_V_def2_SVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_SVPD_VACUUM_Unknown = "wB97X-V/def2-SVPD/VACUUM Unknown" wB97X_V_def2_TZVPD_PCM_Force = "wB97X-V/def2-TZVPD/PCM Force" wB97X_V_def2_TZVPD_PCM_Frequency_Analysis = ( "wB97X-V/def2-TZVPD/PCM Frequency Analysis" ) wB97X_V_def2_TZVPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/PCM Geometry Optimization" ) wB97X_V_def2_TZVPD_PCM_Single_Point = "wB97X-V/def2-TZVPD/PCM Single Point" wB97X_V_def2_TZVPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/PCM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPD_PCM_Unknown = "wB97X-V/def2-TZVPD/PCM Unknown" wB97X_V_def2_TZVPD_SMD_Force = "wB97X-V/def2-TZVPD/SMD Force" wB97X_V_def2_TZVPD_SMD_Frequency_Analysis = ( "wB97X-V/def2-TZVPD/SMD Frequency Analysis" ) wB97X_V_def2_TZVPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/SMD Geometry Optimization" ) wB97X_V_def2_TZVPD_SMD_Single_Point = "wB97X-V/def2-TZVPD/SMD Single Point" wB97X_V_def2_TZVPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/SMD Transition State Geometry Optimization" ) wB97X_V_def2_TZVPD_SMD_Unknown = "wB97X-V/def2-TZVPD/SMD Unknown" wB97X_V_def2_TZVPD_VACUUM_Force = "wB97X-V/def2-TZVPD/VACUUM Force" wB97X_V_def2_TZVPD_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-TZVPD/VACUUM Frequency Analysis" ) wB97X_V_def2_TZVPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/VACUUM Geometry Optimization" ) wB97X_V_def2_TZVPD_VACUUM_Single_Point = "wB97X-V/def2-TZVPD/VACUUM Single Point" wB97X_V_def2_TZVPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPD_VACUUM_Unknown = "wB97X-V/def2-TZVPD/VACUUM Unknown" wB97X_V_def2_TZVPPD_PCM_Force = "wB97X-V/def2-TZVPPD/PCM Force" wB97X_V_def2_TZVPPD_PCM_Frequency_Analysis = ( "wB97X-V/def2-TZVPPD/PCM Frequency Analysis" ) wB97X_V_def2_TZVPPD_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPPD_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPPD/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/PCM Geometry Optimization" ) wB97X_V_def2_TZVPPD_PCM_Single_Point = "wB97X-V/def2-TZVPPD/PCM Single Point" wB97X_V_def2_TZVPPD_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/PCM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPPD_PCM_Unknown = "wB97X-V/def2-TZVPPD/PCM Unknown" wB97X_V_def2_TZVPPD_SMD_Force = "wB97X-V/def2-TZVPPD/SMD Force" wB97X_V_def2_TZVPPD_SMD_Frequency_Analysis = ( "wB97X-V/def2-TZVPPD/SMD Frequency Analysis" ) wB97X_V_def2_TZVPPD_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPPD_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPPD/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/SMD Geometry Optimization" ) wB97X_V_def2_TZVPPD_SMD_Single_Point = "wB97X-V/def2-TZVPPD/SMD Single Point" wB97X_V_def2_TZVPPD_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/SMD Transition State Geometry Optimization" ) wB97X_V_def2_TZVPPD_SMD_Unknown = "wB97X-V/def2-TZVPPD/SMD Unknown" wB97X_V_def2_TZVPPD_VACUUM_Force = "wB97X-V/def2-TZVPPD/VACUUM Force" wB97X_V_def2_TZVPPD_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-TZVPPD/VACUUM Frequency Analysis" ) wB97X_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPPD_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPPD/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/VACUUM Geometry Optimization" ) wB97X_V_def2_TZVPPD_VACUUM_Single_Point = "wB97X-V/def2-TZVPPD/VACUUM Single Point" wB97X_V_def2_TZVPPD_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPPD_VACUUM_Unknown = "wB97X-V/def2-TZVPPD/VACUUM Unknown" wB97X_V_def2_TZVPP_PCM_Force = "wB97X-V/def2-TZVPP/PCM Force" wB97X_V_def2_TZVPP_PCM_Frequency_Analysis = ( "wB97X-V/def2-TZVPP/PCM Frequency Analysis" ) wB97X_V_def2_TZVPP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/PCM Geometry Optimization" ) wB97X_V_def2_TZVPP_PCM_Single_Point = "wB97X-V/def2-TZVPP/PCM Single Point" wB97X_V_def2_TZVPP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/PCM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPP_PCM_Unknown = "wB97X-V/def2-TZVPP/PCM Unknown" wB97X_V_def2_TZVPP_SMD_Force = "wB97X-V/def2-TZVPP/SMD Force" wB97X_V_def2_TZVPP_SMD_Frequency_Analysis = ( "wB97X-V/def2-TZVPP/SMD Frequency Analysis" ) wB97X_V_def2_TZVPP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/SMD Geometry Optimization" ) wB97X_V_def2_TZVPP_SMD_Single_Point = "wB97X-V/def2-TZVPP/SMD Single Point" wB97X_V_def2_TZVPP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/SMD Transition State Geometry Optimization" ) wB97X_V_def2_TZVPP_SMD_Unknown = "wB97X-V/def2-TZVPP/SMD Unknown" wB97X_V_def2_TZVPP_VACUUM_Force = "wB97X-V/def2-TZVPP/VACUUM Force" wB97X_V_def2_TZVPP_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-TZVPP/VACUUM Frequency Analysis" ) wB97X_V_def2_TZVPP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVPP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVPP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/VACUUM Geometry Optimization" ) wB97X_V_def2_TZVPP_VACUUM_Single_Point = "wB97X-V/def2-TZVPP/VACUUM Single Point" wB97X_V_def2_TZVPP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_TZVPP_VACUUM_Unknown = "wB97X-V/def2-TZVPP/VACUUM Unknown" wB97X_V_def2_TZVP_PCM_Force = "wB97X-V/def2-TZVP/PCM Force" wB97X_V_def2_TZVP_PCM_Frequency_Analysis = ( "wB97X-V/def2-TZVP/PCM Frequency Analysis" ) wB97X_V_def2_TZVP_PCM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVP/PCM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVP_PCM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVP/PCM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVP/PCM Geometry Optimization" ) wB97X_V_def2_TZVP_PCM_Single_Point = "wB97X-V/def2-TZVP/PCM Single Point" wB97X_V_def2_TZVP_PCM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/PCM Transition State Geometry Optimization" ) wB97X_V_def2_TZVP_PCM_Unknown = "wB97X-V/def2-TZVP/PCM Unknown" wB97X_V_def2_TZVP_SMD_Force = "wB97X-V/def2-TZVP/SMD Force" wB97X_V_def2_TZVP_SMD_Frequency_Analysis = ( "wB97X-V/def2-TZVP/SMD Frequency Analysis" ) wB97X_V_def2_TZVP_SMD_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVP/SMD Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVP_SMD_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVP/SMD Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVP/SMD Geometry Optimization" ) wB97X_V_def2_TZVP_SMD_Single_Point = "wB97X-V/def2-TZVP/SMD Single Point" wB97X_V_def2_TZVP_SMD_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/SMD Transition State Geometry Optimization" ) wB97X_V_def2_TZVP_SMD_Unknown = "wB97X-V/def2-TZVP/SMD Unknown" wB97X_V_def2_TZVP_VACUUM_Force = "wB97X-V/def2-TZVP/VACUUM Force" wB97X_V_def2_TZVP_VACUUM_Frequency_Analysis = ( "wB97X-V/def2-TZVP/VACUUM Frequency Analysis" ) wB97X_V_def2_TZVP_VACUUM_Frequency_Flattening_Geometry_Optimization = ( "wB97X-V/def2-TZVP/VACUUM Frequency Flattening Geometry Optimization" ) wB97X_V_def2_TZVP_VACUUM_Frequency_Flattening_Transition_State_Geometry_Optimization = "wB97X-V/def2-TZVP/VACUUM Frequency Flattening Transition State Geometry Optimization" wB97X_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVP/VACUUM Geometry Optimization" ) wB97X_V_def2_TZVP_VACUUM_Single_Point = "wB97X-V/def2-TZVP/VACUUM Single Point" wB97X_V_def2_TZVP_VACUUM_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/VACUUM Transition State Geometry Optimization" ) wB97X_V_def2_TZVP_VACUUM_Unknown = "wB97X-V/def2-TZVP/VACUUM Unknown" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calc_types/utils.py0000644000175100001770000001617214673360562022266 0ustar00runnerdocker""" Utilities to determine level of theory, task type, and calculation type for Q-Chem calculations""" from typing import Any, Dict, Optional from emmet.core.qchem.calc_types import LevelOfTheory, CalcType, TaskType from emmet.core.qchem.calc_types.calc_types import ( FUNCTIONALS, BASIS_SETS, ) __author__ = "Evan Spotte-Smith " # TODO : better string translation functional_synonyms = { "b97mv": "b97m-v", "b97mrv": "b97m-rv", "wb97xd": "wb97x-d", "wb97xd3": "wb97x-d3", "wb97xv": "wb97x-v", "wb97mv": "wb97m-v", } smd_synonyms = { "DIELECTRIC=7,230;N=1,410;ALPHA=0,000;BETA=0,859;GAMMA=36,830;PHI=0,000;PSI=0,000": "diglyme", "DIELECTRIC=18,500;N=1,415;ALPHA=0,000;BETA=0,735;GAMMA=20,200;PHI=0,000;PSI=0,000": "3:7 EC:EMC", } def level_of_theory(parameters: Dict[str, Any]) -> LevelOfTheory: """ Returns the level of theory for a calculation, based on the input parameters given to Q-Chem Args: parameters: Dict of Q-Chem input parameters """ funct_raw = parameters.get("rem", dict()).get("method") basis_raw = parameters.get("rem", dict()).get("basis") if funct_raw is None or basis_raw is None: raise ValueError( 'Method and basis must be included in "rem" section ' "of parameters!" ) disp_corr = parameters.get("rem", dict()).get("dft_d") if disp_corr is None: funct_lower = funct_raw.lower() funct_lower = functional_synonyms.get(funct_lower, funct_lower) else: # Replace Q-Chem terms for D3 tails with more common expressions disp_corr = disp_corr.replace("_bj", "(bj)").replace("_zero", "(0)") funct_lower = f"{funct_raw}-{disp_corr}" basis_lower = basis_raw.lower() functional = [f for f in FUNCTIONALS if f.lower() == funct_lower] if not functional: raise ValueError(f"Unexpected functional {funct_lower}!") functional = functional[0] basis = [b for b in BASIS_SETS if b.lower() == basis_lower] if not basis: raise ValueError(f"Unexpected basis set {basis_lower}!") basis = basis[0] solvent_method = parameters["rem"].get("solvent_method", "").lower() if solvent_method == "": solvation = "VACUUM" elif solvent_method in ["pcm", "cosmo"]: solvation = "PCM" # TODO: Add this once added into pymatgen and atomate # elif solvent_method == "isosvp": # if parameters.get("svp", {}).get("idefesr", 0): # solvation = "CMIRS" # else: # solvation = "ISOSVP" elif solvent_method == "smd": solvation = "SMD" else: raise ValueError(f"Unexpected implicit solvent method {solvent_method}!") lot = f"{functional}/{basis}/{solvation}" return LevelOfTheory(lot) def solvent(parameters: Dict[str, Any], custom_smd: Optional[str] = None) -> str: """ Returns the solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ lot = level_of_theory(parameters) solvation = lot.value.split("/")[-1] if solvation == "PCM": dielectric = float(parameters.get("solvent", {}).get("dielectric", 78.39)) dielectric_string = f"{dielectric:.2f}".replace(".", ",") return f"DIELECTRIC={dielectric_string}" # TODO: Add this once added into pymatgen and atomate # elif solvation == "ISOSVP": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # return f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # elif solvation == "CMIRS": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # a = parameters.get("pcm_nonels", {}).get("a") # b = parameters.get("pcm_nonels", {}).get("b") # c = parameters.get("pcm_nonels", {}).get("c") # d = parameters.get("pcm_nonels", {}).get("d") # solvrho = parameters.get("pcm_nonels", {}).get("solvrho") # gamma = parameters.get("pcm_nonels", {}).get("gamma") # # string = f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # for name, (piece, digits) in {"A": (a, 6), "B": (b, 6), "C": (c, 1), "D": (d, 3), # "SOLVRHO": (solvrho, 2), "GAMMA": (gamma, 1)}.items(): # if piece is None: # piecestring = "NONE" # else: # piecestring = f"{name}={round(float(piece), digits)}" # string += "," + piecestring # return string elif solvation == "SMD": solvent = parameters.get("smx", {}).get("solvent", "water") if solvent == "other": if custom_smd is None: raise ValueError( "SMD calculation with solvent=other requires custom_smd!" ) names = ["DIELECTRIC", "N", "ALPHA", "BETA", "GAMMA", "PHI", "PSI"] numbers = [float(x) for x in custom_smd.split(",")] string = "" for name, number in zip(names, numbers): string += f"{name}={number:.3f};" return string.rstrip(",").rstrip(";").replace(".", ",") else: return f"SOLVENT={solvent.upper()}" else: return "NONE" def lot_solvent_string( parameters: Dict[str, Any], custom_smd: Optional[str] = None ) -> str: """ Returns a string representation of the level of theory and solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ lot = level_of_theory(parameters).value solv = solvent(parameters, custom_smd=custom_smd) return f"{lot}({solv})" def task_type(orig: Dict[str, Any], special_run_type: Optional[str] = None) -> TaskType: if special_run_type == "frequency_flattener": return TaskType("Frequency Flattening Geometry Optimization") elif special_run_type == "ts_frequency_flattener": return TaskType("Frequency Flattening Transition State Geometry Optimization") if orig["rem"].get("job_type") == "sp": return TaskType("Single Point") elif orig["rem"].get("job_type") == "force": return TaskType("Force") elif orig["rem"].get("job_type") == "opt": return TaskType("Geometry Optimization") elif orig["rem"].get("job_type") == "ts": return TaskType("Transition State Geometry Optimization") elif orig["rem"].get("job_type") == "freq": return TaskType("Frequency Analysis") return TaskType("Unknown") def calc_type(special_run_type: str, orig: Dict[str, Any]) -> CalcType: """ Determines the calc type Args: inputs: inputs dict with an incar, kpoints, potcar, and poscar dictionaries parameters: Dictionary of VASP parameters from Vasprun.xml """ rt = level_of_theory(orig).value tt = task_type(orig, special_run_type=special_run_type).value return CalcType(f"{rt} {tt}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/calculation.py0000644000175100001770000006145114673360562021276 0ustar00runnerdocker"""Core definitions of a QChem calculation document.""" # mypy: ignore-errors import logging from pathlib import Path from typing import Any, Dict, List, Optional, Union import numpy as np import warnings from pydantic import field_validator, BaseModel, Field, ConfigDict from datetime import datetime from pymatgen.io.qchem.inputs import QCInput from pymatgen.io.qchem.outputs import QCOutput from pymatgen.core.structure import Molecule from collections import OrderedDict import re from emmet.core.qchem.calc_types import ( LevelOfTheory, CalcType, TaskType, ) from emmet.core.qchem.calc_types.calc_types import ( FUNCTIONALS, BASIS_SETS, ) # from emmet.core.qchem.calc_types.em_utils import ( # level_of_theory, # task_type, # calc_type, # ) from emmet.core.qchem.task import QChemStatus functional_synonyms = { "b97mv": "b97m-v", "b97mrv": "b97m-rv", "wb97xd": "wb97x-d", "wb97xd3": "wb97x-d3", "wb97xv": "wb97x-v", "wb97mv": "wb97m-v", } smd_synonyms = { "DIELECTRIC=7,230;N=1,410;ALPHA=0,000;BETA=0,859;GAMMA=36,830;PHI=0,000;PSI=0,000": "diglyme", "DIELECTRIC=18,500;N=1,415;ALPHA=0,000;BETA=0,735;GAMMA=20,200;PHI=0,000;PSI=0,000": "3:7 EC:EMC", } __author__ = "Rishabh D. Guha " logger = logging.getLogger(__name__) # class QChemObject(ValueEnum): # Not sure but can we have something like GRAD and HESS # as QChem data objects class CalculationInput(BaseModel): """ Document defining QChem calculation inputs. """ initial_molecule: Optional[Molecule] = Field( None, description="input molecule geometry before the QChem calculation" ) # parameters: Dict[str, Any] = Field( # None, description = "Parameters from a previous QChem calculation." # ) charge: int = Field(None, description="The charge of the input molecule") rem: Optional[Dict[str, Any]] = Field( None, description="The rem dict of the input file which has all the input parameters", ) job_type: str = Field( None, description="The type of QChem calculation being performed" ) opt: Optional[Dict[str, Any]] = Field( None, description="A dictionary of opt section. For instance atom constraints and fixed atoms. Go to QCInput definition for more details.", ) pcm: Optional[Dict[str, Any]] = Field( None, description="A dictionary for the PCM solvent details if used" ) solvent: Optional[Dict[str, Any]] = Field( None, description="The solvent parameters used if the PCM solvent model has been employed", ) smx: Optional[Dict[str, Any]] = Field( None, description="A dictionary for the solvent parameters if the SMD solvent method has been employed", ) vdw_mode: Optional[str] = Field( None, description="Either atomic or sequential. Used when custon van der Waals radii are used to construct pcm cavity", ) van_der_waals: Optional[Dict[str, Any]] = Field( None, description="The dictionary of the custom van der Waals radii if used" ) scan_variables: Optional[Dict[str, Any]] = Field( None, description="The dictionary of scan variables for torsions or bond stretches", ) tags: Optional[Union[Dict[str, Any], str]] = Field( None, description="Any tags associated with the QChem calculation." ) @classmethod def from_qcinput(cls, qcinput: QCInput) -> "CalculationInput": """ Create a QChem input document from a QCInout object. Parameters ---------- qcinput A QCInput object. Returns -------- CalculationInput The input document. """ return cls( initial_molecule=qcinput.molecule, charge=int(qcinput.molecule.as_dict()["charge"]) if qcinput.molecule.as_dict() else None, rem=qcinput.rem, job_type=qcinput.rem.get("job_type", None), opt=qcinput.opt, pcm=qcinput.pcm, solvent=qcinput.solvent, smx=qcinput.smx, vdw_mode=qcinput.vdw_mode, scan_variables=qcinput.scan, van_der_waals=qcinput.van_der_waals, ) class CalculationOutput(BaseModel): """Document defining QChem calculation outputs.""" optimized_molecule: Optional[Molecule] = Field( None, description="optimized geometry of the molecule after calculation in case of opt, optimization or ts", ) mulliken: Optional[Union[List, Dict[str, Any]]] = Field( None, description="Calculate Mulliken charges on the atoms" ) esp: Optional[Union[List, Dict[str, Any]]] = Field( None, description="Calculated charges on the atoms if esp calculation has been performed", ) resp: Optional[Union[List, Dict[str, Any]]] = Field( None, description="Calculated charges on the atoms if resp calculation has been performed", ) nbo_data: Optional[Dict[str, Any]] = Field( None, description="NBO data if analysis has been performed." ) frequencies: Optional[Union[Dict[str, Any], List]] = Field( None, description="Calculated frequency modes if the job type is freq or frequency", ) frequency_modes: Optional[Union[List, str]] = Field( None, description="The list of calculated frequency mode vectors" ) final_energy: Optional[Union[str, float]] = Field( None, description="The final energy of the molecule after the calculation is complete", ) enthalpy: Optional[Union[str, float]] = Field( None, description="The total enthalpy correction if a frequency calculation has been performed", ) entropy: Optional[Union[str, float]] = Field( None, description="The total entropy of the system if a frequency calculation has been performed", ) scan_energies: Optional[Dict[str, Any]] = Field( None, description="A dictionary of the scan energies with their respective parameters", ) scan_geometries: Optional[Union[List, Dict[str, Any]]] = Field( None, description="optimized geometry of the molecules after the geometric scan" ) scan_molecules: Optional[Union[List, Dict[str, Any], Molecule]] = Field( None, description="The constructed pymatgen molecules from the optimized scan geometries", ) pcm_gradients: Optional[Union[Dict[str, Any], np.ndarray, List]] = Field( None, description="The parsed total gradients after adding the PCM contributions.", ) @field_validator("pcm_gradients", mode="before") @classmethod def validate_pcm_gradients(cls, v): if v is not None and not isinstance(v, (np.ndarray, Dict, List)): raise ValueError( "pcm_gradients must be a numpy array, a dict or a list or None." ) return v cds_gradients: Optional[Union[Dict[str, Any], np.ndarray, List]] = Field( None, description="The parsed CDS gradients." ) @field_validator("cds_gradients", mode="before") @classmethod def validate_cds_gradients(cls, v): if v is not None and not isinstance(v, (np.ndarray, Dict, List)): raise ValueError( "cds_gradients must be a numpy array, a dict or a list or None." ) return v dipoles: Optional[Dict[str, Any]] = Field( None, description="The associated dipoles for Mulliken/RESP/ESP charges" ) gap_info: Optional[Dict[str, Any]] = Field( None, description="The Kohn-Sham HOMO-LUMO gaps and associated Eigenvalues" ) @classmethod def from_qcoutput(cls, qcoutput: QCOutput) -> "CalculationOutput": """ Create a QChem output document from a QCOutput object. Parameters ---------- qcoutput A QCOutput object. Returns -------- CalculationOutput The output document. """ optimized_molecule = qcoutput.data.get("molecule_from_optimized_geometry", {}) optimized_molecule = optimized_molecule if optimized_molecule else None return cls( optimized_molecule=optimized_molecule, mulliken=qcoutput.data.get(["Mulliken"][-1], []), esp=qcoutput.data.get(["ESP"][-1], []), resp=qcoutput.data.get(["RESP"][-1], []), nbo_data=qcoutput.data.get("nbo_data", {}), frequencies=qcoutput.data.get("frequencies", {}), frequency_modes=qcoutput.data.get("frequency_mode_vectors", []), final_energy=qcoutput.data.get("final_energy", None), enthalpy=qcoutput.data.get("total_enthalpy", None), entropy=qcoutput.data.get("total_entropy", None), scan_energies=qcoutput.data.get("scan_energies", {}), scan_geometries=qcoutput.data.get("optimized_geometries", {}), scan_molecules=qcoutput.data.get("molecules_from_optimized_geometries", {}), pcm_gradients=qcoutput.data.get(["pcm_gradients"][0], None), cds_gradients=qcoutput.data.get(["CDS_gradients"][0], None), dipoles=qcoutput.data.get("dipoles", None), gap_info=qcoutput.data.get("gap_info", None), ) model_config = ConfigDict(arbitrary_types_allowed=True) # TODO What can be done for the trajectories, also how will walltime and cputime be reconciled class Calculation(BaseModel): """Full QChem calculation inputs and outputs.""" dir_name: str = Field(None, description="The directory for this QChem calculation") qchem_version: str = Field( None, description="QChem version used to perform the current calculation" ) has_qchem_completed: Union[QChemStatus, bool] = Field( None, description="Whether QChem calculated the calculation successfully" ) input: CalculationInput = Field( None, description="QChem input settings for the calculation" ) output: CalculationOutput = Field( None, description="The QChem calculation output document" ) completed_at: str = Field( None, description="Timestamp for when the calculation was completed" ) task_name: str = Field( None, description="Name of task given by custodian (e.g. opt1, opt2, freq1, freq2)", ) output_file_paths: Dict[str, Union[str, Path, Dict[str, Path]]] = Field( None, description="Paths (relative to dir_name) of the QChem output files associated with this calculation", ) level_of_theory: Union[LevelOfTheory, str] = Field( None, description="Levels of theory used for the QChem calculation: For instance, B97-D/6-31g*", ) solvation_lot_info: Optional[str] = Field( None, description="A condensed string representation of the comboned LOT and Solvent info", ) task_type: TaskType = Field( None, description="Calculation task type like Single Point, Geometry Optimization. Frequency...", ) calc_type: Union[CalcType, str] = Field( None, description="Combination dict of LOT + TaskType: B97-D/6-31g*/VACUUM Geometry Optimization", ) @classmethod def from_qchem_files( cls, dir_name: Union[Path, str], task_name: str, qcinput_file: Union[Path, str], qcoutput_file: Union[Path, str], validate_lot: bool = True, store_energy_trajectory: bool = False, qcinput_kwargs: Optional[Dict] = None, qcoutput_kwargs: Optional[Dict] = None, ) -> "Calculation": """ Create a QChem calculation document from a directory and file paths. Parameters ---------- dir_name The directory containing the QChem calculation outputs. task_name The task name. qcinput_file Path to the .in/qin file, relative to dir_name. qcoutput_file Path to the .out/.qout file, relative to dir_name. store_energy_trajectory Whether to store the energy trajectory during a QChem calculation #TODO: Revisit this- False for now. qcinput_kwargs Additional keyword arguments that will be passed to the qcinput file qcoutput_kwargs Additional keyword arguments that will be passed to the qcoutput file Returns ------- Calculation A QChem calculation document. """ dir_name = Path(dir_name) qcinput_file = dir_name / qcinput_file qcoutput_file = dir_name / qcoutput_file output_file_paths = _find_qchem_files(dir_name) qcinput_kwargs = qcinput_kwargs if qcinput_kwargs else {} qcinput = QCInput.from_file(qcinput_file, **qcinput_kwargs) qcoutput_kwargs = qcoutput_kwargs if qcoutput_kwargs else {} qcoutput = QCOutput(qcoutput_file, **qcoutput_kwargs) completed_at = str(datetime.fromtimestamp(qcoutput_file.stat().st_mtime)) input_doc = CalculationInput.from_qcinput(qcinput) output_doc = CalculationOutput.from_qcoutput(qcoutput) has_qchem_completed = ( QChemStatus.SUCCESS if qcoutput.data.get("completion", []) else QChemStatus.FAILED ) if store_energy_trajectory: print("Still have to figure the energy trajectory") return cls( dir_name=str(dir_name), task_name=task_name, qchem_version=qcoutput.data["version"], has_qchem_completed=has_qchem_completed, completed_at=completed_at, input=input_doc, output=output_doc, output_file_paths={ k.lower(): Path(v) if isinstance(v, str) else {k2: Path(v2) for k2, v2 in v.items()} for k, v in output_file_paths.items() }, level_of_theory=level_of_theory(input_doc, validate_lot=validate_lot), solvation_lot_info=lot_solvent_string(input_doc, validate_lot=validate_lot), task_type=task_type(input_doc), calc_type=calc_type(input_doc, validate_lot=validate_lot), ) def _find_qchem_files( path: Union[str, Path], ) -> Dict[str, Any]: """ Find QChem files in a directory. Only the mol.qout file (or alternatively files with the task name as an extension, e.g., mol.qout.opt_0.gz, mol.qout.freq_1.gz, or something like this...) will be returned. Parameters ---------- path Path to a directory to search. Returns ------- Dict[str, Any] The filenames of the calculation outputs for each QChem task, given as a ordered dictionary of:: { task_name:{ "qchem_out_file": qcrun_filename, }, ... } If there is only 1 qout file task_name will be "standard" otherwise it will be the extension name like "opt_0" """ path = Path(path) task_files = OrderedDict() in_file_pattern = re.compile(r"^(?Pmol\.(qin|in)(?:\..+)?)(\.gz)?$") for file in path.iterdir(): if file.is_file(): in_match = in_file_pattern.match(file.name) # This block is for generalizing outputs coming from both atomate and manual qchem calculations if in_match: in_task_name = re.sub( r"(\.gz|gz)$", "", in_match.group("in_task_name").replace("mol.qin.", ""), ) in_task_name = in_task_name or "mol.qin" if in_task_name == "orig": task_files[in_task_name] = {"orig_input_file": file.name} elif in_task_name == "last": continue elif in_task_name == "mol.qin" or in_task_name == "mol.in": if in_task_name == "mol.qin": out_file = ( path / "mol.qout.gz" if (path / "mol.qout.gz").exists() else path / "mol.qout" ) else: out_file = ( path / "mol.out.gz" if (path / "mol.out.gz").exists() else path / "mol.out" ) task_files["standard"] = { "qcinput_file": file.name, "qcoutput_file": out_file.name, } # This block will exist only if calcs were run through atomate else: try: task_files[in_task_name] = { "qcinput_file": file.name, "qcoutput_file": Path( "mol.qout." + in_task_name + ".gz" ).name, } except FileNotFoundError: task_files[in_task_name] = { "qcinput_file": file.name, "qcoutput_file": "No qout files exist for this in file", } return task_files def level_of_theory( parameters: CalculationInput, validate_lot: bool = True ) -> LevelOfTheory: """ Returns the level of theory for a calculation, based on the input parameters given to Q-Chem Args: parameters: Dict of Q-Chem input parameters """ funct_raw = parameters.rem.get("method") basis_raw = parameters.rem.get("basis") if funct_raw is None or basis_raw is None: raise ValueError( 'Method and basis must be included in "rem" section ' "of parameters!" ) disp_corr = parameters.rem.get("dft_d") if disp_corr is None: funct_lower = funct_raw.lower() funct_lower = functional_synonyms.get(funct_lower, funct_lower) else: # Replace Q-Chem terms for D3 tails with more common expressions disp_corr = disp_corr.replace("_bj", "(bj)").replace("_zero", "(0)") funct_lower = f"{funct_raw}-{disp_corr}" basis_lower = basis_raw.lower() solvent_method = parameters.rem.get("solvent_method", "").lower() if solvent_method == "": solvation = "VACUUM" elif solvent_method in ["pcm", "cosmo"]: solvation = "PCM" # TODO: Add this once added into pymatgen and atomate # elif solvent_method == "isosvp": # if parameters.get("svp", {}).get("idefesr", 0): # solvation = "CMIRS" # else: # solvation = "ISOSVP" elif solvent_method == "smd": solvation = "SMD" else: raise ValueError(f"Unexpected implicit solvent method {solvent_method}!") if validate_lot: # --> TODO: replace with enums functional = [f for f in FUNCTIONALS if f.lower() == funct_lower] if not functional: raise ValueError(f"Unexpected functional {funct_lower}!") functional = functional[0] basis = [b for b in BASIS_SETS if b.lower() == basis_lower] if not basis: raise ValueError(f"Unexpected basis set {basis_lower}!") basis = basis[0] # <-- lot = f"{functional}/{basis}/{solvation}" return LevelOfTheory(lot) else: warnings.warn( "User has turned the validate flag off." "This can have downstream effects if the chosen functional and basis " "is not in the available sets of MP employed functionals and the user" "wants to include the TaskDoc in the MP infrastructure." "Users should ignore this warning if their objective is just to create TaskDocs", UserWarning, stacklevel=2, ) functional = funct_lower basis = basis_lower lot = f"{functional}/{basis}/{solvation}" return lot def solvent( parameters: CalculationInput, validate_lot: bool = True, custom_smd: Optional[str] = None, ) -> str: """ Returns the solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ lot = level_of_theory(parameters, validate_lot=validate_lot) if validate_lot: solvation = lot.value.split("/")[-1] else: solvation = lot.split("/")[-1] if solvation == "PCM": # dielectric = float(parameters.get("solvent", {}).get("dielectric", 78.39)) # dielectric = float(parameters.get("solvent", {})) # dielectric = getattr(parameters, "solvent", None) # dielectric_string = f"{dielectric.get('dielectric', '0.0'):.2f}".replace(".", ",") dielectric_string = getattr(parameters, "solvent", None) return f"DIELECTRIC= {dielectric_string}" # TODO: Add this once added into pymatgen and atomate # elif solvation == "ISOSVP": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # return f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # elif solvation == "CMIRS": # dielectric = float(parameters.get("svp", {}).get("dielst", 78.39)) # rho = float(parameters.get("svp", {}).get("rhoiso", 0.001)) # a = parameters.get("pcm_nonels", {}).get("a") # b = parameters.get("pcm_nonels", {}).get("b") # c = parameters.get("pcm_nonels", {}).get("c") # d = parameters.get("pcm_nonels", {}).get("d") # solvrho = parameters.get("pcm_nonels", {}).get("solvrho") # gamma = parameters.get("pcm_nonels", {}).get("gamma") # # string = f"DIELECTRIC={round(dielectric, 2)},RHO={round(rho, 4)}" # for name, (piece, digits) in {"A": (a, 6), "B": (b, 6), "C": (c, 1), "D": (d, 3), # "SOLVRHO": (solvrho, 2), "GAMMA": (gamma, 1)}.items(): # if piece is None: # piecestring = "NONE" # else: # piecestring = f"{name}={round(float(piece), digits)}" # string += "," + piecestring # return string elif solvation == "SMD": solvent = parameters.smx.get("solvent", "water") if solvent == "other": if custom_smd is None: raise ValueError( "SMD calculation with solvent=other requires custom_smd!" ) names = ["DIELECTRIC", "N", "ALPHA", "BETA", "GAMMA", "PHI", "PSI"] numbers = [float(x) for x in custom_smd.split(",")] string = "" for name, number in zip(names, numbers): string += f"{name}={number:.3f};" return string.rstrip(",").rstrip(";").replace(".", ",") else: return f"SOLVENT={solvent.upper()}" else: return "NONE" def lot_solvent_string( parameters: CalculationInput, validate_lot: bool = True, custom_smd: Optional[str] = None, ) -> str: """ Returns a string representation of the level of theory and solvent used for this calculation. Args: parameters: Dict of Q-Chem input parameters custom_smd: (Optional) string representing SMD parameters for a non-standard solvent """ if validate_lot: lot = level_of_theory(parameters, validate_lot=validate_lot).value else: lot = level_of_theory(parameters, validate_lot=validate_lot) solv = solvent(parameters, custom_smd=custom_smd, validate_lot=validate_lot) return f"{lot}({solv})" def task_type( parameters: CalculationInput, special_run_type: Optional[str] = None ) -> TaskType: if special_run_type == "frequency_flattener": return TaskType("Frequency Flattening Geometry Optimization") elif special_run_type == "ts_frequency_flattener": return TaskType("Frequency Flattening Transition State Geometry Optimization") if parameters.job_type == "sp": return TaskType("Single Point") elif parameters.job_type == "force": return TaskType("Force") elif parameters.job_type == "opt": return TaskType("Geometry Optimization") elif parameters.job_type == "ts": return TaskType("Transition State Geometry Optimization") elif parameters.job_type == "freq": return TaskType("Frequency Analysis") return TaskType("Unknown") def calc_type( parameters: CalculationInput, validate_lot: bool = True, special_run_type: Optional[str] = None, ) -> CalcType: """ Determines the calc type Args: parameters: CalculationInput parameters """ tt = task_type(parameters, special_run_type=special_run_type).value if validate_lot: rt = level_of_theory(parameters, validate_lot=validate_lot).value return CalcType(f"{rt} {tt}") else: rt = level_of_theory(parameters, validate_lot=validate_lot) return str(f"{rt} {tt}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/molecule.py0000644000175100001770000004557014673360562020611 0ustar00runnerdocker""" Core definition of a Molecule Document """ from typing import Any, Dict, List, Mapping, Union, Optional from pydantic import Field from pymatgen.core.structure import Molecule from pymatgen.analysis.molecule_matcher import MoleculeMatcher from pymatgen.io.babel import BabelMolAdaptor from emmet.core.mpid import MPculeID from emmet.core.utils import get_graph_hash, get_molecule_id from emmet.core.settings import EmmetSettings from emmet.core.material import CoreMoleculeDoc, PropertyOrigin from emmet.core.qchem.calc_types import CalcType, LevelOfTheory, TaskType from emmet.core.qchem.task import TaskDocument try: import openbabel except ImportError: openbabel = None __author__ = "Evan Spotte-Smith " SETTINGS = EmmetSettings() def evaluate_lot( lot: Union[LevelOfTheory, str], funct_scores: Dict[str, int] = SETTINGS.QCHEM_FUNCTIONAL_QUALITY_SCORES, basis_scores: Dict[str, int] = SETTINGS.QCHEM_BASIS_QUALITY_SCORES, solvent_scores: Dict[str, int] = SETTINGS.QCHEM_SOLVENT_MODEL_QUALITY_SCORES, ): """ Score the various components of a level of theory (functional, basis set, and solvent model), where a lower score is better than a higher score. :param lot: Level of theory to be evaluated :param funct_scores: Scores for various density functionals :param basis_scores: Scores for various basis sets :param solvent_scores: Scores for various implicit solvent models :return: """ if isinstance(lot, LevelOfTheory): lot_comp = lot.value.split("/") else: lot_comp = lot.split("/") return ( -1 * funct_scores.get(lot_comp[0], 0), -1 * basis_scores.get(lot_comp[1], 0), -1 * solvent_scores.get(lot_comp[2], 0), ) def evaluate_task( task: TaskDocument, funct_scores: Dict[str, int] = SETTINGS.QCHEM_FUNCTIONAL_QUALITY_SCORES, basis_scores: Dict[str, int] = SETTINGS.QCHEM_BASIS_QUALITY_SCORES, solvent_scores: Dict[str, int] = SETTINGS.QCHEM_SOLVENT_MODEL_QUALITY_SCORES, task_quality_scores: Dict[str, int] = SETTINGS.QCHEM_TASK_QUALITY_SCORES, ): """ Helper function to order optimization calcs by - Level of theory - Electronic energy Note that lower scores indicate a higher quality. :param task: Task to be evaluated :param funct_scores: Scores for various density functionals :param basis_scores: Scores for various basis sets :param solvent_scores: Scores for various implicit solvent models :param task_quality_scores: Scores for various task types :return: tuple representing different levels of evaluation: - Task validity - Level of theory score - Task score - Electronic energy """ lot = task.level_of_theory lot_eval = evaluate_lot( lot, funct_scores=funct_scores, basis_scores=basis_scores, solvent_scores=solvent_scores, ) return ( -1 * int(task.is_valid), sum(lot_eval), -1 * task_quality_scores.get(task.task_type.value, 0), task.output.final_energy, ) def evaluate_task_entry( entry: Dict[str, Any], funct_scores: Dict[str, int] = SETTINGS.QCHEM_FUNCTIONAL_QUALITY_SCORES, basis_scores: Dict[str, int] = SETTINGS.QCHEM_BASIS_QUALITY_SCORES, solvent_scores: Dict[str, int] = SETTINGS.QCHEM_SOLVENT_MODEL_QUALITY_SCORES, task_quality_scores: Dict[str, int] = SETTINGS.QCHEM_TASK_QUALITY_SCORES, ): """ Helper function to order optimization calcs by - Level of theory - Electronic energy Note that lower scores indicate a higher quality. :param task: Task to be evaluated :param funct_scores: Scores for various density functionals :param basis_scores: Scores for various basis sets :param solvent_scores: Scores for various implicit solvent models :param task_quality_scores: Scores for various task types :return: tuple representing different levels of evaluation: - Level of theory score - Task score - Electronic energy """ lot = entry["level_of_theory"] lot_eval = evaluate_lot( lot, funct_scores=funct_scores, basis_scores=basis_scores, solvent_scores=solvent_scores, ) return ( sum(lot_eval), -1 * task_quality_scores.get(entry["task_type"], 0), entry["energy"], ) class MoleculeDoc(CoreMoleculeDoc): species: Optional[List[str]] = Field( None, description="Ordered list of elements/species in this Molecule." ) molecules: Optional[Dict[str, Molecule]] = Field( None, description="The lowest energy optimized structures for this molecule for each solvent.", ) molecule_levels_of_theory: Optional[Dict[str, str]] = Field( None, description="Level of theory used to optimize the best molecular structure for each solvent.", ) species_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom species as the graph " "node attribute.", ) coord_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom coordinates as the graph " "node attribute.", ) inchi: Optional[str] = Field( None, description="International Chemical Identifier (InChI) for this molecule" ) inchi_key: Optional[str] = Field( None, description="Standardized hash of the InChI for this molecule" ) calc_types: Mapping[str, CalcType] = Field( # type: ignore None, description="Calculation types for all the calculations that make up this molecule", ) task_types: Optional[Mapping[str, TaskType]] = Field( None, description="Task types for all the calculations that make up this molecule", ) levels_of_theory: Optional[Mapping[str, LevelOfTheory]] = Field( None, description="Levels of theory types for all the calculations that make up this molecule", ) solvents: Optional[Mapping[str, str]] = Field( None, description="Solvents (solvent parameters) for all the calculations that make up this molecule", ) lot_solvents: Optional[Mapping[str, str]] = Field( None, description="Combinations of level of theory and solvent for all calculations that make up this molecule", ) unique_calc_types: Optional[List[CalcType]] = Field( None, description="Collection of all unique calculation types used for this molecule", ) unique_task_types: Optional[List[TaskType]] = Field( None, description="Collection of all unique task types used for this molecule", ) unique_levels_of_theory: Optional[List[LevelOfTheory]] = Field( None, description="Collection of all unique levels of theory used for this molecule", ) unique_solvents: Optional[List[str]] = Field( None, description="Collection of all unique solvents (solvent parameters) used for this molecule", ) unique_lot_solvents: Optional[List[str]] = Field( None, description="Collection of all unique combinations of level of theory and solvent used for this molecule", ) origins: Optional[List[PropertyOrigin]] = Field( None, description="List of property origins for tracking the provenance of properties", ) entries: Optional[List[Dict[str, Any]]] = Field( None, description="Dictionary representations of all task documents for this molecule", ) best_entries: Optional[Mapping[str, Dict[str, Any]]] = Field( None, description="Mapping for tracking the best entries at each level of theory (+ solvent) for Q-Chem calculations", ) constituent_molecules: Optional[List[MPculeID]] = Field( None, description="For cases where data from multiple MoleculeDocs have been compiled, a list of " "MPculeIDs of documents used to construct this document", ) similar_molecules: Optional[List[MPculeID]] = Field( None, description="List of MPculeIDs with of molecules similar (by e.g. structure) to this one", ) @classmethod def from_tasks( cls, task_group: List[TaskDocument], ) -> "MoleculeDoc": """ Converts a group of tasks into one molecule document Args: task_group: List of task document """ if openbabel is None: raise ModuleNotFoundError( "openbabel must be installed to instantiate a MoleculeDoc from tasks" ) if len(task_group) == 0: raise Exception("Must have more than one task in the group.") entries = [t.entry for t in task_group] # Metadata last_updated = max(task.last_updated for task in task_group) created_at = min(task.last_updated for task in task_group) task_ids = list({task.task_id for task in task_group}) deprecated_tasks = {task.task_id for task in task_group if not task.is_valid} levels_of_theory = {task.task_id: task.level_of_theory for task in task_group} solvents = {task.task_id: task.solvent for task in task_group} lot_solvents = {task.task_id: task.lot_solvent for task in task_group} task_types = {task.task_id: task.task_type for task in task_group} calc_types = {task.task_id: task.calc_type for task in task_group} unique_lots = list(set(levels_of_theory.values())) unique_solvents = list(set(solvents.values())) unique_lot_solvents = list(set(lot_solvents.values())) unique_task_types = list(set(task_types.values())) unique_calc_types = list(set(calc_types.values())) mols = [task.output.initial_molecule for task in task_group] # If we're dealing with single-atoms, process is much different if all([len(m) == 1 for m in mols]): sorted_tasks = sorted(task_group, key=evaluate_task) molecule = sorted_tasks[0].output.initial_molecule species = [e.symbol for e in molecule.species] molecule_id = get_molecule_id(molecule, node_attr="coords") # Initial molecules. No geometry should change for a single atom initial_molecules = [molecule] # Deprecated deprecated = all(task.task_id in deprecated_tasks for task in task_group) # Origins origins = [ PropertyOrigin( name="molecule", task_id=sorted_tasks[0].task_id, last_updated=sorted_tasks[0].last_updated, ) ] # entries best_entries = dict() for lot_solv in unique_lot_solvents: relevant_calcs = sorted( [ doc for doc in task_group if doc.lot_solvent == lot_solv and doc.is_valid ], key=evaluate_task, ) if len(relevant_calcs) > 0: best_task_doc = relevant_calcs[0] entry = best_task_doc.entry best_entries[lot_solv] = entry else: geometry_optimizations = [ task for task in task_group if task.task_type in [ TaskType.Geometry_Optimization, TaskType.Frequency_Flattening_Geometry_Optimization, "Geometry Optimization", "Frequency Flattening Geometry Optimization", ] # noqa: E501 ] try: best_molecule_calc = sorted(geometry_optimizations, key=evaluate_task)[ 0 ] except IndexError: raise Exception("No geometry optimization calculations available!") molecule = best_molecule_calc.output.optimized_molecule species = [e.symbol for e in molecule.species] molecule_id = get_molecule_id(molecule, node_attr="coords") # Initial molecules initial_molecules = list() for task in task_group: if isinstance(task.orig["molecule"], Molecule): initial_molecules.append(task.orig["molecule"]) else: initial_molecules.append(Molecule.from_dict(task.orig["molecule"])) mm = MoleculeMatcher() initial_molecules = [ group[0] for group in mm.group_molecules(initial_molecules) ] # Deprecated deprecated = all( task.task_id in deprecated_tasks for task in geometry_optimizations ) deprecated = deprecated or best_molecule_calc.task_id in deprecated_tasks # Origins origins = [ PropertyOrigin( name="molecule", task_id=best_molecule_calc.task_id, last_updated=best_molecule_calc.last_updated, ) ] # entries best_entries = dict() all_lot_solvs = set(lot_solvents.values()) for lot_solv in all_lot_solvs: relevant_calcs = sorted( [ doc for doc in geometry_optimizations if doc.lot_solvent == lot_solv and doc.is_valid ], key=evaluate_task, ) if len(relevant_calcs) > 0: best_task_doc = relevant_calcs[0] entry = best_task_doc.entry best_entries[lot_solv] = entry for entry in entries: entry["entry_id"] = molecule_id species_hash = get_graph_hash(molecule, "specie") coord_hash = get_graph_hash(molecule, "coords") ad = BabelMolAdaptor(molecule) openbabel.StereoFrom3D(ad.openbabel_mol) inchi = ad.pybel_mol.write("inchi").strip() # type: ignore[attr-defined] inchikey = ad.pybel_mol.write("inchikey").strip() # type: ignore[attr-defined] return cls.from_molecule( molecule=molecule, molecule_id=molecule_id, species=species, species_hash=species_hash, coord_hash=coord_hash, inchi=inchi, inchi_key=inchikey, initial_molecules=initial_molecules, last_updated=last_updated, created_at=created_at, task_ids=task_ids, calc_types=calc_types, levels_of_theory=levels_of_theory, solvents=solvents, lot_solvents=lot_solvents, task_types=task_types, unique_levels_of_theory=unique_lots, unique_solvents=unique_solvents, unique_lot_solvents=unique_lot_solvents, unique_task_types=unique_task_types, unique_calc_types=unique_calc_types, deprecated=deprecated, deprecated_tasks=deprecated_tasks, origins=origins, entries=entries, best_entries=best_entries, ) @classmethod def construct_deprecated_molecule( cls, task_group: List[TaskDocument], ) -> "MoleculeDoc": """ Converts a group of tasks into a deprecated molecule document Args: task_group: List of task document """ if len(task_group) == 0: raise Exception("Must have more than one task in the group.") # Metadata last_updated = max(task.last_updated for task in task_group) created_at = min(task.last_updated for task in task_group) task_ids = list({task.task_id for task in task_group}) deprecated_tasks = {task.task_id for task in task_group} levels_of_theory = {task.task_id: task.level_of_theory for task in task_group} solvents = {task.task_id: task.solvent for task in task_group} lot_solvents = {task.task_id: task.lot_solvent for task in task_group} task_types = {task.task_id: task.task_type for task in task_group} calc_types = {task.task_id: task.calc_type for task in task_group} unique_lots = list(set(levels_of_theory.values())) unique_solvents = list(set(solvents.values())) unique_lot_solvents = list(set(lot_solvents.values())) unique_task_types = list(set(task_types.values())) unique_calc_types = list(set(calc_types.values())) # Arbitrarily choose task with lowest ID molecule = sorted(task_group, key=lambda x: x.task_id)[ 0 ].output.initial_molecule species = [e.symbol for e in molecule.species] # Molecule ID molecule_id = get_molecule_id(molecule, "coords") species_hash = get_graph_hash(molecule, "specie") coord_hash = get_graph_hash(molecule, "coords") ad = BabelMolAdaptor(molecule) openbabel.StereoFrom3D(ad.openbabel_mol) inchi = ad.pybel_mol.write("inchi").strip() # type: ignore[attr-defined] inchikey = ad.pybel_mol.write("inchikey").strip() # type: ignore[attr-defined] return cls.from_molecule( molecule=molecule, molecule_id=molecule_id, species=species, species_hash=species_hash, coord_hash=coord_hash, inchi=inchi, inchi_key=inchikey, last_updated=last_updated, created_at=created_at, task_ids=task_ids, calc_types=calc_types, levels_of_theory=levels_of_theory, solvents=solvents, lot_solvents=lot_solvents, task_types=task_types, unique_levels_of_theory=unique_lots, unique_solvents=unique_solvents, unique_lot_solvents=unique_lot_solvents, unique_task_types=unique_task_types, unique_calc_types=unique_calc_types, deprecated=True, deprecated_tasks=deprecated_tasks, ) def best_lot( mol_doc: MoleculeDoc, funct_scores: Dict[str, int] = SETTINGS.QCHEM_FUNCTIONAL_QUALITY_SCORES, basis_scores: Dict[str, int] = SETTINGS.QCHEM_BASIS_QUALITY_SCORES, solvent_scores: Dict[str, int] = SETTINGS.QCHEM_SOLVENT_MODEL_QUALITY_SCORES, ) -> str: """ Return the best level of theory used within a MoleculeDoc :param mol_doc: MoleculeDoc :param funct_scores: Scores for various density functionals :param basis_scores: Scores for various basis sets :param solvent_scores: Scores for various implicit solvent models :return: string representation of LevelOfTheory """ sorted_lots = sorted( mol_doc.best_entries.keys(), # type: ignore key=lambda x: evaluate_lot(x, funct_scores, basis_scores, solvent_scores), ) best = sorted_lots[0] if isinstance(best, LevelOfTheory): return best.value else: return best ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/qchem/task.py0000644000175100001770000001611314673360562017735 0ustar00runnerdocker# mypy: ignore-errors """ Core definition of a Q-Chem Task Document """ from typing import Any, Dict, List, Optional, Callable from pydantic import BaseModel, Field from pymatgen.core.structure import Molecule from emmet.core.structure import MoleculeMetadata from emmet.core.task import BaseTaskDocument from emmet.core.utils import ValueEnum from emmet.core.qchem.calc_types import ( LevelOfTheory, CalcType, TaskType, calc_type, level_of_theory, task_type, solvent, lot_solvent_string, ) __author__ = "Evan Spotte-Smith " class QChemStatus(ValueEnum): """ Q-Chem Calculation State """ SUCCESS = "successful" FAILED = "unsuccessful" class OutputSummary(BaseModel): """ Summary of an output for a Q-Chem calculation """ initial_molecule: Optional[Molecule] = Field( None, description="Input Molecule object" ) optimized_molecule: Optional[Molecule] = Field( None, description="Optimized Molecule object" ) final_energy: Optional[float] = Field( None, description="Final electronic energy for the calculation (units: Hartree)" ) enthalpy: Optional[float] = Field( None, description="Total enthalpy of the molecule (units: kcal/mol)" ) entropy: Optional[float] = Field( None, description="Total entropy of the molecule (units: cal/mol-K" ) mulliken: Optional[List[Any]] = Field( None, description="Mulliken atomic partial charges and partial spins" ) resp: Optional[List[float]] = Field( None, description="Restrained Electrostatic Potential (RESP) atomic partial charges", ) nbo: Optional[Dict[str, Any]] = Field( None, description="Natural Bonding Orbital (NBO) output" ) frequencies: Optional[List[float]] = Field( None, description="Vibrational frequencies of the molecule (units: cm^-1)" ) def as_dict(self) -> Dict[str, Any]: return { "@module": self.__class__.__module__, "@class": self.__class__.__name__, "initial_molecule": self.initial_molecule, "optimized_molecule": self.optimized_molecule, "final_energy": self.final_energy, "enthalpy": self.enthalpy, "entropy": self.entropy, "mulliken": self.mulliken, "resp": self.resp, "nbo": self.nbo, "frequencies": self.frequencies, } class TaskDocument(BaseTaskDocument, MoleculeMetadata): """ Definition of a Q-Chem task document """ calc_code: str = "Q-Chem" completed: bool = True is_valid: bool = Field( True, description="Whether this task document passed validation or not" ) state: Optional[QChemStatus] = Field(None, description="State of this calculation") cputime: Optional[float] = Field(None, description="The system CPU time in seconds") walltime: Optional[float] = Field( None, description="The real elapsed time in seconds" ) calcs_reversed: List[Dict] = Field( [], description="The 'raw' calculation docs used to assembled this task" ) orig: Dict[str, Any] = Field( {}, description="Summary of the original Q-Chem inputs" ) output: OutputSummary = Field(OutputSummary()) critic2: Optional[Dict[str, Any]] = Field( None, description="Output from Critic2 critical point analysis code" ) custom_smd: Optional[str] = Field( None, description="Parameter string for SMD implicit solvent model" ) special_run_type: Optional[str] = Field( None, description="Special workflow name (if applicable)" ) smiles: Optional[str] = Field( None, description="Simplified molecular-input line-entry system (SMILES) string for the molecule involved " "in this calculation.", ) species_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom species as the graph " "node attribute.", ) coord_hash: Optional[str] = Field( None, description="Weisfeiler Lehman (WL) graph hash using the atom coordinates as the graph " "node attribute.", ) # TODO - type of `tags` field seems to differ among task databases # sometimes List, sometimes Dict # left as Any here to ensure tags don't cause validation to fail. tags: Optional[Any] = Field(None, description="Metadata tags") warnings: Optional[Dict[str, bool]] = Field( None, description="Any warnings related to this task document" ) @property def level_of_theory(self) -> LevelOfTheory: return level_of_theory(self.orig) @property def solvent(self) -> str: return solvent(self.orig, custom_smd=self.custom_smd) @property def lot_solvent(self) -> str: return lot_solvent_string(self.orig, custom_smd=self.custom_smd) @property def task_type(self) -> TaskType: return task_type(self.orig, special_run_type=self.special_run_type) @property def calc_type(self) -> CalcType: return calc_type(self.special_run_type, self.orig) @property def entry(self) -> Dict[str, Any]: if self.output.optimized_molecule is not None: mol = self.output.optimized_molecule else: mol = self.output.initial_molecule if self.charge is None: charge = int(mol.charge) else: charge = int(self.charge) if self.spin_multiplicity is None: spin = mol.spin_multiplicity else: spin = self.spin_multiplicity entry_dict = { "entry_id": self.task_id, "task_id": self.task_id, "charge": charge, "spin_multiplicity": spin, "level_of_theory": self.level_of_theory, "solvent": self.solvent, "lot_solvent": self.lot_solvent, "custom_smd": self.custom_smd, "task_type": self.task_type, "calc_type": self.calc_type, "molecule": mol, "composition": mol.composition, "formula": mol.composition.alphabetical_formula, "energy": self.output.final_energy, "output": self.output.as_dict(), "critic2": self.critic2, "orig": self.orig, "tags": self.tags, "last_updated": self.last_updated, "species_hash": self.species_hash, "coord_hash": self.coord_hash, } return entry_dict def filter_task_type( entries: List[Dict[str, Any]], task_type: TaskType, sort_by: Optional[Callable] = None, ) -> List[Dict[str, Any]]: """ Filter (and sort) TaskDocument entries based on task type :param entries: List of TaskDocument entry dicts :param TaskType: TaskType to accept :param sort_by: Function used to sort (default None) :return: Filtered (sorted) list of entries """ filtered = [f for f in entries if f["task_type"] == task_type] if sort_by is not None: return sorted(filtered, key=sort_by) else: return filtered ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/robocrys.py0000644000175100001770000000515714673360562017546 0ustar00runnerdockerfrom typing import Optional, Union from pydantic import BaseModel, Field from pymatgen.core.structure import Structure from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID from emmet.core.utils import generate_robocrys_condensed_struct_and_description class MineralData(BaseModel): """ Model for mineral data in the condensed structure robocrystallographer field """ type: Union[str, None] = Field( description="Mineral type.", ) name: Optional[str] = Field(None, description="The mineral name if found.") class CondensedStructureData(BaseModel): """ Model for data in the condensed structure robocrystallographer field More details: https://hackingmaterials.lbl.gov/robocrystallographer/format.html """ mineral: MineralData = Field( description="Matched mineral data for the material.", ) dimensionality: int = Field( description="Dimensionality of the material.", ) formula: Optional[str] = Field( None, description="Formula for the material.", ) spg_symbol: Optional[str] = Field( None, description="Space group symbol of the material.", ) crystal_system: Optional[str] = Field( None, description="Crystal system of the material.", ) class RobocrystallogapherDoc(PropertyDoc): """ This document contains the descriptive data from robocrystallographer for a material: Structural features, mineral prototypes, dimensionality, ... """ property_name: str = "robocrys" description: str = Field( description="Description text from robocrytallographer.", ) condensed_structure: CondensedStructureData = Field( description="Condensed structure data from robocrytallographer.", ) robocrys_version: str = Field( ..., description="The version of Robocrystallographer used to generate this document.", ) @classmethod def from_structure( cls, structure: Structure, material_id: MPID, robocrys_version: str, mineral_matcher=None, **kwargs ): ( condensed_structure, description, ) = generate_robocrys_condensed_struct_and_description( structure=structure, mineral_matcher=mineral_matcher ) return super().from_structure( meta_structure=structure, material_id=material_id, condensed_structure=condensed_structure, description=description, robocrys_version=robocrys_version, **kwargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/settings.py0000644000175100001770000001736014673360562017543 0ustar00runnerdocker# mypy: ignore-errors """ Settings for defaults in the core definitions of Materials Project Documents """ import json from pathlib import Path from typing import Type, TypeVar, Union, List, Dict import requests from monty.json import MontyDecoder from pydantic import field_validator, model_validator, Field, ImportString from pydantic_settings import BaseSettings, SettingsConfigDict DEFAULT_CONFIG_FILE_PATH = str(Path.home().joinpath(".emmet.json")) S = TypeVar("S", bound="EmmetSettings") class EmmetSettings(BaseSettings): """ Settings for the emmet- packages Non-core packages should subclass this to get settings specific to their needs The default way to modify these is to modify ~/.emmet.json or set the environment variable EMMET_CONFIG_FILE to point to the json with emmet settings """ config_file: str = Field( DEFAULT_CONFIG_FILE_PATH, description="File to load alternative defaults from" ) LTOL: float = Field( 0.2, description="Fractional length tolerance for structure matching" ) STOL: float = Field( 0.3, description="Site tolerance for structure matching. Defined as the fraction of the" " average free length per atom = ( V / Nsites ) ** (1/3)", ) SYMPREC: float = Field( 0.1, description="Symmetry precision for spglib symmetry finding" ) ANGLE_TOL: float = Field( 5, description="Angle tolerance for structure matching in degrees." ) PGATOL: float = Field( 0.3, description="Distance tolerance to consider sites as symmetrically equivalent.", ) PGAEIGENTOL: float = Field( 0.01, description="Tolerance to compare eigen values of the inertia tensor." ) PGAMATRIXTOL: float = Field( 0.1, description="Tolerance used to generate the full set of symmetry operations of the point group.", ) MAX_PIEZO_MILLER: int = Field( 10, description="Maximum miller allowed for computing strain direction for maximal piezo response", ) QCHEM_FUNCTIONAL_QUALITY_SCORES: Dict[str, int] = Field( { "wB97M-V": 7, "wB97X-V": 6, "wB97X-D3": 5, "wB97X-D": 5, "B3LYP": 4, "B97M-V": 3, "B97M-rV": 3, "B97-D3": 2, "B97-D": 2, "PBE": 1, }, description="Dictionary mapping Q-Chem density functionals to a quality score.", ) QCHEM_BASIS_QUALITY_SCORES: Dict[str, int] = Field( { "6-31g*": 1, "def2-SVPD": 2, "def2-TZVP": 3, "def2-TZVPD": 4, "def2-TZVPP": 5, "def2-TZVPPD": 6, "def2-QZVPPD": 7, }, description="Dictionary mapping Q-Chem basis sets to a quality score.", ) QCHEM_SOLVENT_MODEL_QUALITY_SCORES: Dict[str, int] = Field( {"CMIRS": 7, "SMD": 5, "ISOSVP": 4, "PCM": 3, "VACUUM": 1}, description="Dictionary mapping Q-Chem solvent models to a quality score.", ) QCHEM_TASK_QUALITY_SCORES: Dict[str, int] = Field( { "single_point": 1, "geometry optimization": 2, "frequency-flattening geometry optimization": 3, }, description="Dictionary mapping Q-Chem task type to a quality score", ) VASP_STRUCTURE_QUALITY_SCORES: Dict[str, int] = Field( {"r2SCAN": 5, "SCAN": 4, "GGA+U": 3, "GGA": 2, "PBEsol": 1}, description="Dictionary Mapping VASP calculation run types to rung level for VASP materials builder structure data", # noqa: E501 ) VASP_KPTS_TOLERANCE: float = Field( 0.9, description="Relative tolerance for kpt density to still be a valid task document", ) VASP_KSPACING_TOLERANCE: float = Field( 0.05, description="Relative tolerance for kspacing to still be a valid task document", ) VASP_MAX_MAGMOM: Dict[str, float] = Field( {"Cr": 5}, description="Maximum permitted magnetic moments by element type." ) VASP_DEFAULT_INPUT_SETS: Dict[str, ImportString] = Field( { "GGA Structure Optimization": "pymatgen.io.vasp.sets.MPRelaxSet", "GGA+U Structure Optimization": "pymatgen.io.vasp.sets.MPRelaxSet", "r2SCAN Structure Optimization": "pymatgen.io.vasp.sets.MPScanRelaxSet", "SCAN Structure Optimization": "pymatgen.io.vasp.sets.MPScanRelaxSet", "PBEsol Structure Optimization": "pymatgen.io.vasp.sets.MPScanRelaxSet", "GGA Static": "pymatgen.io.vasp.sets.MPStaticSet", "GGA+U Static": "pymatgen.io.vasp.sets.MPStaticSet", "r2SCAN Static": "pymatgen.io.vasp.sets.MPScanStaticSet", "SCAN Static": "pymatgen.io.vasp.sets.MPScanStaticSet", "PBEsol Static": "pymatgen.io.vasp.sets.MPScanStaticSet", "HSE06 Static": "pymatgen.io.vasp.sets.MPScanStaticSet", "GGA NSCF Uniform": "pymatgen.io.vasp.sets.MPNonSCFSet", "GGA+U NSCF Uniform": "pymatgen.io.vasp.sets.MPNonSCFSet", "GGA NSCF Line": "pymatgen.io.vasp.sets.MPNonSCFSet", "GGA+U NSCF Line": "pymatgen.io.vasp.sets.MPNonSCFSet", "GGA NMR Electric Field Gradient": "pymatgen.io.vasp.sets.MPNMRSet", "GGA NMR Nuclear Shielding": "pymatgen.io.vasp.sets.MPNMRSet", "GGA+U NMR Electric Field Gradient": "pymatgen.io.vasp.sets.MPNMRSet", "GGA+U NMR Nuclear Shielding": "pymatgen.io.vasp.sets.MPNMRSet", "GGA Deformation": "pymatgen.io.vasp.sets.MPStaticSet", "GGA+U Deformation": "pymatgen.io.vasp.sets.MPStaticSet", "GGA DFPT Dielectric": "pymatgen.io.vasp.sets.MPStaticSet", "GGA+U DFPT Dielectric": "pymatgen.io.vasp.sets.MPStaticSet", }, description="Default input sets for task validation", ) VASP_VALIDATE_POTCAR_STATS: bool = Field( True, description="Whether to validate POTCAR stat values." ) VASP_CHECKED_LDAU_FIELDS: List[str] = Field( ["LDAUU", "LDAUJ", "LDAUL"], description="LDAU fields to validate for tasks" ) VASP_MAX_SCF_GRADIENT: float = Field( 100, description="Maximum upward gradient in the last SCF for any VASP calculation", ) VASP_USE_STATICS: bool = Field( True, description="Use static calculations for structure and energy along with structure optimizations", ) model_config = SettingsConfigDict(env_prefix="emmet_", extra="ignore") @model_validator(mode="before") @classmethod def load_default_settings(cls, values): """ Loads settings from a root file if available and uses that as defaults in place of built in defaults """ config_file_path: str = values.get("config_file", DEFAULT_CONFIG_FILE_PATH) new_values = {} if config_file_path.startswith("http"): new_values = requests.get(config_file_path).json() elif Path(config_file_path).exists(): with open(config_file_path) as f: new_values = json.load(f) new_values.update(values) return new_values @classmethod def autoload(cls: Type[S], settings: Union[None, dict, S]) -> S: if settings is None: return cls() elif isinstance(settings, dict): return cls(**settings) return settings @field_validator("VASP_DEFAULT_INPUT_SETS", mode="before") @classmethod def convert_input_sets(cls, value): if isinstance(value, dict): return {k: MontyDecoder().process_decoded(v) for k, v in value.items()} return value def as_dict(self): """ HotPatch to enable serializing EmmetSettings via Monty """ return self.dict(exclude_unset=True, exclude_defaults=True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/similarity.py0000644000175100001770000000223114673360562020060 0ustar00runnerdockerfrom typing import List, Optional from pydantic import BaseModel, Field class SimilarityEntry(BaseModel): """ Find similar materials to a specified material based on crystal geometry. """ task_id: Optional[str] = Field( None, description="The Materials Project ID for the matched material. This comes in the form: mp-******.", ) nelements: Optional[int] = Field( None, description="Number of elements in the matched material.", ) dissimilarity: Optional[float] = Field( None, description="Dissimilarity measure for the matched material in %.", ) formula: Optional[str] = Field( None, description="Formula of the matched material.", ) class SimilarityDoc(BaseModel): """ Model for a document containing structure similarity data """ sim: Optional[List[SimilarityEntry]] = Field( None, description="List containing similar structure data for a given material.", ) material_id: Optional[str] = Field( None, description="The Materials Project ID for the material. This comes in the form: mp-******", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/spectrum.py0000644000175100001770000000203314673360562017534 0ustar00runnerdocker""" Core definition of Spectrum document """ from datetime import datetime from typing import List from pydantic import Field from emmet.core.mpid import MPID from emmet.core.structure import StructureMetadata class SpectrumDoc(StructureMetadata): """ Base model definition for any spectra document. This should contain metadata on the structure the spectra pertains to """ spectrum_name: str material_id: MPID = Field( ..., description="The ID of the material, used as a universal reference across proeprty documents." "This comes in the form: mp-******.", ) spectrum_id: str = Field( ..., title="Spectrum Document ID", description="The unique ID for this spectrum document.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property.", default_factory=datetime.utcnow, ) warnings: List[str] = Field( [], description="Any warnings related to this property." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/structure.py0000644000175100001770000002311714673360562017740 0ustar00runnerdocker"""Core definition of Structure and Molecule metadata.""" from __future__ import annotations from typing import List, Optional, Type, TypeVar from pydantic import Field from pymatgen.core.composition import Composition from pymatgen.core.periodic_table import Element from pymatgen.core.structure import Molecule, Structure from emmet.core.base import EmmetBaseModel from emmet.core.symmetry import PointGroupData, SymmetryData T = TypeVar("T", bound="StructureMetadata") S = TypeVar("S", bound="MoleculeMetadata") class StructureMetadata(EmmetBaseModel): """Mix-in class for structure metadata.""" # Structure metadata nsites: Optional[int] = Field( None, description="Total number of sites in the structure." ) elements: Optional[List[Element]] = Field( None, description="List of elements in the material." ) nelements: Optional[int] = Field(None, description="Number of elements.") composition: Optional[Composition] = Field( None, description="Full composition for the material." ) composition_reduced: Optional[Composition] = Field( None, title="Reduced Composition", description="Simplified representation of the composition.", ) formula_pretty: Optional[str] = Field( None, title="Pretty Formula", description="Cleaned representation of the formula.", ) formula_anonymous: Optional[str] = Field( None, title="Anonymous Formula", description="Anonymized representation of the formula.", ) chemsys: Optional[str] = Field( None, title="Chemical System", description="dash-delimited string of elements in the material.", ) volume: Optional[float] = Field( None, title="Volume", description="Total volume for this structure in Angstroms^3.", ) density: Optional[float] = Field( None, title="Density", description="Density in grams per cm^3." ) density_atomic: Optional[float] = Field( None, title="Packing Density", description="The atomic packing density in atoms per cm^3.", ) symmetry: Optional[SymmetryData] = Field( None, description="Symmetry data for this material." ) @classmethod def from_composition( cls: Type[T], composition: Composition, fields: Optional[List[str]] = None, **kwargs, ) -> T: fields = ( [ "elements", "nelements", "composition", "composition_reduced", "formula_pretty", "formula_anonymous", "chemsys", ] if fields is None else fields ) composition = composition.remove_charges() elsyms = sorted({e.symbol for e in composition.elements}) data = { "elements": elsyms, "nelements": len(elsyms), "composition": composition, "composition_reduced": composition.reduced_composition.remove_charges(), "formula_pretty": composition.reduced_formula, "formula_anonymous": composition.anonymized_formula, "chemsys": "-".join(elsyms), } return cls(**{k: v for k, v in data.items() if k in fields}, **kwargs) @classmethod def from_structure( cls: Type[T], meta_structure: Structure, fields: Optional[List[str]] = None, **kwargs, ) -> T: fields = ( [ "nsites", "elements", "nelements", "composition", "composition_reduced", "formula_pretty", "formula_anonymous", "chemsys", "volume", "density", "density_atomic", "symmetry", ] if fields is None else fields ) comp = meta_structure.composition.remove_charges() elsyms = sorted({e.symbol for e in comp.elements}) symmetry = SymmetryData.from_structure(meta_structure) data = { "nsites": meta_structure.num_sites, "elements": elsyms, "nelements": len(elsyms), "composition": comp, "composition_reduced": comp.reduced_composition, "formula_pretty": comp.reduced_formula, "formula_anonymous": comp.anonymized_formula, "chemsys": "-".join(elsyms), "volume": meta_structure.volume, "density": meta_structure.density, "density_atomic": meta_structure.volume / meta_structure.num_sites, "symmetry": symmetry, } kwargs.update({k: v for k, v in data.items() if k in fields}) return cls(**kwargs) class MoleculeMetadata(EmmetBaseModel): """Mix-in class for molecule metadata.""" charge: Optional[int] = Field(None, description="Charge of the molecule") spin_multiplicity: Optional[int] = Field( None, description="Spin multiplicity of the molecule" ) natoms: Optional[int] = Field( None, description="Total number of atoms in the molecule" ) elements: Optional[List[Element]] = Field( None, description="List of elements in the molecule" ) nelements: Optional[int] = Field(None, title="Number of Elements") nelectrons: Optional[int] = Field( None, title="Number of electrons", description="The total number of electrons for the molecule", ) composition: Optional[Composition] = Field( None, description="Full composition for the molecule" ) composition_reduced: Optional[Composition] = Field( None, title="Reduced Composition", description="Simplified representation of the composition", ) formula_alphabetical: Optional[str] = Field( None, title="Alphabetical Formula", description="Alphabetical molecular formula", ) formula_pretty: Optional[str] = Field( None, title="Pretty Formula", description="Cleaned representation of the formula.", ) formula_anonymous: Optional[str] = Field( None, title="Anonymous Formula", description="Anonymized representation of the formula", ) chemsys: Optional[str] = Field( None, title="Chemical System", description="dash-delimited string of elements in the molecule", ) symmetry: Optional[PointGroupData] = Field( None, description="Symmetry data for this molecule" ) @classmethod def from_composition( cls: Type[S], comp: Composition, fields: Optional[List[str]] = None, **kwargs, ) -> S: """ Create a MoleculeMetadata model from a composition. Parameters ---------- comp : .Composition A pymatgen composition. fields : list of str or None Composition fields to include. **kwargs Keyword arguments that are passed to the model constructor. Returns ------- T A molecule metadata model. """ fields = ( [ "elements", "nelements", "composition", "composition_reduced", "formula_alphabetical", "formula_pretty", "formula_anonymous", "chemsys", ] if fields is None else fields ) elsyms = sorted({e.symbol for e in comp.elements}) data = { "elements": elsyms, "nelements": len(elsyms), "composition": comp, "composition_reduced": comp.reduced_composition, "formula_alphabetical": comp.alphabetical_formula, "formula_pretty": comp.reduced_formula, "formula_anonymous": comp.anonymized_formula, "chemsys": "-".join(elsyms), } return cls(**{k: v for k, v in data.items() if k in fields}, **kwargs) @classmethod def from_molecule( cls: Type[S], meta_molecule: Molecule, fields: Optional[List[str]] = None, **kwargs, ) -> S: fields = ( [ "charge", "spin_multiplicity", "natoms", "elements", "nelements", "nelectrons", "composition", "composition_reduced", "formula_alphabetical", "formula_pretty", "formula_anonymous", "chemsys", "symmetry", ] if fields is None else fields ) comp = meta_molecule.composition elsyms = sorted({e.symbol for e in comp.elements}) symmetry = PointGroupData.from_molecule(meta_molecule) data = { "charge": int(meta_molecule.charge), "spin_multiplicity": meta_molecule.spin_multiplicity, "natoms": len(meta_molecule), "elements": elsyms, "nelements": len(elsyms), "nelectrons": int(meta_molecule.nelectrons), "composition": comp, "composition_reduced": comp.reduced_composition, "formula_alphabetical": comp.alphabetical_formula, "formula_pretty": comp.reduced_formula, "formula_anonymous": comp.anonymized_formula, "chemsys": "-".join(elsyms), "symmetry": symmetry, } return cls(**{k: v for k, v in data.items() if k in fields}, **kwargs) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/structure_group.py0000644000175100001770000002551714673360562021162 0ustar00runnerdockerimport logging import operator from datetime import datetime from itertools import groupby from typing import Iterable, List, Optional, Union from pydantic import field_validator, BaseModel, Field from pymatgen.analysis.structure_matcher import ElementComparator, StructureMatcher from pymatgen.core.composition import Composition from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from emmet.core.mpid import MPID from emmet.core.common import convert_datetime logger = logging.getLogger(__name__) def generic_groupby(list_in, comp=operator.eq) -> List[int]: """ Group a list of unsortable objects Args: list_in: A list of generic objects comp: (Default value = operator.eq) The comparator Returns: [int] list of labels for the input list """ list_out = [None] * len(list_in) # type: List[Union[int, None]] label_num = 0 for i1, ls1 in enumerate(list_out): if ls1 is not None: continue list_out[i1] = label_num for i2, ls2 in list(enumerate(list_out))[i1 + 1 :]: if comp(list_in[i1], list_in[i2]): if list_out[i2] is None: list_out[i2] = list_out[i1] else: list_out[i1] = list_out[i2] label_num -= 1 label_num += 1 return list_out # type: ignore def s_hash(el): return el.data["comp_delith"] class StructureGroupDoc(BaseModel): """ Group of structure """ group_id: Optional[str] = Field( None, description="The combined material_id of the grouped document is given by the numerically smallest " "material_id, you can also append the followed by the ignored species at the end.", ) has_distinct_compositions: Optional[bool] = Field( None, description="True if multiple compositions are present in the group." ) material_ids: Optional[list] = Field( None, description="A list of materials ids for all of the materials that were grouped together.", ) host_material_ids: Optional[list] = Field( None, description="Material id(s) that correspond(s) to the host structure(s), which has/have the lowest" "concentration of ignored specie.", ) insertion_material_ids: Optional[list] = Field( None, description="Material ids that correspond to the non-host structures identified in a given structure group.", ) framework_formula: Optional[str] = Field( None, description="The chemical formula for the framework (the materials system without the ignored species).", ) ignored_specie: Optional[str] = Field( None, description="Ignored atomic specie which is usually the working ion (ex: Li, Mg, or Ca).", ) chemsys: Optional[str] = Field( None, description="The chemical system this group belongs to, if the atoms for the ignored species is " "present the chemsys will also include the ignored species.", ) last_updated: Optional[datetime] = Field( None, description="Timestamp when this document was built." ) # Make sure that the datetime field is properly formatted @field_validator("last_updated", mode="before") @classmethod def handle_datetime(cls, v): return convert_datetime(cls, v) @classmethod def from_grouped_entries( cls, entries: List[Union[ComputedEntry, ComputedStructureEntry]], ignored_specie: str, ) -> "StructureGroupDoc": """ " Assuming a list of entries are already grouped together, create a StructureGroupDoc Args: entries: A list of entries that is already grouped together. ignored_specie: The specie that is ignored during structure matching """ all_atoms = set() all_comps = set() for ient in entries: all_atoms |= set(ient.composition.as_dict().keys()) all_comps.add(ient.composition.reduced_formula) common_atoms = all_atoms - set([ignored_specie]) if len(common_atoms) == 0: framework_str = "ignored" else: comp_d = {k: entries[0].composition.as_dict()[k] for k in common_atoms} framework_comp = Composition.from_dict(comp_d) framework_str = framework_comp.reduced_formula ids = [ient.data["material_id"] for ient in entries] lowest_id = min(ids, key=_get_id_lexi) sub_script = "_".join([ignored_specie]) host_and_insertion_ids = StructureGroupDoc.get_host_and_insertion_ids( entries=entries, ignored_specie=ignored_specie ) fields = { "group_id": f"{lowest_id}_{sub_script}", "material_ids": ids, "host_material_ids": host_and_insertion_ids["host_ids"], "insertion_material_ids": host_and_insertion_ids["insertion_ids"], "framework_formula": framework_str, "ignored_specie": ignored_specie, "chemsys": "-".join(sorted(all_atoms | set([ignored_specie]))), "has_distinct_compositions": len(all_comps) > 1, } return cls(**fields) @classmethod def from_ungrouped_structure_entries( cls, entries: List[Union[ComputedEntry, ComputedStructureEntry]], ignored_specie: str, ltol: float = 0.2, stol: float = 0.3, angle_tol: float = 5.0, ) -> List["StructureGroupDoc"]: """ Create a list of StructureGroupDocs from a list of ungrouped entries. Args: entries: the list of ComputedStructureEntries to process. ignored_specie: the ignored specie for the structure matcher ltol: length tolerance for the structure matcher stol: site position tolerance for the structure matcher angle_tol: angel tolerance for the structure matcher """ results = [] sm = StructureMatcher( comparator=ElementComparator(), primitive_cell=True, ignored_species=[ignored_specie], ltol=ltol, stol=stol, angle_tol=angle_tol, ) # Add a framework field to each entry's data attribute for ient in entries: ient.data["framework"] = _get_framework( ient.composition.reduced_formula, ignored_specie ) # split into groups for each framework, must sort before grouping entries.sort(key=lambda x: x.data["framework"]) framework_groups = groupby(entries, key=lambda x: x.data["framework"]) cnt_ = 0 for framework, f_group in framework_groups: # if you only have ignored atoms put them into one "ignored" group f_group_l = list(f_group) if framework == "ignored": struct_group = cls.from_grouped_entries( f_group_l, ignored_specie=ignored_specie ) cnt_ += len(struct_group.material_ids) # type: ignore continue logger.debug( f"Performing structure matching for {framework} with {len(f_group_l)} documents." ) for g in group_entries_with_structure_matcher(f_group_l, sm): struct_group = cls.from_grouped_entries( g, ignored_specie=ignored_specie ) cnt_ += len(struct_group.material_ids) # type: ignore results.append(struct_group) if cnt_ != len(entries): raise RuntimeError( "The number of entries in all groups the end does not match the number of supplied entries documents." "Something is seriously wrong, please rebuild the entire database and see if the problem persists." ) return results @staticmethod def get_host_and_insertion_ids( entries: List[Union[ComputedEntry, ComputedStructureEntry]], ignored_specie: str, ) -> dict: host_and_insertion_ids = { "host_id": None, "host_ids": [], "host_entries": [], "insertion_ids": [], } # type:dict ignored_specie_min_fraction = min( [e.composition.get_atomic_fraction(ignored_specie) for e in entries] ) for e in entries: if ( e.composition.get_atomic_fraction(ignored_specie) == ignored_specie_min_fraction ): host_and_insertion_ids["host_entries"].append(e) host_and_insertion_ids["host_ids"].append(e.data["material_id"]) else: host_and_insertion_ids["insertion_ids"].append(e.data["material_id"]) host_and_insertion_ids["host_id"] = min( host_and_insertion_ids["host_entries"], key=lambda x: x.energy_per_atom ).data["material_id"] return host_and_insertion_ids def group_entries_with_structure_matcher( g, struct_matcher: StructureMatcher, working_ion: Optional[str] = None, ) -> Iterable[List[Union[ComputedStructureEntry, ComputedEntry]]]: """ Group the entries together based on similarity of the primitive cells Args: g: a list of entries struct_matcher: the StructureMatcher object used to aggregate structures working_ion: the name of the working ion, if none use the first ignored species from the structure_matcher Returns: subgroups: subgroups that are grouped together based on structure similarity """ if working_ion is None: wion: str = struct_matcher.as_dict()["ignored_species"][0] # Sort the entries by symmetry and by working ion fraction def get_num_sym_ops(ent): sga = SpacegroupAnalyzer(ent.structure) return len(sga.get_space_group_operations()) g.sort(key=get_num_sym_ops, reverse=True) g.sort(key=lambda x: x.composition.get_atomic_fraction(wion)) labs = generic_groupby( g, comp=lambda x, y: struct_matcher.fit(x.structure, y.structure, symmetric=True), ) for ilab in set(labs): sub_g = [g[itr] for itr, jlab in enumerate(labs) if jlab == ilab] yield [el for el in sub_g] def _get_id_lexi(task_id) -> Union[int, str]: """Get a lexicographic representation for a task ID""" # matches "mp-1234" or "1234" followed by and optional "-(Alphanumeric)" mpid = MPID(task_id) return mpid.parts def _get_framework(formula, ignored_specie) -> str: """ Return the reduced formula of the entry without any of the ignored species Return 'ignored' if the all the atoms are ignored """ dd_ = Composition(formula).as_dict() if dd_.keys() == set([ignored_specie]): return "ignored" if ignored_specie in dd_: dd_.pop(ignored_specie) return Composition.from_dict(dd_).reduced_formula ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/stubs.py0000644000175100001770000000175214673360562017041 0ustar00runnerdocker# mypy: ignore-errors # isort: off """ This module stubs some pymatgen classes that implement custom behavior outside the standard MSONable model """ from typing import Dict import pymatgen.core.composition from pydantic import BaseModel from pymatgen.core.periodic_table import Element """ The stub names are kept in sync with the actual classes so they show up correctly in the JSON Schema. They are imported here in as Stubbed classes to prevent name clashing """ class StubComposition(BaseModel): """A dictionary mapping element to total quantity""" __root__: Dict[Element, float] @classmethod # type: ignore def get_validators(cls): yield validate_composition def validate_composition(cls, v): if isinstance(v, pymatgen.core.structure.Composition): return v return pymatgen.core.composition.Composition(**v) pymatgen.core.composition.Composition.__pydantic_model__ = StubComposition pymatgen.core.composition.Composition.__get_validators__ = get_validators ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/substrates.py0000644000175100001770000000234514673360562020077 0ustar00runnerdockerfrom pydantic import BaseModel, Field from typing import Optional class SubstratesDoc(BaseModel): """ Possible growth substrates for a given material. """ sub_form: Optional[str] = Field( None, description="Reduced formula of the substrate.", ) sub_id: Optional[str] = Field( None, description="Materials Project ID of the substrate material. This comes in the form: mp-******.", ) film_orient: Optional[str] = Field( None, description="Surface orientation of the film material.", ) area: Optional[float] = Field( None, description="Minimum coincident interface area in Ų.", ) energy: Optional[float] = Field( None, description="Elastic energy in meV.", ) film_id: Optional[str] = Field( None, description="The Materials Project ID of the film material. This comes in the form: mp-******.", ) norients: Optional[int] = Field( None, description="Number of possible surface orientations for the substrate.", alias="_norients", ) orient: Optional[str] = Field( None, description="Surface orientation of the substrate material.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/summary.py0000644000175100001770000003701014673360562017372 0ustar00runnerdockerfrom enum import Enum from typing import Dict, List, Optional, TypeVar, Union from pydantic import BaseModel, Field from pymatgen.core.periodic_table import Element from pymatgen.core.structure import Structure from emmet.core.electronic_structure import BandstructureData, DosData from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID from emmet.core.thermo import DecompositionProduct from emmet.core.xas import Edge, Type T = TypeVar("T", bound="SummaryDoc") class HasProps(Enum): """ Enum of possible hasprops values. """ materials = "materials" thermo = "thermo" xas = "xas" grain_boundaries = "grain_boundaries" chemenv = "chemenv" electronic_structure = "electronic_structure" absorption = "absorption" bandstructure = "bandstructure" dos = "dos" magnetism = "magnetism" elasticity = "elasticity" dielectric = "dielectric" piezoelectric = "piezoelectric" surface_properties = "surface_properties" oxi_states = "oxi_states" provenance = "provenance" charge_density = "charge_density" eos = "eos" phonon = "phonon" insertion_electrodes = "insertion_electrodes" substrates = "substrates" class SummaryStats(BaseModel): """ Statistics about a specified SummaryDoc field. """ field: Optional[str] = Field( None, title="Field", description="Field name corresponding to a field in SummaryDoc.", ) num_samples: Optional[int] = Field( None, title="Sample", description="The number of documents sampled to generate statistics. " "If unspecified, statistics will be from entire database.", ) min: Optional[float] = Field( None, title="Minimum", description="The minimum value " "of the specified field used to " "generate statistics.", ) max: Optional[float] = Field( None, title="Maximum", description="The maximum value " "of the specified field used to " "generate statistics.", ) median: Optional[float] = Field( None, title="Median", description="The median of the field values." ) mean: Optional[float] = Field( None, title="Mean", description="The mean of the field values." ) distribution: Optional[List[float]] = Field( None, title="Distribution", description="List of floats specifying a kernel density " "estimator of the distribution, equally spaced " "between specified minimum and maximum values.", ) class XASSearchData(BaseModel): """ Fields in XAS sub docs in summary """ edge: Optional[Edge] = Field( None, title="Absorption Edge", description="The interaction edge for XAS", ) absorbing_element: Optional[Element] = Field( None, description="Absorbing element.", ) spectrum_type: Optional[Type] = Field( None, description="Type of XAS spectrum.", ) class GBSearchData(BaseModel): """ Fields in grain boundary sub docs in summary """ sigma: Optional[int] = Field( None, description="Sigma value of the boundary.", ) type: Optional[str] = Field( None, description="Grain boundary type.", ) gb_energy: Optional[float] = Field( None, description="Grain boundary energy in J/m^2.", ) rotation_angle: Optional[float] = Field( None, description="Rotation angle in degrees.", ) class SummaryDoc(PropertyDoc): """ Summary information about materials and their properties, useful for materials screening studies and searching. """ property_name: str = "summary" # Materials structure: Structure = Field( ..., description="The lowest energy structure for this material.", ) task_ids: List[MPID] = Field( [], title="Calculation IDs", description="List of Calculations IDs associated with this material.", ) # Thermo uncorrected_energy_per_atom: Optional[float] = Field( None, description="The total DFT energy of this material per atom in eV/atom.", ) energy_per_atom: Optional[float] = Field( None, description="The total corrected DFT energy of this material per atom in eV/atom.", ) formation_energy_per_atom: Optional[float] = Field( None, description="The formation energy per atom in eV/atom.", ) energy_above_hull: Optional[float] = Field( None, description="The energy above the hull in eV/Atom.", ) is_stable: bool = Field( False, description="Flag for whether this material is on the hull and therefore stable.", ) equilibrium_reaction_energy_per_atom: Optional[float] = Field( None, description="The reaction energy of a stable entry from the neighboring equilibrium stable materials in eV." " Also known as the inverse distance to hull.", ) decomposes_to: Optional[List[DecompositionProduct]] = Field( None, description="List of decomposition data for this material. Only valid for metastable or unstable material.", ) # XAS xas: Optional[List[XASSearchData]] = Field( None, description="List of xas documents.", ) # GB grain_boundaries: Optional[List[GBSearchData]] = Field( None, description="List of grain boundary documents.", ) # Electronic Structure band_gap: Optional[float] = Field( None, description="Band gap energy in eV.", ) cbm: Optional[Union[float, Dict]] = Field( None, description="Conduction band minimum data.", ) vbm: Optional[Union[float, Dict]] = Field( None, description="Valence band maximum data.", ) efermi: Optional[float] = Field( None, description="Fermi energy in eV.", ) is_gap_direct: Optional[bool] = Field( None, description="Whether the band gap is direct.", ) is_metal: Optional[bool] = Field( None, description="Whether the material is a metal.", ) es_source_calc_id: Optional[Union[MPID, int]] = Field( None, description="The source calculation ID for the electronic structure data.", ) bandstructure: Optional[BandstructureData] = Field( None, description="Band structure data for the material.", ) dos: Optional[DosData] = Field( None, description="Density of states data for the material.", ) # DOS dos_energy_up: Optional[float] = Field( None, description="Spin-up DOS band gap in eV.", ) dos_energy_down: Optional[float] = Field( None, description="Spin-down DOS band gap in eV.", ) # Magnetism is_magnetic: Optional[bool] = Field( None, description="Whether the material is magnetic.", ) ordering: Optional[str] = Field( None, description="Type of magnetic ordering.", ) total_magnetization: Optional[float] = Field( None, description="Total magnetization in μB.", ) total_magnetization_normalized_vol: Optional[float] = Field( None, description="Total magnetization normalized by volume in μB/ų.", ) total_magnetization_normalized_formula_units: Optional[float] = Field( None, description="Total magnetization normalized by formula unit in μB/f.u. .", ) num_magnetic_sites: Optional[int] = Field( None, description="The number of magnetic sites.", ) num_unique_magnetic_sites: Optional[int] = Field( None, description="The number of unique magnetic sites.", ) types_of_magnetic_species: Optional[List[Element]] = Field( None, description="Magnetic specie elements.", ) # Elasticity # k_voigt: Optional[float] = Field(None, description="Voigt average of the bulk modulus.") # k_reuss: Optional[float] = Field(None, description="Reuss average of the bulk modulus in GPa.") # k_vrh: Optional[float] = Field(None, description="Voigt-Reuss-Hill average of the bulk modulus in GPa.") # g_voigt: Optional[float] = Field(None, description="Voigt average of the shear modulus in GPa.") # g_reuss: Optional[float] = Field(None, description="Reuss average of the shear modulus in GPa.") # g_vrh: Optional[float] = Field(None, description="Voigt-Reuss-Hill average of the shear modulus in GPa.") bulk_modulus: Optional[dict] = Field( None, description="Voigt, Reuss, and Voigt-Reuss-Hill averages of the bulk modulus in GPa.", ) shear_modulus: Optional[dict] = Field( None, description="Voigt, Reuss, and Voigt-Reuss-Hill averages of the shear modulus in GPa.", ) universal_anisotropy: Optional[float] = Field( None, description="Elastic anisotropy." ) homogeneous_poisson: Optional[float] = Field(None, description="Poisson's ratio.") # Dielectric and Piezo e_total: Optional[float] = Field( None, description="Total dielectric constant.", ) e_ionic: Optional[float] = Field( None, description="Ionic contribution to dielectric constant.", ) e_electronic: Optional[float] = Field( None, description="Electronic contribution to dielectric constant.", ) n: Optional[float] = Field( None, description="Refractive index.", ) e_ij_max: Optional[float] = Field( None, description="Piezoelectric modulus.", ) # Surface Properties weighted_surface_energy_EV_PER_ANG2: Optional[float] = Field( None, description="Weighted surface energy in eV/Ų.", ) weighted_surface_energy: Optional[float] = Field( None, description="Weighted surface energy in J/m².", ) weighted_work_function: Optional[float] = Field( None, description="Weighted work function in eV.", ) surface_anisotropy: Optional[float] = Field( None, description="Surface energy anisotropy.", ) shape_factor: Optional[float] = Field( None, description="Shape factor.", ) has_reconstructed: Optional[bool] = Field( None, description="Whether the material has any reconstructed surfaces.", ) # Oxi States possible_species: Optional[List[str]] = Field( None, description="Possible charged species in this material.", ) # Has Props has_props: Optional[Dict[str, bool]] = Field( None, description="List of properties that are available for a given material.", ) # Theoretical theoretical: bool = Field( True, description="Whether the material is theoretical.", ) # External Database IDs database_IDs: Dict[str, List[str]] = Field( {}, description="External database IDs corresponding to this material." ) @classmethod def from_docs(cls, material_id: MPID, **docs: Dict[str, Dict]): """Converts a bunch of summary docs into a SummaryDoc""" doc = _copy_from_doc(docs) # Reshape document for various sub-sections # Electronic Structure + Bandstructure + DOS if "bandstructure" in doc: if doc["bandstructure"] is not None and list( filter(lambda x: x is not None, doc["bandstructure"].values()) ): doc["has_props"]["bandstructure"] = True else: del doc["bandstructure"] if "dos" in doc: if doc["dos"] is not None and list( filter(lambda x: x is not None, doc["dos"].values()) ): doc["has_props"]["dos"] = True else: del doc["dos"] if "task_id" in doc: del doc["task_id"] return SummaryDoc(material_id=material_id, **doc) # Key mapping summary_fields: Dict[str, list] = { HasProps.materials.value: [ "nsites", "elements", "nelements", "composition", "composition_reduced", "formula_pretty", "formula_anonymous", "chemsys", "volume", "density", "density_atomic", "symmetry", "structure", "deprecated", "task_ids", "builder_meta", ], HasProps.thermo.value: [ "uncorrected_energy_per_atom", "energy_per_atom", "formation_energy_per_atom", "energy_above_hull", "is_stable", "equilibrium_reaction_energy_per_atom", "decomposes_to", ], HasProps.xas.value: ["absorbing_element", "edge", "spectrum_type", "spectrum_id"], HasProps.grain_boundaries.value: [ "gb_energy", "sigma", "type", "rotation_angle", "w_sep", ], HasProps.electronic_structure.value: [ "band_gap", "efermi", "cbm", "vbm", "is_gap_direct", "is_metal", "bandstructure", "dos", "task_id", ], HasProps.magnetism.value: [ "is_magnetic", "ordering", "total_magnetization", "total_magnetization_normalized_vol", "total_magnetization_normalized_formula_units", "num_magnetic_sites", "num_unique_magnetic_sites", "types_of_magnetic_species", "is_magnetic", ], HasProps.elasticity.value: [ "bulk_modulus", "shear_modulus", "universal_anisotropy", "homogeneous_poisson", ], HasProps.dielectric.value: ["e_total", "e_ionic", "e_electronic", "n"], HasProps.piezoelectric.value: ["e_ij_max"], HasProps.surface_properties.value: [ "weighted_surface_energy", "weighted_surface_energy_EV_PER_ANG2", "shape_factor", "surface_anisotropy", "weighted_work_function", "has_reconstructed", ], HasProps.oxi_states.value: ["possible_species"], HasProps.provenance.value: ["theoretical", "database_IDs"], HasProps.charge_density.value: [], HasProps.eos.value: [], HasProps.phonon.value: [], HasProps.absorption.value: [], HasProps.insertion_electrodes.value: [], HasProps.substrates.value: [], HasProps.chemenv.value: [], } def _copy_from_doc(doc): """Helper function to copy the list of keys over from amalgamated document""" has_props = {str(val.value): False for val in HasProps} d = {"has_props": has_props, "origins": []} # Complex function to grab the keys and put them in the root doc # if the item is a list, it makes one doc per item with those corresponding keys for doc_key in summary_fields: sub_doc = doc.get(doc_key, None) if isinstance(sub_doc, list) and len(sub_doc) > 0: d["has_props"][doc_key] = True d[doc_key] = [] for sub_item in sub_doc: temp_doc = { copy_key: sub_item[copy_key] for copy_key in summary_fields[doc_key] if copy_key in sub_item } d[doc_key].append(temp_doc) elif isinstance(sub_doc, dict): d["has_props"][doc_key] = True if sub_doc.get("origins", None): d["origins"].extend(sub_doc["origins"]) d.update( { copy_key: sub_doc[copy_key] for copy_key in summary_fields[doc_key] if copy_key in sub_doc } ) return d ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/surface_properties.py0000644000175100001770000000514614673360562021606 0ustar00runnerdockerfrom typing import List, Optional from pymatgen.core.structure import Structure from pydantic import BaseModel, Field class SurfaceEntry(BaseModel): """ Surface energies, miller indicies, ... """ miller_index: Optional[List[int]] = Field( None, description="Miller index of surface.", ) surface_energy_EV_PER_ANG2: Optional[float] = Field( None, description="Surface energy in eV/Ų.", ) surface_energy: Optional[float] = Field( None, description="Surface energy in J/m².", ) is_reconstructed: Optional[bool] = Field( None, description="Whether it is a reconstructed surface.", ) structure: Optional[str] = Field( None, description="CIF of slab structure.", ) work_function: Optional[float] = Field( None, description="Work function in eV.", ) efermi: Optional[float] = Field( None, description="Fermi energy in eV.", ) area_fraction: Optional[float] = Field( None, description="Area fraction.", ) has_wulff: Optional[bool] = Field( None, description="Whether the surface has wulff entry.", ) class SurfacePropDoc(BaseModel): """ Model for a document containing surface properties data """ surfaces: Optional[List[SurfaceEntry]] = Field( None, description="List of individual surface data.", ) weighted_surface_energy_EV_PER_ANG2: Optional[float] = Field( None, description="Weighted surface energy in eV/Ų", ) weighted_surface_energy: Optional[float] = Field( None, description="Weighted surface energy in J/m²", ) surface_anisotropy: Optional[float] = Field( None, description="Surface energy anisotropy.", ) pretty_formula: Optional[str] = Field( None, description="Reduced Formula of the material.", ) shape_factor: Optional[float] = Field( None, description="Shape factor.", ) weighted_work_function: Optional[float] = Field( None, description="Weighted work function in eV.", ) has_reconstructed: Optional[bool] = Field( None, description="Whether the entry has any reconstructed surfaces.", ) material_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) structure: Optional[Structure] = Field( None, description="The conventional crystal structure of the material.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/symmetry.py0000644000175100001770000001201214673360562017561 0ustar00runnerdockerfrom typing import Any, Dict, Optional from pydantic import BaseModel, Field from pymatgen.core import Structure from pymatgen.core.structure import Molecule from pymatgen.symmetry.analyzer import PointGroupAnalyzer, SpacegroupAnalyzer, spglib from emmet.core.settings import EmmetSettings from emmet.core.utils import ValueEnum SETTINGS = EmmetSettings() class CrystalSystem(ValueEnum): """ The crystal system of the lattice """ tri = "Triclinic" mono = "Monoclinic" ortho = "Orthorhombic" tet = "Tetragonal" trig = "Trigonal" hex_ = "Hexagonal" cubic = "Cubic" class PointGroupData(BaseModel): """ Defines symmetry for a molecule document """ point_group: Optional[str] = Field( None, title="Point Group Symbol", description="The point group for the lattice" ) rotation_number: Optional[float] = Field( None, title="Rotational Symmetry Number", description="Rotational symmetry number for the molecule", ) linear: Optional[bool] = Field( None, title="Molecule Linearity", description="Is the molecule linear?" ) tolerance: Optional[float] = Field( None, title="Point Group Analyzer Tolerance", description="Distance tolerance to consider sites as symmetrically equivalent.", ) eigen_tolerance: Optional[float] = Field( None, title="Interia Tensor Eigenvalue Tolerance", description="Tolerance to compare eigen values of the inertia tensor.", ) matrix_tolerance: Optional[float] = Field( None, title="Symmetry Operation Matrix Element Tolerance", description="Tolerance used to generate the full set of symmetry operations of the point group.", ) @classmethod def from_molecule(cls, molecule: Molecule) -> "PointGroupData": tol = SETTINGS.PGATOL eigentol = SETTINGS.PGAEIGENTOL matrixtol = SETTINGS.PGAMATRIXTOL pga = PointGroupAnalyzer( molecule, tolerance=tol, eigen_tolerance=eigentol, matrix_tolerance=matrixtol, ) symmetry: Dict[str, Any] = { "tolerance": tol, "eigen_tolerance": eigentol, "matrix_tolerance": matrixtol, "point_group": pga.sch_symbol, } rotational_symmetry_numbers = { 1.0: ["C1", "Cs", "Ci", "C*v", "S2"], 2.0: ["C2", "C2h", "C2v", "S4", "D*h"], 3.0: ["C3", "C3h", "C3v", "S6"], 4.0: ["C4v", "D4h", "D4d", "D2", "D2h", "D2d"], 5.0: ["C5v", "Ih"], 6.0: ["D3", "D3h", "D3d"], 10.0: ["D5h", "D5d"], 12.0: ["T", "Td", "Th", "D6h"], 14.0: ["D7h"], 16.0: ["D8h"], 24.0: ["Oh"], float("inf"): ["Kh"], } r = 1.0 for rot_num, point_groups in rotational_symmetry_numbers.items(): if symmetry["point_group"] in point_groups: r = rot_num break if symmetry["point_group"] in ["C*v", "D*h"]: linear = True else: linear = False symmetry["rotation_number"] = float(r) symmetry["linear"] = linear return PointGroupData(**symmetry) class SymmetryData(BaseModel): """ Defines a symmetry data set for materials documents """ crystal_system: Optional[CrystalSystem] = Field( None, title="Crystal System", description="The crystal system for this lattice." ) symbol: Optional[str] = Field( None, title="Space Group Symbol", description="The spacegroup symbol for the lattice.", ) number: Optional[int] = Field( None, title="Space Group Number", description="The spacegroup number for the lattice.", ) point_group: Optional[str] = Field( None, title="Point Group Symbol", description="The point group for the lattice." ) symprec: Optional[float] = Field( None, title="Symmetry Finding Precision", description="The precision given to spglib to determine the symmetry of this lattice.", ) version: Optional[str] = Field(None, title="SPGLib version") @classmethod def from_structure(cls, structure: Structure) -> "SymmetryData": symprec = SETTINGS.SYMPREC sg = SpacegroupAnalyzer(structure, symprec=symprec) symmetry: Dict[str, Any] = {"symprec": symprec} if not sg.get_symmetry_dataset(): sg = SpacegroupAnalyzer(structure, 1e-3, 1) symmetry["symprec"] = 1e-3 symmetry.update( { "source": "spglib", "symbol": sg.get_space_group_symbol(), "number": sg.get_space_group_number(), "point_group": sg.get_point_group_symbol(), "crystal_system": CrystalSystem(sg.get_crystal_system().title()), "hall": sg.get_hall(), "version": spglib.__version__, } ) return SymmetryData(**symmetry) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0512903 emmet-core-0.84.2/emmet/core/synthesis/0000755000175100001770000000000014673360566017357 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/synthesis/__init__.py0000644000175100001770000000062014673360562021462 0ustar00runnerdockerfrom emmet.core.synthesis.core import ( SynthesisRecipe, SynthesisTypeEnum, SynthesisSearchResultModel, ) from emmet.core.synthesis.materials import ( Component, ExtractedMaterial, ) from emmet.core.synthesis.operations import ( Value, Conditions, Operation, OperationTypeEnum, ) from emmet.core.synthesis.reaction import ( FormulaPart, ReactionFormula, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/synthesis/core.py0000644000175100001770000000434414673360562020662 0ustar00runnerdockerfrom enum import Enum from typing import List, Optional, Any from pydantic import BaseModel, Field from emmet.core.synthesis.materials import ExtractedMaterial from emmet.core.synthesis.operations import Operation from emmet.core.synthesis.reaction import ReactionFormula class SynthesisTypeEnum(str, Enum): solid_state = "solid-state" sol_gel = "sol-gel" class SynthesisRecipe(BaseModel): """ Model for a document containing synthesis description data """ # Basic facts about this recipe: doi: str = Field( ..., description="DOI of the journal article.", ) paragraph_string: str = Field( "", description="The paragraph from which this recipe is extracted." ) synthesis_type: SynthesisTypeEnum = Field( ..., description="Type of the synthesis recipe." ) # Reaction related information: reaction_string: str = Field( ..., description="String representation of this recipe." ) reaction: ReactionFormula = Field(..., description="The balanced reaction formula.") target: ExtractedMaterial = Field(..., description="The target material.") targets_formula: List[str] = Field( ..., description="List of synthesized target material compositions." ) precursors_formula: List[str] = Field( ..., description="List of precursor material compositions." ) targets_formula_s: List[str] = Field( ..., description="List of synthesized target material compositions, as strings." ) precursors_formula_s: List[str] = Field( ..., description="List of precursor material compositions, as strings." ) precursors: List[ExtractedMaterial] = Field( ..., description="List of precursor materials." ) operations: List[Operation] = Field( ..., description="List of operations used to synthesize this recipe." ) class SynthesisSearchResultModel(SynthesisRecipe): """ Model for a document containing synthesis recipes data and additional keyword search results """ search_score: Optional[float] = Field( None, description="Search score.", ) highlights: Optional[List[Any]] = Field( None, description="Search highlights.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/synthesis/materials.py0000644000175100001770000000360314673360562021710 0ustar00runnerdockerfrom typing import List, Dict, Optional from pydantic import BaseModel, Field __all__ = ["Component", "ExtractedMaterial"] class Component(BaseModel): formula: str = Field(..., description="Formula of this component.") amount: str = Field(..., description="Amount of this component.") elements: Dict[str, str] = Field( ..., description="Amount of each chemical elements in this component." ) class Values(BaseModel): values: Optional[List[float]] = Field(None, description="List of values.") min_value: Optional[float] = Field(None, description="Minimal value.") max_value: Optional[float] = Field(None, description="Maximal value.") class ExtractedMaterial(BaseModel): """ Model for a material extracted from the literature """ material_string: str = Field( ..., description="String of the material as written in paper." ) material_formula: str = Field( ..., description="Normalized formula of the material." ) material_name: Optional[str] = Field( None, description="English name of the material." ) phase: Optional[str] = Field( None, description="Phase description of material, such as anatase." ) is_acronym: Optional[bool] = Field( None, description="Whether the material is an acronym, such as LMO for LiMn2O4." ) composition: List[Component] = Field( ..., description="List of components in this material." ) amounts_vars: Dict[str, Values] = Field( {}, description="Amount variables (formula subscripts)." ) elements_vars: Dict[str, List[str]] = Field( {}, description="Chemical element variables" ) additives: List[str] = Field([], description="List of additives, dopants, etc.") oxygen_deficiency: Optional[str] = Field( None, description="Symbol indicating whether the materials is oxygen deficient." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/synthesis/operations.py0000644000175100001770000000311414673360562022107 0ustar00runnerdockerfrom enum import Enum from typing import List, Optional from pydantic import BaseModel, Field class Value(BaseModel): min_value: Optional[float] = Field(None, description="Minimal value.") max_value: Optional[float] = Field(None, description="Maximal value.") values: List[float] = Field([], description="Enumerated values in the literature.") units: str = Field(..., description="Unit of this value.") class Conditions(BaseModel): heating_temperature: Optional[List[Value]] = Field( None, description="Heating temperatures." ) heating_time: Optional[List[Value]] = Field(None, description="Heating times.") heating_atmosphere: Optional[List[str]] = Field( None, description="List of heating atmospheres." ) mixing_device: Optional[str] = Field( None, description="Mixing device, if this operation is MIXING." ) mixing_media: Optional[str] = Field( None, description="Mixing media, if this operation is MIXING." ) class OperationTypeEnum(str, Enum): starting = "StartingSynthesis" mixing = "MixingOperation" shaping = "ShapingOperation" drying = "DryingOperation" heating = "HeatingOperation" quenching = "QuenchingOperation" class Operation(BaseModel): type: OperationTypeEnum = Field( ..., description="Type of the operation as classified by the pipeline." ) token: str = Field( ..., description="Token (word) of the operation as written in paper." ) conditions: Conditions = Field( ..., description="The conditions linked to this operation." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/synthesis/reaction.py0000644000175100001770000000160414673360562021532 0ustar00runnerdockerfrom typing import List, Dict from pydantic import BaseModel, Field __all__ = [ "FormulaPart", "ReactionFormula", ] class FormulaPart(BaseModel): amount: str = Field("1", description="Amount of the compound in a formula.") material: str = Field( ..., description="The compound that participates in a reaction." ) class ReactionFormula(BaseModel): """ Model for a balanced reaction """ left_side: List[FormulaPart] = Field( ..., description="List of materials and their amounts at the left side." ) right_side: List[FormulaPart] = Field( ..., description="List of materials and their amounts at the right side." ) # For example, BaCO3 + MO2 == BaMO3, element_substitution = {"M": "Ti"} element_substitution: Dict[str, str] = Field( {}, description="Dictionary that contains elemental substitutions" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/task.py0000644000175100001770000000215614673360562016642 0ustar00runnerdocker""" Core definition of a Task Document which represents a calculation from some program""" from datetime import datetime from typing import Union, Optional from pydantic import Field from emmet.core.base import EmmetBaseModel from emmet.core.mpid import MPID, MPculeID class BaseTaskDocument(EmmetBaseModel): """ Definition of base Task Document """ calc_code: str = Field(description="The calculation code used to compute this task") version: Optional[str] = Field( None, description="The version of the calculation code" ) dir_name: Optional[str] = Field(None, description="The directory for this task") task_id: Optional[Union[MPID, MPculeID]] = Field( None, description="the Task ID For this document" ) completed: bool = Field(False, description="Whether this calcuation completed") completed_at: Optional[datetime] = Field( None, description="Timestamp for when this task was completed" ) last_updated: datetime = Field( default_factory=datetime.utcnow, description="Timestamp for when this task document was last updated", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/tasks.py0000644000175100001770000011603314673360562017025 0ustar00runnerdocker# mypy: ignore-errors import logging import re from collections import OrderedDict from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar, Union import numpy as np from emmet.core.common import convert_datetime from emmet.core.mpid import MPID from emmet.core.structure import StructureMetadata from emmet.core.utils import utcnow from emmet.core.vasp.calc_types import ( CalcType, calc_type, TaskType, run_type, RunType, task_type, ) from emmet.core.vasp.calculation import ( CalculationInput, Calculation, PotcarSpec, RunStatistics, VaspObject, ) from emmet.core.vasp.task_valid import TaskState from monty.json import MontyDecoder from monty.serialization import loadfn from pydantic import ( BaseModel, ConfigDict, Field, field_validator, model_validator, ) from pymatgen.analysis.structure_analyzer import oxide_type from pymatgen.core.structure import Structure from pymatgen.core.trajectory import Trajectory from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from pymatgen.io.vasp import Incar, Kpoints, Poscar from pymatgen.io.vasp import Potcar as VaspPotcar monty_decoder = MontyDecoder() logger = logging.getLogger(__name__) _T = TypeVar("_T", bound="TaskDoc") _VOLUMETRIC_FILES = ("CHGCAR", "LOCPOT", "AECCAR0", "AECCAR1", "AECCAR2") class Potcar(BaseModel): pot_type: Optional[str] = Field(None, description="Pseudo-potential type, e.g. PAW") functional: Optional[str] = Field( None, description="Functional type use in the calculation." ) symbols: Optional[List[str]] = Field( None, description="List of VASP potcar symbols used in the calculation." ) class OrigInputs(CalculationInput): poscar: Optional[Poscar] = Field( None, description="Pymatgen object representing the POSCAR file.", ) potcar: Optional[Union[Potcar, VaspPotcar, List[Any]]] = Field( None, description="Pymatgen object representing the POTCAR file.", ) @field_validator("potcar", mode="before") @classmethod def potcar_ok(cls, v): """Check that the POTCAR meets type requirements.""" if isinstance(v, list): return list(v) return v @field_validator("potcar", mode="after") @classmethod def parse_potcar(cls, v): """Check that potcar attribute is not a pymatgen POTCAR.""" if isinstance(v, VaspPotcar): # The user should not mix potential types, but account for that here # Using multiple potential types will be caught in validation pot_typ = "_".join(set(p.potential_type for p in v)) return Potcar(pot_type=pot_typ, functional=v.functional, symbols=v.symbols) return v model_config = ConfigDict(arbitrary_types_allowed=True) class OutputDoc(BaseModel): structure: Optional[Structure] = Field( None, title="Output Structure", description="Output Structure from the VASP calculation.", ) density: Optional[float] = Field(None, description="Density of in units of g/cc.") energy: Optional[float] = Field(None, description="Total Energy in units of eV.") forces: Optional[List[List[float]]] = Field( None, description="The force on each atom in units of eV/A^2." ) stress: Optional[List[List[float]]] = Field( None, description="The stress on the cell in units of kB." ) energy_per_atom: Optional[float] = Field( None, description="The final DFT energy per atom for the last calculation" ) bandgap: Optional[float] = Field( None, description="The DFT bandgap for the last calculation" ) @model_validator(mode="before") def set_density_from_structure(cls, values): # Validator to automatically set density from structure if not already # specified. This might happen when importing an older atomate2-format # TaskDocument. if not values.get("density", None): if isinstance(values["structure"], dict): values["density"] = values["structure"].get("density", None) else: values["density"] = values["structure"].density return values @classmethod def from_vasp_calc_doc( cls, calc_doc: Calculation, trajectory: Optional[Trajectory] = None ) -> "OutputDoc": """ Create a summary of VASP calculation outputs from a VASP calculation document. This will first look for ionic steps in the calculation document. If found, will use it and ignore the trajectory. I not, will get ionic steps from the trajectory. Parameters ---------- calc_doc A VASP calculation document. trajectory A pymatgen Trajectory. Returns ------- OutputDoc The calculation output summary. """ if calc_doc.output.ionic_steps is not None: forces = calc_doc.output.ionic_steps[-1].forces stress = calc_doc.output.ionic_steps[-1].stress elif trajectory is not None: ionic_steps = trajectory.frame_properties forces = ionic_steps[-1]["forces"] stress = ionic_steps[-1]["stress"] else: raise RuntimeError("Unable to find ionic steps.") return cls( structure=calc_doc.output.structure, energy=calc_doc.output.energy, energy_per_atom=calc_doc.output.energy_per_atom, bandgap=calc_doc.output.bandgap, forces=forces, stress=stress, ) class InputDoc(CalculationInput): """Light wrapper around `CalculationInput` with a few extra fields. pseudo_potentials (Potcar) : summary of the POTCARs used in the calculation xc_override (str) : the exchange-correlation functional used if not the one specified by POTCAR is_lasph (bool) : how the calculation set LASPH (aspherical corrections) magnetic_moments (list of floats) : on-site magnetic moments """ pseudo_potentials: Optional[Potcar] = Field( None, description="Summary of the pseudo-potentials used in this calculation" ) xc_override: Optional[str] = Field( None, description="Exchange-correlation functional used if not the default" ) is_lasph: Optional[bool] = Field( None, description="Whether the calculation was run with aspherical corrections" ) magnetic_moments: Optional[List[float]] = Field( None, description="Magnetic moments for each atom" ) @field_validator("parameters", mode="after") @classmethod def parameter_keys_should_not_contain_spaces(cls, parameters: Optional[Dict]): # A change in VASP introduced whitespace into some parameters, # for example `PE` was observed in # VASP 6.4.3. This will lead to an incorrect return value from RunType. # This validator will ensure that any already-parsed documents are fixed. if parameters: return {k.strip(): v for k, v in parameters.items()} @classmethod def from_vasp_calc_doc(cls, calc_doc: Calculation) -> "InputDoc": """ Create calculation input summary from a calculation document. Parameters ---------- calc_doc A VASP calculation document. Returns ------- InputDoc A summary of the input structure and parameters. """ xc = calc_doc.input.incar.get("GGA") or calc_doc.input.incar.get("METAGGA") if xc: xc = xc.upper() pot_type, func = calc_doc.input.potcar_type[0].split("_") func = "lda" if len(pot_type) == 1 else "_".join(func) pps = Potcar(pot_type=pot_type, functional=func, symbols=calc_doc.input.potcar) return cls( **calc_doc.input.model_dump(), pseudo_potentials=pps, xc_override=xc, is_lasph=calc_doc.input.parameters.get("LASPH", False), magnetic_moments=calc_doc.input.parameters.get("MAGMOM"), ) class CustodianDoc(BaseModel): corrections: Optional[List[Any]] = Field( None, title="Custodian Corrections", description="List of custodian correction data for calculation.", ) job: Optional[Any] = Field( None, title="Custodian Job Data", description="Job data logged by custodian.", ) class AnalysisDoc(BaseModel): delta_volume: Optional[float] = Field( None, title="Volume Change", description="Volume change for the calculation.", ) delta_volume_percent: Optional[float] = Field( None, title="Volume Change Percent", description="Percent volume change for the calculation.", ) max_force: Optional[float] = Field( None, title="Max Force", description="Maximum force on any atom at the end of the calculation.", ) warnings: Optional[List[str]] = Field( None, title="Calculation Warnings", description="Warnings issued after analysis.", ) errors: Optional[List[str]] = Field( None, title="Calculation Errors", description="Errors issued after analysis.", ) @classmethod def from_vasp_calc_docs( cls, calcs_reversed: List[Calculation], volume_change_warning_tol: float = 0.2, ) -> "AnalysisDoc": """ Create analysis summary from VASP calculation documents. Parameters ---------- calcs_reversed A list of VASP calculation documents in reverse order . volume_change_warning_tol Maximum volume change allowed in VASP relaxations before the calculation is tagged with a warning. Returns ------- AnalysisDoc The relaxation analysis. """ initial_vol = calcs_reversed[-1].input.structure.lattice.volume final_vol = calcs_reversed[0].output.structure.lattice.volume delta_vol = final_vol - initial_vol percent_delta_vol = 100 * delta_vol / initial_vol warnings = [] errors = [] if abs(percent_delta_vol) > volume_change_warning_tol * 100: warnings.append(f"Volume change > {volume_change_warning_tol * 100}%") final_calc = calcs_reversed[0] max_force = None if final_calc.has_vasp_completed == TaskState.SUCCESS: # max force and valid structure checks structure = final_calc.output.structure # do not check max force for MD run if calcs_reversed[0].input.parameters.get("IBRION", -1) != 0: max_force = _get_max_force(final_calc) warnings.extend(_get_drift_warnings(final_calc)) if not structure.is_valid(): errors.append("Bad structure (atoms are too close!)") return cls( delta_volume=delta_vol, delta_volume_percent=percent_delta_vol, max_force=max_force, warnings=warnings, errors=errors, ) class TaskDoc(StructureMetadata, extra="allow"): """Calculation-level details about VASP calculations that power Materials Project.""" tags: Union[List[str], None] = Field( [], title="tag", description="Metadata tagged to a given task." ) dir_name: Optional[str] = Field( None, description="The directory for this VASP task" ) state: Optional[TaskState] = Field(None, description="State of this calculation") calcs_reversed: Optional[List[Calculation]] = Field( None, title="Calcs reversed data", description="Detailed data for each VASP calculation contributing to the task document.", ) structure: Optional[Structure] = Field( None, description="Final output structure from the task" ) task_type: Optional[Union[TaskType, CalcType]] = Field( None, description="The type of calculation." ) run_type: Optional[RunType] = Field( None, description="The functional used in the calculation." ) calc_type: Optional[CalcType] = Field( None, description="The functional and task type used in the calculation." ) task_id: Optional[Union[MPID, str]] = Field( None, description="The (task) ID of this calculation, used as a universal reference across property documents." "This comes in the form: mp-******.", ) orig_inputs: Optional[OrigInputs] = Field( None, description="The exact set of input parameters used to generate the current task document.", ) input: Optional[InputDoc] = Field( None, description="The input structure used to generate the current task document.", ) output: Optional[OutputDoc] = Field( None, description="The exact set of output parameters used to generate the current task document.", ) included_objects: Optional[List[VaspObject]] = Field( None, description="List of VASP objects included with this task document" ) vasp_objects: Optional[Dict[VaspObject, Any]] = Field( None, description="Vasp objects associated with this task" ) entry: Optional[ComputedEntry] = Field( None, description="The ComputedEntry from the task doc" ) task_label: Optional[str] = Field(None, description="A description of the task") author: Optional[str] = Field( None, description="Author extracted from transformations" ) icsd_id: Optional[Union[str, int]] = Field( None, description="Inorganic Crystal Structure Database id of the structure" ) transformations: Optional[Any] = Field( None, description="Information on the structural transformations, parsed from a " "transformations.json file", ) additional_json: Optional[Dict[str, Any]] = Field( None, description="Additional json loaded from the calculation directory" ) custodian: Optional[List[CustodianDoc]] = Field( None, title="Calcs reversed data", description="Detailed custodian data for each VASP calculation contributing to the task document.", ) analysis: Optional[AnalysisDoc] = Field( None, title="Calculation Analysis", description="Some analysis of calculation data after collection.", ) last_updated: Optional[datetime] = Field( utcnow(), description="Timestamp for the most recent calculation for this task document", ) batch_id: Optional[str] = Field( None, description="Identifier for this calculation; should provide rough information about the calculation origin and purpose.", ) # Note that private fields are needed because TaskDoc permits extra info # added to the model, unlike TaskDocument. Because of this, when pydantic looks up # attrs on the model, it searches for them in the model extra dict first, and if it # can't find them, throws an AttributeError. It does this before looking to see if the # class has that attr defined on it. # _structure_entry: Optional[ComputedStructureEntry] = PrivateAttr(None) def model_post_init(self, __context: Any) -> None: # Always refresh task_type, calc_type, run_type # See, e.g. https://github.com/materialsproject/emmet/issues/960 # where run_type's were set incorrectly in older versions of TaskDoc # only run if attributes containing input sets are available attrs = ["calcs_reversed", "input", "orig_inputs"] if not any(hasattr(self, attr) and getattr(self, attr) for attr in attrs): return # To determine task and run type, we search for input sets in this order # of precedence: calcs_reversed, inputs, orig_inputs inp_set = None inp_sets_to_check = [self.input, self.orig_inputs] if (calcs_reversed := getattr(self, "calcs_reversed", None)) is not None: inp_sets_to_check = [calcs_reversed[0].input] + inp_sets_to_check for inp_set in inp_sets_to_check: if inp_set is not None: self.task_type = task_type(inp_set) break # calcs_reversed needed below if calcs_reversed is not None: self.run_type = self._get_run_type(calcs_reversed) if inp_set is not None: self.calc_type = self._get_calc_type(calcs_reversed, inp_set) # TODO: remove after imposing TaskDoc schema on older tasks in collection if self.structure is None: self.structure = calcs_reversed[0].output.structure # Make sure that the datetime field is properly formatted # (Unclear when this is not the case, please leave comment if observed) @field_validator("last_updated", mode="before") @classmethod def last_updated_dict_ok(cls, v) -> datetime: return convert_datetime(cls, v) @field_validator("batch_id", mode="before") @classmethod def _validate_batch_id(cls, v) -> str: if v is not None: invalid_chars = set( char for char in v if (not char.isalnum()) and (char not in {"-", "_"}) ) if len(invalid_chars) > 0: raise ValueError( f"Invalid characters in batch_id: {' '.join(invalid_chars)}" ) return v @model_validator(mode="after") def set_entry(self) -> datetime: if ( not self.entry and self.calcs_reversed and getattr(self.calcs_reversed[0].output, "structure", None) ): self.entry = self.get_entry(self.calcs_reversed, self.task_id) return self @classmethod def from_directory( cls: Type[_T], dir_name: Union[Path, str], volumetric_files: Tuple[str, ...] = _VOLUMETRIC_FILES, store_additional_json: bool = True, additional_fields: Optional[Dict[str, Any]] = None, volume_change_warning_tol: float = 0.2, task_names: Optional[list[str]] = None, **vasp_calculation_kwargs, ) -> _T: """ Create a task document from a directory containing VASP files. Parameters ---------- dir_name The path to the folder containing the calculation outputs. store_additional_json Whether to store additional json files found in the calculation directory. volumetric_files Volumetric files to search for. additional_fields Dictionary of additional fields to add to output document. volume_change_warning_tol Maximum volume change allowed in VASP relaxations before the calculation is tagged with a warning. task_names Naming scheme for multiple calculations in on folder e.g. ["relax1","relax2"]. Can be subfolder or extension. **vasp_calculation_kwargs Additional parsing options that will be passed to the :obj:`.Calculation.from_vasp_files` function. Returns ------- TaskDoc A task document for the calculation. """ logger.info(f"Getting task doc in: {dir_name}") additional_fields = {} if additional_fields is None else additional_fields dir_name = Path(dir_name) task_files = _find_vasp_files( dir_name, volumetric_files=volumetric_files, task_names=task_names ) if len(task_files) == 0: raise FileNotFoundError("No VASP files found!") calcs_reversed = [] all_vasp_objects = [] for task_name, files in task_files.items(): calc_doc, vasp_objects = Calculation.from_vasp_files( dir_name, task_name, **files, **vasp_calculation_kwargs ) calcs_reversed.append(calc_doc) all_vasp_objects.append(vasp_objects) # Reverse the list of calculations in the order: newest calc is the first # To match with calcs_reversed, all_vasp_objects is also reversed. calcs_reversed.reverse() all_vasp_objects.reverse() analysis = AnalysisDoc.from_vasp_calc_docs( calcs_reversed, volume_change_warning_tol=volume_change_warning_tol ) transformations, icsd_id, tags, author = _parse_transformations(dir_name) custodian = _parse_custodian(dir_name) orig_inputs = _parse_orig_inputs(dir_name) additional_json = None if store_additional_json: additional_json = _parse_additional_json(dir_name) dir_name = get_uri(dir_name) # convert to full uri path # only store objects from last calculation # TODO: make this an option vasp_objects = all_vasp_objects[0] included_objects = None if vasp_objects: included_objects = list(vasp_objects.keys()) doc = cls.from_structure( structure=calcs_reversed[0].output.structure, meta_structure=calcs_reversed[0].output.structure, include_structure=True, dir_name=dir_name, calcs_reversed=calcs_reversed, analysis=analysis, transformations=transformations, custodian=custodian, orig_inputs=orig_inputs, additional_json=additional_json, icsd_id=icsd_id, tags=tags, author=author, completed_at=calcs_reversed[0].completed_at, input=InputDoc.from_vasp_calc_doc(calcs_reversed[-1]), output=OutputDoc.from_vasp_calc_doc( calcs_reversed[0], vasp_objects.get(VaspObject.TRAJECTORY), # type: ignore ), state=_get_state(calcs_reversed, analysis), run_stats=_get_run_stats(calcs_reversed), vasp_objects=vasp_objects, included_objects=included_objects, task_type=calcs_reversed[0].task_type, ) return doc.model_copy(update=additional_fields) @classmethod def from_vasprun( cls: Type[_T], path: Union[str, Path], additional_fields: Optional[Dict[str, Any]] = None, volume_change_warning_tol: float = 0.2, **vasp_calculation_kwargs, ) -> _T: """ Create a task document from a vasprun.xml file. This is not recommended and will raise warnings, since some necessary information is absent from the vasprun.xml file, such as per-atom magnetic moments. However, the majority of the TaskDoc will be complete. Parameters ---------- path The path to the vasprun.xml. additional_fields: Dict[str, Any] = None, volume_change_warning_tol Maximum volume change allowed in VASP relaxations before the calculation is tagged with a warning. **vasp_calculation_kwargs Additional parsing options that will be passed to the :obj:`.Calculation.from_vasp_files` function. Returns ------- TaskDoc A task document for the calculation. """ logger.info(f"Getting vasprun.xml at: {path}") path = Path(path) dir_name = path.resolve().parent calc = Calculation.from_vasprun(path, **vasp_calculation_kwargs) calcs_reversed = [calc] analysis = AnalysisDoc.from_vasp_calc_docs( calcs_reversed, volume_change_warning_tol=volume_change_warning_tol ) # assume orig_inputs are those stated in vasprun.xml orig_inputs = OrigInputs( incar=calc.input.incar, poscar=Poscar(calc.input.structure), kpoints=calc.input.kpoints, potcar=calc.input.potcar, ) doc = cls.from_structure( structure=calcs_reversed[0].output.structure, meta_structure=calcs_reversed[0].output.structure, include_structure=True, dir_name=get_uri(dir_name), calcs_reversed=calcs_reversed, analysis=analysis, orig_inputs=orig_inputs, completed_at=calcs_reversed[0].completed_at, input=InputDoc.from_vasp_calc_doc(calcs_reversed[-1]), output=OutputDoc.from_vasp_calc_doc(calcs_reversed[0]), state=_get_state(calcs_reversed, analysis), run_stats=None, vasp_objects={}, included_objects=[], task_type=calcs_reversed[0].task_type, ) if additional_fields: doc = doc.model_copy(update=additional_fields) return doc @staticmethod def get_entry( calcs_reversed: List[Calculation], task_id: Optional[Union[MPID, str]] = None ) -> ComputedEntry: """ Get a computed entry from a list of VASP calculation documents. Parameters ---------- calcs_reversed A list of VASP calculation documents in a reverse order. task_id The job identifier. Returns ------- ComputedEntry A computed entry. """ entry_dict = { "correction": 0.0, "entry_id": task_id, "composition": calcs_reversed[0].output.structure.composition, "energy": calcs_reversed[0].output.energy, "parameters": { # Cannot be PotcarSpec document, pymatgen expects a dict # Note that `potcar_spec` is optional "potcar_spec": ( [dict(d) for d in calcs_reversed[0].input.potcar_spec] if calcs_reversed[0].input.potcar_spec else [] ), # Required to be compatible with MontyEncoder for the ComputedEntry "run_type": str(calcs_reversed[0].run_type), "is_hubbard": calcs_reversed[0].input.is_hubbard, "hubbards": calcs_reversed[0].input.hubbards, }, "data": { "oxide_type": oxide_type(calcs_reversed[0].output.structure), "aspherical": calcs_reversed[0].input.parameters.get("LASPH", False), "last_updated": str(utcnow()), }, } return ComputedEntry.from_dict(entry_dict) @staticmethod def _get_calc_type( calcs_reversed: list[Calculation], orig_inputs: OrigInputs ) -> CalcType: """Get the calc type from calcs_reversed. Returns -------- CalcType The type of calculation. """ inputs = ( calcs_reversed[0].input.model_dump() if len(calcs_reversed) > 0 else orig_inputs ) params = calcs_reversed[0].input.parameters incar = calcs_reversed[0].input.incar return calc_type(inputs, {**params, **incar}) @staticmethod def _get_run_type(calcs_reversed: list[Calculation]) -> RunType: """Get the run type from calcs_reversed. Returns -------- RunType The type of calculation. """ params = calcs_reversed[0].input.parameters incar = calcs_reversed[0].input.incar return run_type({**params, **incar}) @property def structure_entry(self) -> ComputedStructureEntry: """ Retrieve a ComputedStructureEntry for this TaskDoc. Returns ------- ComputedStructureEntry The TaskDoc.entry with corresponding TaskDoc.structure added. """ return ComputedStructureEntry( structure=self.structure, energy=self.entry.energy, correction=self.entry.correction, composition=self.entry.composition, energy_adjustments=self.entry.energy_adjustments, parameters=self.entry.parameters, data=self.entry.data, entry_id=self.entry.entry_id, ) class TrajectoryDoc(BaseModel): """Model for task trajectory data.""" task_id: Optional[str] = Field( None, description="The (task) ID of this calculation, used as a universal reference across property documents." "This comes in the form: mp-******.", ) trajectories: Optional[List[Trajectory]] = Field( None, description="Trajectory data for calculations associated with a task doc.", ) class EntryDoc(BaseModel): """Model for task entry data.""" task_id: Optional[str] = Field( None, description="The (task) ID of this calculation, used as a universal reference across property documents." "This comes in the form: mp-******.", ) entry: Optional[ComputedStructureEntry] = Field( None, description="Computed structure entry for the calculation associated with the task doc.", ) class DeprecationDoc(BaseModel): """Model for task deprecation data.""" task_id: Optional[str] = Field( None, description="The (task) ID of this calculation, used as a universal reference across property documents." "This comes in the form: mp-******.", ) deprecated: Optional[bool] = Field( None, description="Whether the ID corresponds to a deprecated calculation.", ) deprecation_reason: Optional[str] = Field( None, description="Reason for deprecation.", ) def get_uri(dir_name: Union[str, Path]) -> str: """ Return the URI path for a directory. This allows files hosted on different file servers to have distinct locations. Parameters ---------- dir_name : str or Path A directory name. Returns ------- str Full URI path, e.g., "fileserver.host.com:/full/path/of/dir_name". """ import socket fullpath = Path(dir_name).absolute() hostname = socket.gethostname() try: hostname = socket.gethostbyaddr(hostname)[0] except (socket.gaierror, socket.herror): pass return f"{hostname}:{fullpath}" def _parse_transformations( dir_name: Path, ) -> Tuple[Dict, Optional[int], Optional[List[str]], Optional[str]]: """Parse transformations.json file.""" transformations = {} filenames = tuple(dir_name.glob("transformations.json*")) icsd_id = None if len(filenames) >= 1: transformations = loadfn(filenames[0], cls=None) try: match = re.match(r"(\d+)-ICSD", transformations["history"][0]["source"]) if match: icsd_id = int(match.group(1)) except (KeyError, IndexError): pass # We don't want to leave tags or authors in the # transformations file because they'd be copied into # every structure generated after this one. other_parameters = transformations.get("other_parameters", {}) new_tags = other_parameters.pop("tags", None) new_author = other_parameters.pop("author", None) if "other_parameters" in transformations and not other_parameters: # if dict is now empty remove it transformations.pop("other_parameters") return transformations, icsd_id, new_tags, new_author def _parse_custodian(dir_name: Path) -> Optional[Dict]: """ Parse custodian.json file. Calculations done using custodian have a custodian.json file which tracks the makers performed and any errors detected and fixed. Parameters ---------- dir_name Path to calculation directory. Returns ------- Optional[dict] The information parsed from custodian.json file. """ filenames = tuple(dir_name.glob("custodian.json*")) if len(filenames) >= 1: return loadfn(filenames[0], cls=None) return None def _parse_orig_inputs( dir_name: Path, ) -> Dict[str, Union[Kpoints, Poscar, PotcarSpec, Incar]]: """ Parse original input files. Calculations using custodian generate a *.orig file for the inputs. This is useful to know how the calculation originally started. Parameters ---------- dir_name Path to calculation directory. Returns ------- Dict[str, Union[Kpints, Poscar, PotcarSpec, Incar]] The original POSCAR, KPOINTS, POTCAR, and INCAR data. """ orig_inputs = {} input_mapping = { "INCAR": Incar, "KPOINTS": Kpoints, "POTCAR": VaspPotcar, "POSCAR": Poscar, } for filename in dir_name.glob("*.orig*"): for name, vasp_input in input_mapping.items(): if f"{name}.orig" in str(filename): if name == "POTCAR": # can't serialize POTCAR orig_inputs[name.lower()] = PotcarSpec.from_potcar( vasp_input.from_file(filename) ) else: orig_inputs[name.lower()] = vasp_input.from_file(filename) return orig_inputs def _parse_additional_json(dir_name: Path) -> Dict[str, Any]: """Parse additional json files in the directory.""" additional_json = {} for filename in dir_name.glob("*.json*"): key = filename.name.split(".")[0] # ignore FW.json(.gz) so jobflow doesn't try to parse prev_vasp_dir OutputReferences # was causing atomate2 MP workflows to fail with ValueError: Could not resolve reference # 7f5a7f14-464c-4a5b-85f9-8d11b595be3b not in store or cache # contact @janosh in case of questions if key not in ("custodian", "transformations", "FW"): additional_json[key] = loadfn(filename, cls=None) return additional_json def _get_max_force(calc_doc: Calculation) -> Optional[float]: """Get max force acting on atoms from a calculation document.""" if calc_doc.output.ionic_steps: forces: Optional[Union[np.ndarray, List]] = calc_doc.output.ionic_steps[ -1 ].forces structure = calc_doc.output.structure if forces: forces = np.array(forces) sdyn = structure.site_properties.get("selective_dynamics") if sdyn: forces[np.logical_not(sdyn)] = 0 return max(np.linalg.norm(forces, axis=1)) return None def _get_drift_warnings(calc_doc: Calculation) -> List[str]: """Get warnings of whether the drift on atoms is too large.""" warnings = [] if calc_doc.input.parameters.get("NSW", 0) > 0: drift = calc_doc.output.outcar.get("drift", [[0, 0, 0]]) max_drift = max(np.linalg.norm(d) for d in drift) ediffg = calc_doc.input.parameters.get("EDIFFG", None) max_force = -float(ediffg) if ediffg and float(ediffg) < 0 else np.inf if max_drift > max_force: warnings.append( f"Drift ({drift}) > desired force convergence ({max_force}), structure " "likely not converged to desired accuracy." ) return warnings def _get_state(calcs_reversed: List[Calculation], analysis: AnalysisDoc) -> TaskState: """Get state from calculation documents and relaxation analysis.""" all_calcs_completed = all( c.has_vasp_completed == TaskState.SUCCESS for c in calcs_reversed ) if len(analysis.errors) == 0 and all_calcs_completed: return TaskState.SUCCESS # type: ignore return TaskState.FAILED # type: ignore def _get_run_stats(calcs_reversed: List[Calculation]) -> Dict[str, RunStatistics]: """Get summary of runtime statistics for each calculation in this task.""" run_stats = {} total = dict( average_memory=0.0, max_memory=0.0, elapsed_time=0.0, system_time=0.0, user_time=0.0, total_time=0.0, cores=0, ) for calc_doc in calcs_reversed: stats = calc_doc.output.run_stats run_stats[calc_doc.task_name] = stats total["average_memory"] = max(total["average_memory"], stats.average_memory) total["max_memory"] = max(total["max_memory"], stats.max_memory) total["cores"] = max(total["cores"], stats.cores) total["elapsed_time"] += stats.elapsed_time total["system_time"] += stats.system_time total["user_time"] += stats.user_time total["total_time"] += stats.total_time run_stats["overall"] = RunStatistics(**total) return run_stats def _find_vasp_files( path: Union[str, Path], volumetric_files: Tuple[str, ...] = _VOLUMETRIC_FILES, task_names: Optional[list[str]] = None, ) -> Dict[str, Any]: """ Find VASP files in a directory. Only files in folders with names matching a task name (or alternatively files with the task name as an extension, e.g., vasprun.relax1.xml) will be returned. VASP files in the current directory will be given the task name "standard". Parameters ---------- path Path to a directory to search. volumetric_files Volumetric files to search for. Returns ------- dict[str, Any] The filenames of the calculation outputs for each VASP task, given as a ordered dictionary of:: { task_name: { "vasprun_file": vasprun_filename, "outcar_file": outcar_filename, "contcar_file": contcar_filename, "volumetric_files": [CHGCAR, LOCPOT, etc] "elph_poscars": [POSCAR.T=300, POSCAR.T=400, etc] }, ... } """ task_names = ["precondition"] + [f"relax{i}" for i in range(9)] path = Path(path) task_files = OrderedDict() def _get_task_files(files, suffix=""): vasp_files = {} vol_files = [] elph_poscars = [] for file in files: file_no_path = file.relative_to(path) if file.match(f"*vasprun.xml{suffix}*"): vasp_files["vasprun_file"] = file_no_path elif file.match(f"*OUTCAR{suffix}*"): vasp_files["outcar_file"] = file_no_path elif file.match(f"*CONTCAR{suffix}*"): vasp_files["contcar_file"] = file_no_path elif any(file.match(f"*{f}{suffix}*") for f in volumetric_files): vol_files.append(file_no_path) elif file.match(f"*POSCAR.T=*{suffix}*"): elph_poscars.append(file_no_path) elif file.match(f"*OSZICAR{suffix}*"): vasp_files["oszicar_file"] = file_no_path if len(vol_files) > 0: # add volumetric files if some were found or other vasp files were found vasp_files["volumetric_files"] = vol_files if len(elph_poscars) > 0: # add elph displaced poscars if they were found or other vasp files found vasp_files["elph_poscars"] = elph_poscars return vasp_files for task_name in task_names: subfolder_match = list(path.glob(f"{task_name}/*")) suffix_match = list(path.glob(f"*.{task_name}*")) if len(subfolder_match) > 0: # subfolder match task_files[task_name] = _get_task_files(subfolder_match) elif len(suffix_match) > 0: # try extension schema task_files[task_name] = _get_task_files( suffix_match, suffix=f".{task_name}" ) if len(task_files) == 0: # get any matching file from the root folder standard_files = _get_task_files(list(path.glob("*"))) if len(standard_files) > 0: task_files["standard"] = standard_files return task_files ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/thermo.py0000644000175100001770000002677314673360562017211 0ustar00runnerdocker""" Core definition of a Thermo Document """ from collections import defaultdict from datetime import datetime from typing import Dict, List, Optional, Union from pydantic import BaseModel, Field from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.base import EmmetMeta from emmet.core.material import PropertyOrigin from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID from emmet.core.utils import ValueEnum from emmet.core.vasp.calc_types.enums import RunType class DecompositionProduct(BaseModel): """ Entry metadata for a decomposition process """ material_id: Optional[MPID] = Field( None, description="The Materials Project ID for the material this decomposition points to.", ) formula: Optional[str] = Field( None, description="The formula of the decomposed material this material decomposes to.", ) amount: Optional[float] = Field( None, description="The amount of the decomposed material by formula units this this material decomposes to.", ) class ThermoType(ValueEnum): GGA_GGA_U = "GGA_GGA+U" GGA_GGA_U_R2SCAN = "GGA_GGA+U_R2SCAN" R2SCAN = "R2SCAN" UNKNOWN = "UNKNOWN" class ThermoDoc(PropertyDoc): """ A thermo entry document """ property_name: str = "thermo" thermo_type: Union[ThermoType, RunType] = Field( ..., description="Functional types of calculations involved in the energy mixing scheme.", ) thermo_id: str = Field( ..., description="Unique document ID which is composed of the Material ID and thermo data type.", ) uncorrected_energy_per_atom: float = Field( ..., description="The total DFT energy of this material per atom in eV/atom." ) energy_per_atom: float = Field( ..., description="The total corrected DFT energy of this material per atom in eV/atom.", ) energy_uncertainy_per_atom: Optional[float] = Field(None, description="") formation_energy_per_atom: Optional[float] = Field( None, description="The formation energy per atom in eV/atom." ) energy_above_hull: float = Field( ..., description="The energy above the hull in eV/Atom." ) is_stable: bool = Field( False, description="Flag for whether this material is on the hull and therefore stable.", ) equilibrium_reaction_energy_per_atom: Optional[float] = Field( None, description="The reaction energy of a stable entry from the neighboring equilibrium stable materials in eV." " Also known as the inverse distance to hull.", ) decomposes_to: Optional[List[DecompositionProduct]] = Field( None, description="List of decomposition data for this material. Only valid for metastable or unstable material.", ) decomposition_enthalpy: Optional[float] = Field( None, description="Decomposition enthalpy as defined by `get_decomp_and_phase_separation_energy` in pymatgen.", ) decomposition_enthalpy_decomposes_to: Optional[List[DecompositionProduct]] = Field( None, description="List of decomposition data associated with the decomposition_enthalpy quantity.", ) energy_type: str = Field( ..., description="The type of calculation this energy evaluation comes from.", ) entry_types: List[str] = Field( description="List of available energy types computed for this material." ) entries: Dict[str, Union[ComputedEntry, ComputedStructureEntry]] = Field( ..., description="List of all entries that are valid for this material." " The keys for this dictionary are names of various calculation types.", ) @classmethod def from_entries( cls, entries: List[Union[ComputedEntry, ComputedStructureEntry]], thermo_type: Union[ThermoType, RunType], phase_diagram: Optional[PhaseDiagram] = None, use_max_chemsys: bool = False, **kwargs ): """Produce a list of ThermoDocs from a list of Entry objects Args: entries (List[Union[ComputedEntry, ComputedStructureEntry]]): List of Entry objects thermo_type (Union[ThermoType, RunType]): Thermo type phase_diagram (Optional[PhaseDiagram], optional): Already built phase diagram. Defaults to None. use_max_chemsys (bool, optional): Whether to only produce thermo docs for materials that match the largest chemsys represented in the list. Defaults to False. Returns: List[ThermoDoc]: List of built thermo doc objects. """ pd = phase_diagram or cls.construct_phase_diagram(entries) chemsys = "-".join(sorted([str(e) for e in pd.elements])) docs = [] entries_by_mpid = defaultdict(list) for e in entries: entries_by_mpid[e.data["material_id"]].append(e) entry_quality_scores = {"GGA": 1, "GGA+U": 2, "SCAN": 3, "R2SCAN": 4} def _energy_eval(entry: Union[ComputedStructureEntry, ComputedEntry]): """ Helper function to order entries for thermo energy data selection - Run type - LASPH - Energy """ return ( -1 * entry_quality_scores.get(entry.data["run_type"], 0), -1 * int(entry.data.get("aspherical", False)), entry.energy, ) for material_id, entry_group in entries_by_mpid.items(): if ( use_max_chemsys and entry_group[0].composition.chemical_system != chemsys ): continue sorted_entries = sorted(entry_group, key=_energy_eval) blessed_entry = sorted_entries[0] (decomp, ehull) = pd.get_decomp_and_e_above_hull(blessed_entry) # type: ignore[arg-type] builder_meta = EmmetMeta(license=blessed_entry.data.get("license")) d = { "thermo_id": "{}_{}".format(material_id, str(thermo_type)), "material_id": material_id, "thermo_type": thermo_type, "uncorrected_energy_per_atom": blessed_entry.uncorrected_energy / blessed_entry.composition.num_atoms, "energy_per_atom": blessed_entry.energy / blessed_entry.composition.num_atoms, "formation_energy_per_atom": pd.get_form_energy_per_atom(blessed_entry), # type: ignore[arg-type] "energy_above_hull": ehull, "is_stable": blessed_entry in pd.stable_entries, "builder_meta": builder_meta.model_dump(), } # Uncomment to make last_updated line up with materials. # if "last_updated" in blessed_entry.data: # d["last_updated"] = blessed_entry.data["last_updated"] # Store different info if stable vs decomposes if d["is_stable"]: d[ "equilibrium_reaction_energy_per_atom" ] = pd.get_equilibrium_reaction_energy( blessed_entry # type: ignore[arg-type] ) else: d["decomposes_to"] = [ { "material_id": de.data["material_id"], # type: ignore[union-attr] "formula": de.composition.formula, "amount": amt, } for de, amt in decomp.items() # type: ignore[union-attr] ] try: decomp, energy = pd.get_decomp_and_phase_separation_energy( blessed_entry # type: ignore[arg-type] ) d["decomposition_enthalpy"] = energy d["decomposition_enthalpy_decomposes_to"] = [ { "material_id": de.data["material_id"], # type: ignore[union-attr] "formula": de.composition.formula, "amount": amt, } for de, amt in decomp.items() # type: ignore[union-attr] ] except ValueError: # try/except so this quantity does not take down the builder if it fails: # it includes an optimization step that can be fragile in some instances, # most likely failure is ValueError, "invalid value encountered in true_divide" d["warnings"] = [ "Could not calculate decomposition enthalpy for this entry." ] d["energy_type"] = blessed_entry.parameters.get("run_type", "Unknown") d["entry_types"] = [] d["entries"] = {} # Currently, each entry group contains a single entry due to how the compatibility scheme works for entry in entry_group: d["entry_types"].append(entry.parameters.get("run_type", "Unknown")) d["entries"][entry.parameters.get("run_type", "Unknown")] = entry d["origins"] = [ PropertyOrigin( name="energy", task_id=blessed_entry.data["task_id"], last_updated=d.get("last_updated", datetime.utcnow()), ) ] docs.append( ThermoDoc.from_structure( meta_structure=blessed_entry.structure, **d, **kwargs # type: ignore[attr-defined] ) ) return docs @staticmethod def construct_phase_diagram(entries) -> PhaseDiagram: """ Efficienty construct a phase diagram using only the lowest entries at every composition represented in the entry data passed. Args: entries (List[ComputedStructureEntry]): List of corrected pymatgen entry objects. Returns: PhaseDiagram: Pymatgen PhaseDiagram object """ entries_by_comp = defaultdict(list) for e in entries: entries_by_comp[e.composition.reduced_formula].append(e) # Only use lowest entry per composition to speed up QHull in Phase Diagram reduced_entries = [ sorted(comp_entries, key=lambda e: e.energy_per_atom)[0] for comp_entries in entries_by_comp.values() ] pd = PhaseDiagram(reduced_entries) # Add back all entries, not just those on the hull pd_computed_data = pd.computed_data pd_computed_data["all_entries"] = entries new_pd = PhaseDiagram( entries, elements=pd.elements, computed_data=pd_computed_data ) return new_pd class PhaseDiagramDoc(BaseModel): """ A phase diagram document """ property_name: str = "phase_diagram" phase_diagram_id: str = Field( ..., description="Phase diagram ID consisting of the chemical system and thermo type", ) chemsys: str = Field( ..., description="Dash-delimited string of elements in the material", ) thermo_type: Union[ThermoType, RunType] = Field( ..., description="Functional types of calculations involved in the energy mixing scheme.", ) phase_diagram: PhaseDiagram = Field( ..., description="Phase diagram for the chemical system.", ) last_updated: datetime = Field( description="Timestamp for the most recent calculation update for this property", default_factory=datetime.utcnow, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/utils.py0000644000175100001770000003460414673360562017043 0ustar00runnerdockerimport copy import datetime from enum import Enum from itertools import groupby from typing import Any, Dict, Iterator, List, Optional, Union import numpy as np from monty.json import MSONable from pydantic import BaseModel from pymatgen.analysis.elasticity.strain import Deformation from pymatgen.analysis.graphs import MoleculeGraph from pymatgen.analysis.local_env import OpenBabelNN, metal_edge_extender from pymatgen.analysis.molecule_matcher import MoleculeMatcher from pymatgen.analysis.structure_matcher import ( AbstractComparator, ElementComparator, StructureMatcher, ) from pymatgen.core.structure import Molecule, Structure from pymatgen.transformations.standard_transformations import ( DeformStructureTransformation, ) from pymatgen.util.graph_hashing import weisfeiler_lehman_graph_hash from emmet.core.mpid import MPculeID from emmet.core.settings import EmmetSettings try: import bson except ImportError: bson = None # type: ignore SETTINGS = EmmetSettings() def get_sg(struc, symprec=SETTINGS.SYMPREC) -> int: """helper function to get spacegroup with a loose tolerance""" try: return struc.get_space_group_info(symprec=symprec)[1] except Exception: return -1 def group_structures( structures: List[Structure], ltol: float = SETTINGS.LTOL, stol: float = SETTINGS.STOL, angle_tol: float = SETTINGS.ANGLE_TOL, symprec: float = SETTINGS.SYMPREC, comparator: AbstractComparator = ElementComparator(), ) -> Iterator[List[Structure]]: """ Groups structures according to space group and structure matching Args: structures ([Structure]): list of structures to group ltol (float): StructureMatcher tuning parameter for matching tasks to materials stol (float): StructureMatcher tuning parameter for matching tasks to materials angle_tol (float): StructureMatcher tuning parameter for matching tasks to materials symprec (float): symmetry tolerance for space group finding """ sm = StructureMatcher( ltol=ltol, stol=stol, angle_tol=angle_tol, primitive_cell=True, scale=True, attempt_supercell=False, allow_subset=False, comparator=comparator, ) def _get_sg(struc): return get_sg(struc, symprec=symprec) # First group by spacegroup number then by structure matching for _, pregroup in groupby(sorted(structures, key=_get_sg), key=_get_sg): for group in sm.group_structures(list(pregroup)): yield group def undeform_structure(structure: Structure, transformations: Dict) -> Structure: """ Get an undeformed structure by applying transformations in a reverse order. Args: structure: deformed structure transformation: transformation that deforms the structure Returns: undeformed structure """ for transformation in reversed(transformations.get("history", [])): if transformation["@class"] == "DeformStructureTransformation": deform = Deformation(transformation["deformation"]) dst = DeformStructureTransformation(deform.inv) structure = dst.apply_transformation(structure) else: raise RuntimeError( "Expect transformation to be `DeformStructureTransformation`; " f"got {transformation['@class']}" ) return structure def generate_robocrys_condensed_struct_and_description( structure: Structure, mineral_matcher=None, symprecs: list[float] = [0.01, 0.1, 1.0e-3], ) -> tuple[dict[str, Any], str]: """ Get robocrystallographer description of a structure. Input ------ structure : pymatgen .Structure mineral_matcher : optional robocrys MineralMatcher object Slightly reduces load time by storing mineral data in memory, rather than reloading for each structure. symprecs : list[float] A list of symprec values to try for symmetry identification. The first value is the default used by robocrys, then the default used by emmet (looser), then a tighter symprec. Output ------- A robocrys condensed structure and description. """ try: from robocrys import StructureCondenser, StructureDescriber except ImportError: raise ImportError( "robocrys needs to be installed to generate Robocrystallographer descriptions" ) for isymprec, symprec in enumerate(symprecs): # occasionally, symmetry detection fails - give a few chances to modify symprec try: condenser = StructureCondenser( mineral_matcher=mineral_matcher, symprec=symprec ) condensed_structure = condenser.condense_structure(structure) break except ValueError as exc: if isymprec == len(symprecs) - 1: raise exc for desc_fmt in ["unicode", "html", "raw"]: try: describer = StructureDescriber( describe_symmetry_labels=False, fmt=desc_fmt, return_parts=False ) description = describer.describe(condensed_structure) break except ValueError as exc: # pymatgen won't convert a "subscript period" character to unicode # in these cases, the description is still generated but unicode # parsing failed - use html instead if "subscript period" not in str(exc): raise exc return condensed_structure, description def group_molecules(molecules: List[Molecule]): """ Groups molecules according to composition, charge, and equality Note: this function is (currently) only used in the MoleculesAssociationBuilder. At that stage, we want to link calculations that are performed on identical structures. Collapsing similar structures on the basis of e.g. graph isomorphism happens at a later stage. Args: molecules (List[Molecule]) """ def _mol_form(mol_solv): return mol_solv.composition.alphabetical_formula # Extremely tight tolerance is desirable # We want to match only calculations that are EXACTLY the same # Molecules with slight differences in bonding (which might be caused by, for instance, # different solvent environments) # This tolerance was chosen based on trying to distinguish CO optimized in # two different solvents mm = MoleculeMatcher(tolerance=0.000001) # First, group by formula # Hopefully this step is unnecessary - builders should already be doing this for mol_key, pregroup in groupby(sorted(molecules, key=_mol_form), key=_mol_form): groups: List[Dict[str, Any]] = list() for mol in pregroup: mol_copy = copy.deepcopy(mol) # Single atoms could always have identical structure # So grouping by geometry isn't enough # Need to also group by charge if len(mol_copy) > 1: mol_copy.set_charge_and_spin(0) matched = False # Group by structure for group in groups: if ( (mm.fit(mol_copy, group["mol"]) or mol_copy == group["mol"]) and mol_copy.charge == group["mol"].charge and mol_copy.spin_multiplicity == group["mol"].spin_multiplicity ): group["mol_list"].append(mol) matched = True break if not matched: groups.append({"mol": mol_copy, "mol_list": [mol]}) for group in groups: yield group["mol_list"] def confirm_molecule(mol: Union[Molecule, Dict]): """ Check that something that we expect to be a molecule is actually a Molecule object, and not a dictionary representation. :param mol (Molecule): :return: """ if isinstance(mol, Dict): return Molecule.from_dict(mol) else: return mol def make_mol_graph( mol: Molecule, critic_bonds: Optional[List[List[int]]] = None ) -> MoleculeGraph: """ Construct a MoleculeGraph using OpenBabelNN with metal_edge_extender and (optionally) Critic2 bonding information. This bonding scheme was used to define bonding for the Lithium-Ion Battery Electrolyte (LIBE) dataset (DOI: 10.1038/s41597-021-00986-9) :param mol: Molecule to be converted to MoleculeGraph :param critic_bonds: (optional) List of lists [a, b], where a and b are atom indices (0-indexed) :return: mol_graph, a MoleculeGraph """ mol_graph = MoleculeGraph.with_local_env_strategy(mol, OpenBabelNN()) mol_graph = metal_edge_extender(mol_graph) if critic_bonds: mg_edges = mol_graph.graph.edges() for bond in critic_bonds: bond.sort() if bond[0] != bond[1]: bond_tup = (bond[0], bond[1]) if bond_tup not in mg_edges: mol_graph.add_edge(bond_tup[0], bond_tup[1]) return mol_graph def get_graph_hash(mol: Molecule, node_attr: Optional[str] = None): """ Return the Weisfeiler Lehman (WL) graph hash of the MoleculeGraph described by this molecule, using the OpenBabelNN strategy with extension for metal coordinate bonds :param mol: Molecule :param node_attr: Node attribute to be used to compute the WL hash :return: string of the WL graph hash """ mg = make_mol_graph(mol) return weisfeiler_lehman_graph_hash( mg.graph.to_undirected(), node_attr=node_attr, ) def get_molecule_id(mol: Molecule, node_attr: Optional[str] = None): """ Return an MPculeID for a molecule, with the hash component based on a particular attribute of the molecule graph representation. :param mol: Molecule :param node_attr:Node attribute to be used to compute the WL hash :return: MPculeID """ graph_hash = get_graph_hash(mol, node_attr=node_attr) return MPculeID( "{}-{}-{}-{}".format( graph_hash, mol.composition.alphabetical_formula.replace(" ", ""), str(int(mol.charge)).replace("-", "m"), str(mol.spin_multiplicity), ) ) def jsanitize(obj, strict=False, allow_bson=False): """ This method cleans an input json-like object, either a list or a dict or some sequence, nested or otherwise, by converting all non-string dictionary keys (such as int and float) to strings, and also recursively encodes all objects using Monty's as_dict() protocol. Args: obj: input json-like object. strict (bool): This parameters sets the behavior when jsanitize encounters an object it does not understand. If strict is True, jsanitize will try to get the as_dict() attribute of the object. If no such attribute is found, an attribute error will be thrown. If strict is False, jsanitize will simply call str(object) to convert the object to a string representation. allow_bson (bool): This parameters sets the behavior when jsanitize encounters an bson supported type such as objectid and datetime. If True, such bson types will be ignored, allowing for proper insertion into MongoDb databases. Returns: Sanitized dict that can be json serialized. """ if allow_bson and ( isinstance(obj, (datetime.datetime, bytes)) or (bson is not None and isinstance(obj, bson.objectid.ObjectId)) ): return obj if isinstance(obj, (list, tuple, set)): return [jsanitize(i, strict=strict, allow_bson=allow_bson) for i in obj] if np is not None and isinstance(obj, np.ndarray): return [ jsanitize(i, strict=strict, allow_bson=allow_bson) for i in obj.tolist() ] if isinstance(obj, Enum): return obj.value if isinstance(obj, dict): return { k.__str__(): jsanitize(v, strict=strict, allow_bson=allow_bson) for k, v in obj.items() } if isinstance(obj, MSONable): return { k.__str__(): jsanitize(v, strict=strict, allow_bson=allow_bson) for k, v in obj.as_dict().items() } if isinstance(obj, BaseModel): return { k.__str__(): jsanitize(v, strict=strict, allow_bson=allow_bson) for k, v in obj.model_dump().items() } if isinstance(obj, (int, float)): if np.isnan(obj): return 0 return obj if obj is None: return None if not strict: return obj.__str__() if isinstance(obj, str): return obj.__str__() return jsanitize(obj.as_dict(), strict=strict, allow_bson=allow_bson) class ValueEnum(Enum): """ Enum that serializes to string as the value. While this method has an `as_dict` method, this returns a `str`. This is to ensure deserialization to a `str` when functions like `monty.json.jsanitize` are called on a ValueEnum with `strict = True` and `enum_values = False` (occurs often in jobflow). """ def __str__(self): return str(self.value) def __eq__(self, obj: object) -> bool: """Special Equals to enable converting strings back to the enum""" if isinstance(obj, str): return super().__eq__(self.__class__(obj)) elif isinstance(obj, self.__class__): return super().__eq__(obj) return False def __hash__(self): """Get a hash of the enum.""" return hash(str(self)) class DocEnum(ValueEnum): """ Enum with docstrings support from: https://stackoverflow.com/a/50473952 """ def __new__(cls, value, doc=None): """add docstring to the member of Enum if exists Args: value: Enum member value doc: Enum member docstring, None if not exists """ self = object.__new__(cls) # calling super().__new__(value) here would fail self._value_ = value if doc is not None: self.__doc__ = doc return self class IgnoreCaseEnum(ValueEnum): """Enum that permits case-insensitve lookup. Reference issue: https://github.com/materialsproject/api/issues/869 """ @classmethod def _missing_(cls, value): for member in cls: if member.value.upper() == value.upper(): return member def utcnow() -> datetime.datetime: """Get UTC time right now.""" return datetime.datetime.now(datetime.timezone.utc) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0522902 emmet-core-0.84.2/emmet/core/vasp/0000755000175100001770000000000014673360566016277 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/__init__.py0000644000175100001770000000000014673360562020372 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0522902 emmet-core-0.84.2/emmet/core/vasp/calc_types/0000755000175100001770000000000014673360566020425 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/calc_types/__init__.py0000644000175100001770000000030414673360562022527 0ustar00runnerdocker"""Module defining VASP calculation types.""" from emmet.core.vasp.calc_types.enums import CalcType, RunType, TaskType from emmet.core.vasp.calc_types.utils import calc_type, run_type, task_type ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/calc_types/calc_types.yaml0000644000175100001770000000460014673360562023433 0ustar00runnerdockerRUN_TYPES: LDA: # Note that GGA = CA is the same as GGA = PZ for VASP LDA: GGA: CA GGA: AM05: GGA: AM GGA: GGA: -- PBE: GGA: PE PBEsol: GGA: PS revPBE+PADE: GGA: RP optB86b: GGA: MK optB88: GGA: BO optPBE: GGA: OR revPBE: GGA: RE HF: B3LYP: AEXX: 0.2 AGGAC: 0.81 AGGAX: 0.72 ALDAC: 0.19 GGA: B3 LHFCALC: true HF: AEXX: 1.0 AGGAC: 0.0 AGGAX: 1.0 ALDAC: 0.0 LHFCALC: true HSE03: AEXX: 0.25 AGGAC: 1.0 AGGAX: 0.75 ALDAC: 1.0 HFSCREEN: 0.3 LHFCALC: true HSE06: AEXX: 0.25 AGGAC: 1.0 AGGAX: 0.75 ALDAC: 1.0 HFSCREEN: 0.2 LHFCALC: true PBE0: AEXX: 0.25 AGGAC: 1.0 AGGAX: 0.75 ALDAC: 1.0 LHFCALC: true # From the VASP manual, the default for setting LHFCALC = True is PBE0 # HFCus is the same as PBE0 HFCus: LHFCALC: true METAGGA: M06L: METAGGA: M06L MBJL: METAGGA: MBJL MS0: METAGGA: MS0 MS1: METAGGA: MS1 MS2: METAGGA: MS2 RTPSS: METAGGA: RTPSS SCAN: METAGGA: SCAN r2SCAN: METAGGA: R2SCAN TPSS: METAGGA: TPSS VDW: r2SCAN-rVV10: BPARAM: 15.7 LASPH: true LUSE_VDW: true METAGGA: R2SCAN SCAN-rVV10: BPARAM: 15.7 LASPH: true LUSE_VDW: true METAGGA: SCAN optB86b-vdW: AGGAC: 0.0 GGA: MK LASPH: true LUSE_VDW: true PARAM1: 0.1234 PARAM2: 1.0 optB88-vdW: AGGAC: 0.0 GGA: BO LUSE_VDW: true PARAM1: 0.1833333333 PARAM2: 0.22 optPBE-vdW: AGGAC: 0.0 GGA: OR LASPH: true LUSE_VDW: true rev-vdW-DF2: AGGAC: 0.0 GGA: MK LASPH: true LUSE_VDW: true PARAM1: 0.1234 PARAM2: 0.711357 Zab_vdW: -1.8867 revPBE-vdW: AGGAC: 0.0 GGA: RE LASPH: true LUSE_VDW: true vdW-DF2: AGGAC: 0.0 GGA: ML LASPH: true LUSE_VDW: true Zab_vdW: -1.8867 TASK_TYPES: - NSCF Line - NSCF Uniform - Dielectric - DFPT - DFPT Dielectric - NMR Nuclear Shielding - NMR Electric Field Gradient - Static - Structure Optimization - Deformation - Optic - Molecular Dynamics - Unrecognized ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/calc_types/enums.py0000644000175100001770000013512614673360562022132 0ustar00runnerdocker""" Autogenerated Enums for VASP RunType, TaskType, and CalcType. Do not edit this by hand to add or remove enums. Instead, edit dev_scripts/generate_enums.py and/or emmet/core/vasp/calc_types/calc_types.yaml """ from emmet.core.utils import ValueEnum, IgnoreCaseEnum class RunType(IgnoreCaseEnum): """VASP calculation run types.""" AM05 = "AM05" AM05_U = "AM05+U" B3LYP = "B3LYP" B3LYP_U = "B3LYP+U" GGA = "GGA" GGA_U = "GGA+U" HF = "HF" HFCus = "HFCus" HFCus_U = "HFCus+U" HF_U = "HF+U" HSE03 = "HSE03" HSE03_U = "HSE03+U" HSE06 = "HSE06" HSE06_U = "HSE06+U" LDA = "LDA" LDA_U = "LDA+U" M06L = "M06L" M06L_U = "M06L+U" MBJL = "MBJL" MBJL_U = "MBJL+U" MS0 = "MS0" MS0_U = "MS0+U" MS1 = "MS1" MS1_U = "MS1+U" MS2 = "MS2" MS2_U = "MS2+U" PBE = "PBE" PBE0 = "PBE0" PBE0_U = "PBE0+U" PBE_U = "PBE+U" PBEsol = "PBEsol" PBEsol_U = "PBEsol+U" RTPSS = "RTPSS" RTPSS_U = "RTPSS+U" SCAN = "SCAN" SCAN_U = "SCAN+U" SCAN_rVV10 = "SCAN-rVV10" SCAN_rVV10_U = "SCAN-rVV10+U" TPSS = "TPSS" TPSS_U = "TPSS+U" optB86b = "optB86b" optB86b_U = "optB86b+U" optB86b_vdW = "optB86b-vdW" optB86b_vdW_U = "optB86b-vdW+U" optB88 = "optB88" optB88_U = "optB88+U" optB88_vdW = "optB88-vdW" optB88_vdW_U = "optB88-vdW+U" optPBE = "optPBE" optPBE_U = "optPBE+U" optPBE_vdW = "optPBE-vdW" optPBE_vdW_U = "optPBE-vdW+U" r2SCAN = "r2SCAN" r2SCAN_U = "r2SCAN+U" r2SCAN_rVV10 = "r2SCAN-rVV10" r2SCAN_rVV10_U = "r2SCAN-rVV10+U" revPBE = "revPBE" revPBE_PADE = "revPBE+PADE" revPBE_PADE_U = "revPBE+PADE+U" revPBE_U = "revPBE+U" revPBE_vdW = "revPBE-vdW" revPBE_vdW_U = "revPBE-vdW+U" rev_vdW_DF2 = "rev-vdW-DF2" rev_vdW_DF2_U = "rev-vdW-DF2+U" vdW_DF2 = "vdW-DF2" vdW_DF2_U = "vdW-DF2+U" class TaskType(ValueEnum): """VASP calculation task types.""" DFPT = "DFPT" DFPT_Dielectric = "DFPT Dielectric" Deformation = "Deformation" Dielectric = "Dielectric" Molecular_Dynamics = "Molecular Dynamics" NMR_Electric_Field_Gradient = "NMR Electric Field Gradient" NMR_Nuclear_Shielding = "NMR Nuclear Shielding" NSCF_Line = "NSCF Line" NSCF_Uniform = "NSCF Uniform" Optic = "Optic" Static = "Static" Structure_Optimization = "Structure Optimization" Unrecognized = "Unrecognized" class CalcType(IgnoreCaseEnum): """VASP calculation types.""" AM05_DFPT = "AM05 DFPT" AM05_DFPT_Dielectric = "AM05 DFPT Dielectric" AM05_Deformation = "AM05 Deformation" AM05_Dielectric = "AM05 Dielectric" AM05_Molecular_Dynamics = "AM05 Molecular Dynamics" AM05_NMR_Electric_Field_Gradient = "AM05 NMR Electric Field Gradient" AM05_NMR_Nuclear_Shielding = "AM05 NMR Nuclear Shielding" AM05_NSCF_Line = "AM05 NSCF Line" AM05_NSCF_Uniform = "AM05 NSCF Uniform" AM05_Optic = "AM05 Optic" AM05_Static = "AM05 Static" AM05_Structure_Optimization = "AM05 Structure Optimization" AM05_U_DFPT = "AM05+U DFPT" AM05_U_DFPT_Dielectric = "AM05+U DFPT Dielectric" AM05_U_Deformation = "AM05+U Deformation" AM05_U_Dielectric = "AM05+U Dielectric" AM05_U_Molecular_Dynamics = "AM05+U Molecular Dynamics" AM05_U_NMR_Electric_Field_Gradient = "AM05+U NMR Electric Field Gradient" AM05_U_NMR_Nuclear_Shielding = "AM05+U NMR Nuclear Shielding" AM05_U_NSCF_Line = "AM05+U NSCF Line" AM05_U_NSCF_Uniform = "AM05+U NSCF Uniform" AM05_U_Optic = "AM05+U Optic" AM05_U_Static = "AM05+U Static" AM05_U_Structure_Optimization = "AM05+U Structure Optimization" AM05_U_Unrecognized = "AM05+U Unrecognized" AM05_Unrecognized = "AM05 Unrecognized" B3LYP_DFPT = "B3LYP DFPT" B3LYP_DFPT_Dielectric = "B3LYP DFPT Dielectric" B3LYP_Deformation = "B3LYP Deformation" B3LYP_Dielectric = "B3LYP Dielectric" B3LYP_Molecular_Dynamics = "B3LYP Molecular Dynamics" B3LYP_NMR_Electric_Field_Gradient = "B3LYP NMR Electric Field Gradient" B3LYP_NMR_Nuclear_Shielding = "B3LYP NMR Nuclear Shielding" B3LYP_NSCF_Line = "B3LYP NSCF Line" B3LYP_NSCF_Uniform = "B3LYP NSCF Uniform" B3LYP_Optic = "B3LYP Optic" B3LYP_Static = "B3LYP Static" B3LYP_Structure_Optimization = "B3LYP Structure Optimization" B3LYP_U_DFPT = "B3LYP+U DFPT" B3LYP_U_DFPT_Dielectric = "B3LYP+U DFPT Dielectric" B3LYP_U_Deformation = "B3LYP+U Deformation" B3LYP_U_Dielectric = "B3LYP+U Dielectric" B3LYP_U_Molecular_Dynamics = "B3LYP+U Molecular Dynamics" B3LYP_U_NMR_Electric_Field_Gradient = "B3LYP+U NMR Electric Field Gradient" B3LYP_U_NMR_Nuclear_Shielding = "B3LYP+U NMR Nuclear Shielding" B3LYP_U_NSCF_Line = "B3LYP+U NSCF Line" B3LYP_U_NSCF_Uniform = "B3LYP+U NSCF Uniform" B3LYP_U_Optic = "B3LYP+U Optic" B3LYP_U_Static = "B3LYP+U Static" B3LYP_U_Structure_Optimization = "B3LYP+U Structure Optimization" B3LYP_U_Unrecognized = "B3LYP+U Unrecognized" B3LYP_Unrecognized = "B3LYP Unrecognized" GGA_DFPT = "GGA DFPT" GGA_DFPT_Dielectric = "GGA DFPT Dielectric" GGA_Deformation = "GGA Deformation" GGA_Dielectric = "GGA Dielectric" GGA_Molecular_Dynamics = "GGA Molecular Dynamics" GGA_NMR_Electric_Field_Gradient = "GGA NMR Electric Field Gradient" GGA_NMR_Nuclear_Shielding = "GGA NMR Nuclear Shielding" GGA_NSCF_Line = "GGA NSCF Line" GGA_NSCF_Uniform = "GGA NSCF Uniform" GGA_Optic = "GGA Optic" GGA_Static = "GGA Static" GGA_Structure_Optimization = "GGA Structure Optimization" GGA_U_DFPT = "GGA+U DFPT" GGA_U_DFPT_Dielectric = "GGA+U DFPT Dielectric" GGA_U_Deformation = "GGA+U Deformation" GGA_U_Dielectric = "GGA+U Dielectric" GGA_U_Molecular_Dynamics = "GGA+U Molecular Dynamics" GGA_U_NMR_Electric_Field_Gradient = "GGA+U NMR Electric Field Gradient" GGA_U_NMR_Nuclear_Shielding = "GGA+U NMR Nuclear Shielding" GGA_U_NSCF_Line = "GGA+U NSCF Line" GGA_U_NSCF_Uniform = "GGA+U NSCF Uniform" GGA_U_Optic = "GGA+U Optic" GGA_U_Static = "GGA+U Static" GGA_U_Structure_Optimization = "GGA+U Structure Optimization" GGA_U_Unrecognized = "GGA+U Unrecognized" GGA_Unrecognized = "GGA Unrecognized" HFCus_DFPT = "HFCus DFPT" HFCus_DFPT_Dielectric = "HFCus DFPT Dielectric" HFCus_Deformation = "HFCus Deformation" HFCus_Dielectric = "HFCus Dielectric" HFCus_Molecular_Dynamics = "HFCus Molecular Dynamics" HFCus_NMR_Electric_Field_Gradient = "HFCus NMR Electric Field Gradient" HFCus_NMR_Nuclear_Shielding = "HFCus NMR Nuclear Shielding" HFCus_NSCF_Line = "HFCus NSCF Line" HFCus_NSCF_Uniform = "HFCus NSCF Uniform" HFCus_Optic = "HFCus Optic" HFCus_Static = "HFCus Static" HFCus_Structure_Optimization = "HFCus Structure Optimization" HFCus_U_DFPT = "HFCus+U DFPT" HFCus_U_DFPT_Dielectric = "HFCus+U DFPT Dielectric" HFCus_U_Deformation = "HFCus+U Deformation" HFCus_U_Dielectric = "HFCus+U Dielectric" HFCus_U_Molecular_Dynamics = "HFCus+U Molecular Dynamics" HFCus_U_NMR_Electric_Field_Gradient = "HFCus+U NMR Electric Field Gradient" HFCus_U_NMR_Nuclear_Shielding = "HFCus+U NMR Nuclear Shielding" HFCus_U_NSCF_Line = "HFCus+U NSCF Line" HFCus_U_NSCF_Uniform = "HFCus+U NSCF Uniform" HFCus_U_Optic = "HFCus+U Optic" HFCus_U_Static = "HFCus+U Static" HFCus_U_Structure_Optimization = "HFCus+U Structure Optimization" HFCus_U_Unrecognized = "HFCus+U Unrecognized" HFCus_Unrecognized = "HFCus Unrecognized" HF_DFPT = "HF DFPT" HF_DFPT_Dielectric = "HF DFPT Dielectric" HF_Deformation = "HF Deformation" HF_Dielectric = "HF Dielectric" HF_Molecular_Dynamics = "HF Molecular Dynamics" HF_NMR_Electric_Field_Gradient = "HF NMR Electric Field Gradient" HF_NMR_Nuclear_Shielding = "HF NMR Nuclear Shielding" HF_NSCF_Line = "HF NSCF Line" HF_NSCF_Uniform = "HF NSCF Uniform" HF_Optic = "HF Optic" HF_Static = "HF Static" HF_Structure_Optimization = "HF Structure Optimization" HF_U_DFPT = "HF+U DFPT" HF_U_DFPT_Dielectric = "HF+U DFPT Dielectric" HF_U_Deformation = "HF+U Deformation" HF_U_Dielectric = "HF+U Dielectric" HF_U_Molecular_Dynamics = "HF+U Molecular Dynamics" HF_U_NMR_Electric_Field_Gradient = "HF+U NMR Electric Field Gradient" HF_U_NMR_Nuclear_Shielding = "HF+U NMR Nuclear Shielding" HF_U_NSCF_Line = "HF+U NSCF Line" HF_U_NSCF_Uniform = "HF+U NSCF Uniform" HF_U_Optic = "HF+U Optic" HF_U_Static = "HF+U Static" HF_U_Structure_Optimization = "HF+U Structure Optimization" HF_U_Unrecognized = "HF+U Unrecognized" HF_Unrecognized = "HF Unrecognized" HSE03_DFPT = "HSE03 DFPT" HSE03_DFPT_Dielectric = "HSE03 DFPT Dielectric" HSE03_Deformation = "HSE03 Deformation" HSE03_Dielectric = "HSE03 Dielectric" HSE03_Molecular_Dynamics = "HSE03 Molecular Dynamics" HSE03_NMR_Electric_Field_Gradient = "HSE03 NMR Electric Field Gradient" HSE03_NMR_Nuclear_Shielding = "HSE03 NMR Nuclear Shielding" HSE03_NSCF_Line = "HSE03 NSCF Line" HSE03_NSCF_Uniform = "HSE03 NSCF Uniform" HSE03_Optic = "HSE03 Optic" HSE03_Static = "HSE03 Static" HSE03_Structure_Optimization = "HSE03 Structure Optimization" HSE03_U_DFPT = "HSE03+U DFPT" HSE03_U_DFPT_Dielectric = "HSE03+U DFPT Dielectric" HSE03_U_Deformation = "HSE03+U Deformation" HSE03_U_Dielectric = "HSE03+U Dielectric" HSE03_U_Molecular_Dynamics = "HSE03+U Molecular Dynamics" HSE03_U_NMR_Electric_Field_Gradient = "HSE03+U NMR Electric Field Gradient" HSE03_U_NMR_Nuclear_Shielding = "HSE03+U NMR Nuclear Shielding" HSE03_U_NSCF_Line = "HSE03+U NSCF Line" HSE03_U_NSCF_Uniform = "HSE03+U NSCF Uniform" HSE03_U_Optic = "HSE03+U Optic" HSE03_U_Static = "HSE03+U Static" HSE03_U_Structure_Optimization = "HSE03+U Structure Optimization" HSE03_U_Unrecognized = "HSE03+U Unrecognized" HSE03_Unrecognized = "HSE03 Unrecognized" HSE06_DFPT = "HSE06 DFPT" HSE06_DFPT_Dielectric = "HSE06 DFPT Dielectric" HSE06_Deformation = "HSE06 Deformation" HSE06_Dielectric = "HSE06 Dielectric" HSE06_Molecular_Dynamics = "HSE06 Molecular Dynamics" HSE06_NMR_Electric_Field_Gradient = "HSE06 NMR Electric Field Gradient" HSE06_NMR_Nuclear_Shielding = "HSE06 NMR Nuclear Shielding" HSE06_NSCF_Line = "HSE06 NSCF Line" HSE06_NSCF_Uniform = "HSE06 NSCF Uniform" HSE06_Optic = "HSE06 Optic" HSE06_Static = "HSE06 Static" HSE06_Structure_Optimization = "HSE06 Structure Optimization" HSE06_U_DFPT = "HSE06+U DFPT" HSE06_U_DFPT_Dielectric = "HSE06+U DFPT Dielectric" HSE06_U_Deformation = "HSE06+U Deformation" HSE06_U_Dielectric = "HSE06+U Dielectric" HSE06_U_Molecular_Dynamics = "HSE06+U Molecular Dynamics" HSE06_U_NMR_Electric_Field_Gradient = "HSE06+U NMR Electric Field Gradient" HSE06_U_NMR_Nuclear_Shielding = "HSE06+U NMR Nuclear Shielding" HSE06_U_NSCF_Line = "HSE06+U NSCF Line" HSE06_U_NSCF_Uniform = "HSE06+U NSCF Uniform" HSE06_U_Optic = "HSE06+U Optic" HSE06_U_Static = "HSE06+U Static" HSE06_U_Structure_Optimization = "HSE06+U Structure Optimization" HSE06_U_Unrecognized = "HSE06+U Unrecognized" HSE06_Unrecognized = "HSE06 Unrecognized" LDA_DFPT = "LDA DFPT" LDA_DFPT_Dielectric = "LDA DFPT Dielectric" LDA_Deformation = "LDA Deformation" LDA_Dielectric = "LDA Dielectric" LDA_Molecular_Dynamics = "LDA Molecular Dynamics" LDA_NMR_Electric_Field_Gradient = "LDA NMR Electric Field Gradient" LDA_NMR_Nuclear_Shielding = "LDA NMR Nuclear Shielding" LDA_NSCF_Line = "LDA NSCF Line" LDA_NSCF_Uniform = "LDA NSCF Uniform" LDA_Optic = "LDA Optic" LDA_Static = "LDA Static" LDA_Structure_Optimization = "LDA Structure Optimization" LDA_U_DFPT = "LDA+U DFPT" LDA_U_DFPT_Dielectric = "LDA+U DFPT Dielectric" LDA_U_Deformation = "LDA+U Deformation" LDA_U_Dielectric = "LDA+U Dielectric" LDA_U_Molecular_Dynamics = "LDA+U Molecular Dynamics" LDA_U_NMR_Electric_Field_Gradient = "LDA+U NMR Electric Field Gradient" LDA_U_NMR_Nuclear_Shielding = "LDA+U NMR Nuclear Shielding" LDA_U_NSCF_Line = "LDA+U NSCF Line" LDA_U_NSCF_Uniform = "LDA+U NSCF Uniform" LDA_U_Optic = "LDA+U Optic" LDA_U_Static = "LDA+U Static" LDA_U_Structure_Optimization = "LDA+U Structure Optimization" LDA_U_Unrecognized = "LDA+U Unrecognized" LDA_Unrecognized = "LDA Unrecognized" M06L_DFPT = "M06L DFPT" M06L_DFPT_Dielectric = "M06L DFPT Dielectric" M06L_Deformation = "M06L Deformation" M06L_Dielectric = "M06L Dielectric" M06L_Molecular_Dynamics = "M06L Molecular Dynamics" M06L_NMR_Electric_Field_Gradient = "M06L NMR Electric Field Gradient" M06L_NMR_Nuclear_Shielding = "M06L NMR Nuclear Shielding" M06L_NSCF_Line = "M06L NSCF Line" M06L_NSCF_Uniform = "M06L NSCF Uniform" M06L_Optic = "M06L Optic" M06L_Static = "M06L Static" M06L_Structure_Optimization = "M06L Structure Optimization" M06L_U_DFPT = "M06L+U DFPT" M06L_U_DFPT_Dielectric = "M06L+U DFPT Dielectric" M06L_U_Deformation = "M06L+U Deformation" M06L_U_Dielectric = "M06L+U Dielectric" M06L_U_Molecular_Dynamics = "M06L+U Molecular Dynamics" M06L_U_NMR_Electric_Field_Gradient = "M06L+U NMR Electric Field Gradient" M06L_U_NMR_Nuclear_Shielding = "M06L+U NMR Nuclear Shielding" M06L_U_NSCF_Line = "M06L+U NSCF Line" M06L_U_NSCF_Uniform = "M06L+U NSCF Uniform" M06L_U_Optic = "M06L+U Optic" M06L_U_Static = "M06L+U Static" M06L_U_Structure_Optimization = "M06L+U Structure Optimization" M06L_U_Unrecognized = "M06L+U Unrecognized" M06L_Unrecognized = "M06L Unrecognized" MBJL_DFPT = "MBJL DFPT" MBJL_DFPT_Dielectric = "MBJL DFPT Dielectric" MBJL_Deformation = "MBJL Deformation" MBJL_Dielectric = "MBJL Dielectric" MBJL_Molecular_Dynamics = "MBJL Molecular Dynamics" MBJL_NMR_Electric_Field_Gradient = "MBJL NMR Electric Field Gradient" MBJL_NMR_Nuclear_Shielding = "MBJL NMR Nuclear Shielding" MBJL_NSCF_Line = "MBJL NSCF Line" MBJL_NSCF_Uniform = "MBJL NSCF Uniform" MBJL_Optic = "MBJL Optic" MBJL_Static = "MBJL Static" MBJL_Structure_Optimization = "MBJL Structure Optimization" MBJL_U_DFPT = "MBJL+U DFPT" MBJL_U_DFPT_Dielectric = "MBJL+U DFPT Dielectric" MBJL_U_Deformation = "MBJL+U Deformation" MBJL_U_Dielectric = "MBJL+U Dielectric" MBJL_U_Molecular_Dynamics = "MBJL+U Molecular Dynamics" MBJL_U_NMR_Electric_Field_Gradient = "MBJL+U NMR Electric Field Gradient" MBJL_U_NMR_Nuclear_Shielding = "MBJL+U NMR Nuclear Shielding" MBJL_U_NSCF_Line = "MBJL+U NSCF Line" MBJL_U_NSCF_Uniform = "MBJL+U NSCF Uniform" MBJL_U_Optic = "MBJL+U Optic" MBJL_U_Static = "MBJL+U Static" MBJL_U_Structure_Optimization = "MBJL+U Structure Optimization" MBJL_U_Unrecognized = "MBJL+U Unrecognized" MBJL_Unrecognized = "MBJL Unrecognized" MS0_DFPT = "MS0 DFPT" MS0_DFPT_Dielectric = "MS0 DFPT Dielectric" MS0_Deformation = "MS0 Deformation" MS0_Dielectric = "MS0 Dielectric" MS0_Molecular_Dynamics = "MS0 Molecular Dynamics" MS0_NMR_Electric_Field_Gradient = "MS0 NMR Electric Field Gradient" MS0_NMR_Nuclear_Shielding = "MS0 NMR Nuclear Shielding" MS0_NSCF_Line = "MS0 NSCF Line" MS0_NSCF_Uniform = "MS0 NSCF Uniform" MS0_Optic = "MS0 Optic" MS0_Static = "MS0 Static" MS0_Structure_Optimization = "MS0 Structure Optimization" MS0_U_DFPT = "MS0+U DFPT" MS0_U_DFPT_Dielectric = "MS0+U DFPT Dielectric" MS0_U_Deformation = "MS0+U Deformation" MS0_U_Dielectric = "MS0+U Dielectric" MS0_U_Molecular_Dynamics = "MS0+U Molecular Dynamics" MS0_U_NMR_Electric_Field_Gradient = "MS0+U NMR Electric Field Gradient" MS0_U_NMR_Nuclear_Shielding = "MS0+U NMR Nuclear Shielding" MS0_U_NSCF_Line = "MS0+U NSCF Line" MS0_U_NSCF_Uniform = "MS0+U NSCF Uniform" MS0_U_Optic = "MS0+U Optic" MS0_U_Static = "MS0+U Static" MS0_U_Structure_Optimization = "MS0+U Structure Optimization" MS0_U_Unrecognized = "MS0+U Unrecognized" MS0_Unrecognized = "MS0 Unrecognized" MS1_DFPT = "MS1 DFPT" MS1_DFPT_Dielectric = "MS1 DFPT Dielectric" MS1_Deformation = "MS1 Deformation" MS1_Dielectric = "MS1 Dielectric" MS1_Molecular_Dynamics = "MS1 Molecular Dynamics" MS1_NMR_Electric_Field_Gradient = "MS1 NMR Electric Field Gradient" MS1_NMR_Nuclear_Shielding = "MS1 NMR Nuclear Shielding" MS1_NSCF_Line = "MS1 NSCF Line" MS1_NSCF_Uniform = "MS1 NSCF Uniform" MS1_Optic = "MS1 Optic" MS1_Static = "MS1 Static" MS1_Structure_Optimization = "MS1 Structure Optimization" MS1_U_DFPT = "MS1+U DFPT" MS1_U_DFPT_Dielectric = "MS1+U DFPT Dielectric" MS1_U_Deformation = "MS1+U Deformation" MS1_U_Dielectric = "MS1+U Dielectric" MS1_U_Molecular_Dynamics = "MS1+U Molecular Dynamics" MS1_U_NMR_Electric_Field_Gradient = "MS1+U NMR Electric Field Gradient" MS1_U_NMR_Nuclear_Shielding = "MS1+U NMR Nuclear Shielding" MS1_U_NSCF_Line = "MS1+U NSCF Line" MS1_U_NSCF_Uniform = "MS1+U NSCF Uniform" MS1_U_Optic = "MS1+U Optic" MS1_U_Static = "MS1+U Static" MS1_U_Structure_Optimization = "MS1+U Structure Optimization" MS1_U_Unrecognized = "MS1+U Unrecognized" MS1_Unrecognized = "MS1 Unrecognized" MS2_DFPT = "MS2 DFPT" MS2_DFPT_Dielectric = "MS2 DFPT Dielectric" MS2_Deformation = "MS2 Deformation" MS2_Dielectric = "MS2 Dielectric" MS2_Molecular_Dynamics = "MS2 Molecular Dynamics" MS2_NMR_Electric_Field_Gradient = "MS2 NMR Electric Field Gradient" MS2_NMR_Nuclear_Shielding = "MS2 NMR Nuclear Shielding" MS2_NSCF_Line = "MS2 NSCF Line" MS2_NSCF_Uniform = "MS2 NSCF Uniform" MS2_Optic = "MS2 Optic" MS2_Static = "MS2 Static" MS2_Structure_Optimization = "MS2 Structure Optimization" MS2_U_DFPT = "MS2+U DFPT" MS2_U_DFPT_Dielectric = "MS2+U DFPT Dielectric" MS2_U_Deformation = "MS2+U Deformation" MS2_U_Dielectric = "MS2+U Dielectric" MS2_U_Molecular_Dynamics = "MS2+U Molecular Dynamics" MS2_U_NMR_Electric_Field_Gradient = "MS2+U NMR Electric Field Gradient" MS2_U_NMR_Nuclear_Shielding = "MS2+U NMR Nuclear Shielding" MS2_U_NSCF_Line = "MS2+U NSCF Line" MS2_U_NSCF_Uniform = "MS2+U NSCF Uniform" MS2_U_Optic = "MS2+U Optic" MS2_U_Static = "MS2+U Static" MS2_U_Structure_Optimization = "MS2+U Structure Optimization" MS2_U_Unrecognized = "MS2+U Unrecognized" MS2_Unrecognized = "MS2 Unrecognized" PBE0_DFPT = "PBE0 DFPT" PBE0_DFPT_Dielectric = "PBE0 DFPT Dielectric" PBE0_Deformation = "PBE0 Deformation" PBE0_Dielectric = "PBE0 Dielectric" PBE0_Molecular_Dynamics = "PBE0 Molecular Dynamics" PBE0_NMR_Electric_Field_Gradient = "PBE0 NMR Electric Field Gradient" PBE0_NMR_Nuclear_Shielding = "PBE0 NMR Nuclear Shielding" PBE0_NSCF_Line = "PBE0 NSCF Line" PBE0_NSCF_Uniform = "PBE0 NSCF Uniform" PBE0_Optic = "PBE0 Optic" PBE0_Static = "PBE0 Static" PBE0_Structure_Optimization = "PBE0 Structure Optimization" PBE0_U_DFPT = "PBE0+U DFPT" PBE0_U_DFPT_Dielectric = "PBE0+U DFPT Dielectric" PBE0_U_Deformation = "PBE0+U Deformation" PBE0_U_Dielectric = "PBE0+U Dielectric" PBE0_U_Molecular_Dynamics = "PBE0+U Molecular Dynamics" PBE0_U_NMR_Electric_Field_Gradient = "PBE0+U NMR Electric Field Gradient" PBE0_U_NMR_Nuclear_Shielding = "PBE0+U NMR Nuclear Shielding" PBE0_U_NSCF_Line = "PBE0+U NSCF Line" PBE0_U_NSCF_Uniform = "PBE0+U NSCF Uniform" PBE0_U_Optic = "PBE0+U Optic" PBE0_U_Static = "PBE0+U Static" PBE0_U_Structure_Optimization = "PBE0+U Structure Optimization" PBE0_U_Unrecognized = "PBE0+U Unrecognized" PBE0_Unrecognized = "PBE0 Unrecognized" PBE_DFPT = "PBE DFPT" PBE_DFPT_Dielectric = "PBE DFPT Dielectric" PBE_Deformation = "PBE Deformation" PBE_Dielectric = "PBE Dielectric" PBE_Molecular_Dynamics = "PBE Molecular Dynamics" PBE_NMR_Electric_Field_Gradient = "PBE NMR Electric Field Gradient" PBE_NMR_Nuclear_Shielding = "PBE NMR Nuclear Shielding" PBE_NSCF_Line = "PBE NSCF Line" PBE_NSCF_Uniform = "PBE NSCF Uniform" PBE_Optic = "PBE Optic" PBE_Static = "PBE Static" PBE_Structure_Optimization = "PBE Structure Optimization" PBE_U_DFPT = "PBE+U DFPT" PBE_U_DFPT_Dielectric = "PBE+U DFPT Dielectric" PBE_U_Deformation = "PBE+U Deformation" PBE_U_Dielectric = "PBE+U Dielectric" PBE_U_Molecular_Dynamics = "PBE+U Molecular Dynamics" PBE_U_NMR_Electric_Field_Gradient = "PBE+U NMR Electric Field Gradient" PBE_U_NMR_Nuclear_Shielding = "PBE+U NMR Nuclear Shielding" PBE_U_NSCF_Line = "PBE+U NSCF Line" PBE_U_NSCF_Uniform = "PBE+U NSCF Uniform" PBE_U_Optic = "PBE+U Optic" PBE_U_Static = "PBE+U Static" PBE_U_Structure_Optimization = "PBE+U Structure Optimization" PBE_U_Unrecognized = "PBE+U Unrecognized" PBE_Unrecognized = "PBE Unrecognized" PBEsol_DFPT = "PBEsol DFPT" PBEsol_DFPT_Dielectric = "PBEsol DFPT Dielectric" PBEsol_Deformation = "PBEsol Deformation" PBEsol_Dielectric = "PBEsol Dielectric" PBEsol_Molecular_Dynamics = "PBEsol Molecular Dynamics" PBEsol_NMR_Electric_Field_Gradient = "PBEsol NMR Electric Field Gradient" PBEsol_NMR_Nuclear_Shielding = "PBEsol NMR Nuclear Shielding" PBEsol_NSCF_Line = "PBEsol NSCF Line" PBEsol_NSCF_Uniform = "PBEsol NSCF Uniform" PBEsol_Optic = "PBEsol Optic" PBEsol_Static = "PBEsol Static" PBEsol_Structure_Optimization = "PBEsol Structure Optimization" PBEsol_U_DFPT = "PBEsol+U DFPT" PBEsol_U_DFPT_Dielectric = "PBEsol+U DFPT Dielectric" PBEsol_U_Deformation = "PBEsol+U Deformation" PBEsol_U_Dielectric = "PBEsol+U Dielectric" PBEsol_U_Molecular_Dynamics = "PBEsol+U Molecular Dynamics" PBEsol_U_NMR_Electric_Field_Gradient = "PBEsol+U NMR Electric Field Gradient" PBEsol_U_NMR_Nuclear_Shielding = "PBEsol+U NMR Nuclear Shielding" PBEsol_U_NSCF_Line = "PBEsol+U NSCF Line" PBEsol_U_NSCF_Uniform = "PBEsol+U NSCF Uniform" PBEsol_U_Optic = "PBEsol+U Optic" PBEsol_U_Static = "PBEsol+U Static" PBEsol_U_Structure_Optimization = "PBEsol+U Structure Optimization" PBEsol_U_Unrecognized = "PBEsol+U Unrecognized" PBEsol_Unrecognized = "PBEsol Unrecognized" RTPSS_DFPT = "RTPSS DFPT" RTPSS_DFPT_Dielectric = "RTPSS DFPT Dielectric" RTPSS_Deformation = "RTPSS Deformation" RTPSS_Dielectric = "RTPSS Dielectric" RTPSS_Molecular_Dynamics = "RTPSS Molecular Dynamics" RTPSS_NMR_Electric_Field_Gradient = "RTPSS NMR Electric Field Gradient" RTPSS_NMR_Nuclear_Shielding = "RTPSS NMR Nuclear Shielding" RTPSS_NSCF_Line = "RTPSS NSCF Line" RTPSS_NSCF_Uniform = "RTPSS NSCF Uniform" RTPSS_Optic = "RTPSS Optic" RTPSS_Static = "RTPSS Static" RTPSS_Structure_Optimization = "RTPSS Structure Optimization" RTPSS_U_DFPT = "RTPSS+U DFPT" RTPSS_U_DFPT_Dielectric = "RTPSS+U DFPT Dielectric" RTPSS_U_Deformation = "RTPSS+U Deformation" RTPSS_U_Dielectric = "RTPSS+U Dielectric" RTPSS_U_Molecular_Dynamics = "RTPSS+U Molecular Dynamics" RTPSS_U_NMR_Electric_Field_Gradient = "RTPSS+U NMR Electric Field Gradient" RTPSS_U_NMR_Nuclear_Shielding = "RTPSS+U NMR Nuclear Shielding" RTPSS_U_NSCF_Line = "RTPSS+U NSCF Line" RTPSS_U_NSCF_Uniform = "RTPSS+U NSCF Uniform" RTPSS_U_Optic = "RTPSS+U Optic" RTPSS_U_Static = "RTPSS+U Static" RTPSS_U_Structure_Optimization = "RTPSS+U Structure Optimization" RTPSS_U_Unrecognized = "RTPSS+U Unrecognized" RTPSS_Unrecognized = "RTPSS Unrecognized" SCAN_DFPT = "SCAN DFPT" SCAN_DFPT_Dielectric = "SCAN DFPT Dielectric" SCAN_Deformation = "SCAN Deformation" SCAN_Dielectric = "SCAN Dielectric" SCAN_Molecular_Dynamics = "SCAN Molecular Dynamics" SCAN_NMR_Electric_Field_Gradient = "SCAN NMR Electric Field Gradient" SCAN_NMR_Nuclear_Shielding = "SCAN NMR Nuclear Shielding" SCAN_NSCF_Line = "SCAN NSCF Line" SCAN_NSCF_Uniform = "SCAN NSCF Uniform" SCAN_Optic = "SCAN Optic" SCAN_Static = "SCAN Static" SCAN_Structure_Optimization = "SCAN Structure Optimization" SCAN_U_DFPT = "SCAN+U DFPT" SCAN_U_DFPT_Dielectric = "SCAN+U DFPT Dielectric" SCAN_U_Deformation = "SCAN+U Deformation" SCAN_U_Dielectric = "SCAN+U Dielectric" SCAN_U_Molecular_Dynamics = "SCAN+U Molecular Dynamics" SCAN_U_NMR_Electric_Field_Gradient = "SCAN+U NMR Electric Field Gradient" SCAN_U_NMR_Nuclear_Shielding = "SCAN+U NMR Nuclear Shielding" SCAN_U_NSCF_Line = "SCAN+U NSCF Line" SCAN_U_NSCF_Uniform = "SCAN+U NSCF Uniform" SCAN_U_Optic = "SCAN+U Optic" SCAN_U_Static = "SCAN+U Static" SCAN_U_Structure_Optimization = "SCAN+U Structure Optimization" SCAN_U_Unrecognized = "SCAN+U Unrecognized" SCAN_Unrecognized = "SCAN Unrecognized" SCAN_rVV10_DFPT = "SCAN-rVV10 DFPT" SCAN_rVV10_DFPT_Dielectric = "SCAN-rVV10 DFPT Dielectric" SCAN_rVV10_Deformation = "SCAN-rVV10 Deformation" SCAN_rVV10_Dielectric = "SCAN-rVV10 Dielectric" SCAN_rVV10_Molecular_Dynamics = "SCAN-rVV10 Molecular Dynamics" SCAN_rVV10_NMR_Electric_Field_Gradient = "SCAN-rVV10 NMR Electric Field Gradient" SCAN_rVV10_NMR_Nuclear_Shielding = "SCAN-rVV10 NMR Nuclear Shielding" SCAN_rVV10_NSCF_Line = "SCAN-rVV10 NSCF Line" SCAN_rVV10_NSCF_Uniform = "SCAN-rVV10 NSCF Uniform" SCAN_rVV10_Optic = "SCAN-rVV10 Optic" SCAN_rVV10_Static = "SCAN-rVV10 Static" SCAN_rVV10_Structure_Optimization = "SCAN-rVV10 Structure Optimization" SCAN_rVV10_U_DFPT = "SCAN-rVV10+U DFPT" SCAN_rVV10_U_DFPT_Dielectric = "SCAN-rVV10+U DFPT Dielectric" SCAN_rVV10_U_Deformation = "SCAN-rVV10+U Deformation" SCAN_rVV10_U_Dielectric = "SCAN-rVV10+U Dielectric" SCAN_rVV10_U_Molecular_Dynamics = "SCAN-rVV10+U Molecular Dynamics" SCAN_rVV10_U_NMR_Electric_Field_Gradient = ( "SCAN-rVV10+U NMR Electric Field Gradient" ) SCAN_rVV10_U_NMR_Nuclear_Shielding = "SCAN-rVV10+U NMR Nuclear Shielding" SCAN_rVV10_U_NSCF_Line = "SCAN-rVV10+U NSCF Line" SCAN_rVV10_U_NSCF_Uniform = "SCAN-rVV10+U NSCF Uniform" SCAN_rVV10_U_Optic = "SCAN-rVV10+U Optic" SCAN_rVV10_U_Static = "SCAN-rVV10+U Static" SCAN_rVV10_U_Structure_Optimization = "SCAN-rVV10+U Structure Optimization" SCAN_rVV10_U_Unrecognized = "SCAN-rVV10+U Unrecognized" SCAN_rVV10_Unrecognized = "SCAN-rVV10 Unrecognized" TPSS_DFPT = "TPSS DFPT" TPSS_DFPT_Dielectric = "TPSS DFPT Dielectric" TPSS_Deformation = "TPSS Deformation" TPSS_Dielectric = "TPSS Dielectric" TPSS_Molecular_Dynamics = "TPSS Molecular Dynamics" TPSS_NMR_Electric_Field_Gradient = "TPSS NMR Electric Field Gradient" TPSS_NMR_Nuclear_Shielding = "TPSS NMR Nuclear Shielding" TPSS_NSCF_Line = "TPSS NSCF Line" TPSS_NSCF_Uniform = "TPSS NSCF Uniform" TPSS_Optic = "TPSS Optic" TPSS_Static = "TPSS Static" TPSS_Structure_Optimization = "TPSS Structure Optimization" TPSS_U_DFPT = "TPSS+U DFPT" TPSS_U_DFPT_Dielectric = "TPSS+U DFPT Dielectric" TPSS_U_Deformation = "TPSS+U Deformation" TPSS_U_Dielectric = "TPSS+U Dielectric" TPSS_U_Molecular_Dynamics = "TPSS+U Molecular Dynamics" TPSS_U_NMR_Electric_Field_Gradient = "TPSS+U NMR Electric Field Gradient" TPSS_U_NMR_Nuclear_Shielding = "TPSS+U NMR Nuclear Shielding" TPSS_U_NSCF_Line = "TPSS+U NSCF Line" TPSS_U_NSCF_Uniform = "TPSS+U NSCF Uniform" TPSS_U_Optic = "TPSS+U Optic" TPSS_U_Static = "TPSS+U Static" TPSS_U_Structure_Optimization = "TPSS+U Structure Optimization" TPSS_U_Unrecognized = "TPSS+U Unrecognized" TPSS_Unrecognized = "TPSS Unrecognized" optB86b_DFPT = "optB86b DFPT" optB86b_DFPT_Dielectric = "optB86b DFPT Dielectric" optB86b_Deformation = "optB86b Deformation" optB86b_Dielectric = "optB86b Dielectric" optB86b_Molecular_Dynamics = "optB86b Molecular Dynamics" optB86b_NMR_Electric_Field_Gradient = "optB86b NMR Electric Field Gradient" optB86b_NMR_Nuclear_Shielding = "optB86b NMR Nuclear Shielding" optB86b_NSCF_Line = "optB86b NSCF Line" optB86b_NSCF_Uniform = "optB86b NSCF Uniform" optB86b_Optic = "optB86b Optic" optB86b_Static = "optB86b Static" optB86b_Structure_Optimization = "optB86b Structure Optimization" optB86b_U_DFPT = "optB86b+U DFPT" optB86b_U_DFPT_Dielectric = "optB86b+U DFPT Dielectric" optB86b_U_Deformation = "optB86b+U Deformation" optB86b_U_Dielectric = "optB86b+U Dielectric" optB86b_U_Molecular_Dynamics = "optB86b+U Molecular Dynamics" optB86b_U_NMR_Electric_Field_Gradient = "optB86b+U NMR Electric Field Gradient" optB86b_U_NMR_Nuclear_Shielding = "optB86b+U NMR Nuclear Shielding" optB86b_U_NSCF_Line = "optB86b+U NSCF Line" optB86b_U_NSCF_Uniform = "optB86b+U NSCF Uniform" optB86b_U_Optic = "optB86b+U Optic" optB86b_U_Static = "optB86b+U Static" optB86b_U_Structure_Optimization = "optB86b+U Structure Optimization" optB86b_U_Unrecognized = "optB86b+U Unrecognized" optB86b_Unrecognized = "optB86b Unrecognized" optB86b_vdW_DFPT = "optB86b-vdW DFPT" optB86b_vdW_DFPT_Dielectric = "optB86b-vdW DFPT Dielectric" optB86b_vdW_Deformation = "optB86b-vdW Deformation" optB86b_vdW_Dielectric = "optB86b-vdW Dielectric" optB86b_vdW_Molecular_Dynamics = "optB86b-vdW Molecular Dynamics" optB86b_vdW_NMR_Electric_Field_Gradient = "optB86b-vdW NMR Electric Field Gradient" optB86b_vdW_NMR_Nuclear_Shielding = "optB86b-vdW NMR Nuclear Shielding" optB86b_vdW_NSCF_Line = "optB86b-vdW NSCF Line" optB86b_vdW_NSCF_Uniform = "optB86b-vdW NSCF Uniform" optB86b_vdW_Optic = "optB86b-vdW Optic" optB86b_vdW_Static = "optB86b-vdW Static" optB86b_vdW_Structure_Optimization = "optB86b-vdW Structure Optimization" optB86b_vdW_U_DFPT = "optB86b-vdW+U DFPT" optB86b_vdW_U_DFPT_Dielectric = "optB86b-vdW+U DFPT Dielectric" optB86b_vdW_U_Deformation = "optB86b-vdW+U Deformation" optB86b_vdW_U_Dielectric = "optB86b-vdW+U Dielectric" optB86b_vdW_U_Molecular_Dynamics = "optB86b-vdW+U Molecular Dynamics" optB86b_vdW_U_NMR_Electric_Field_Gradient = ( "optB86b-vdW+U NMR Electric Field Gradient" ) optB86b_vdW_U_NMR_Nuclear_Shielding = "optB86b-vdW+U NMR Nuclear Shielding" optB86b_vdW_U_NSCF_Line = "optB86b-vdW+U NSCF Line" optB86b_vdW_U_NSCF_Uniform = "optB86b-vdW+U NSCF Uniform" optB86b_vdW_U_Optic = "optB86b-vdW+U Optic" optB86b_vdW_U_Static = "optB86b-vdW+U Static" optB86b_vdW_U_Structure_Optimization = "optB86b-vdW+U Structure Optimization" optB86b_vdW_U_Unrecognized = "optB86b-vdW+U Unrecognized" optB86b_vdW_Unrecognized = "optB86b-vdW Unrecognized" optB88_DFPT = "optB88 DFPT" optB88_DFPT_Dielectric = "optB88 DFPT Dielectric" optB88_Deformation = "optB88 Deformation" optB88_Dielectric = "optB88 Dielectric" optB88_Molecular_Dynamics = "optB88 Molecular Dynamics" optB88_NMR_Electric_Field_Gradient = "optB88 NMR Electric Field Gradient" optB88_NMR_Nuclear_Shielding = "optB88 NMR Nuclear Shielding" optB88_NSCF_Line = "optB88 NSCF Line" optB88_NSCF_Uniform = "optB88 NSCF Uniform" optB88_Optic = "optB88 Optic" optB88_Static = "optB88 Static" optB88_Structure_Optimization = "optB88 Structure Optimization" optB88_U_DFPT = "optB88+U DFPT" optB88_U_DFPT_Dielectric = "optB88+U DFPT Dielectric" optB88_U_Deformation = "optB88+U Deformation" optB88_U_Dielectric = "optB88+U Dielectric" optB88_U_Molecular_Dynamics = "optB88+U Molecular Dynamics" optB88_U_NMR_Electric_Field_Gradient = "optB88+U NMR Electric Field Gradient" optB88_U_NMR_Nuclear_Shielding = "optB88+U NMR Nuclear Shielding" optB88_U_NSCF_Line = "optB88+U NSCF Line" optB88_U_NSCF_Uniform = "optB88+U NSCF Uniform" optB88_U_Optic = "optB88+U Optic" optB88_U_Static = "optB88+U Static" optB88_U_Structure_Optimization = "optB88+U Structure Optimization" optB88_U_Unrecognized = "optB88+U Unrecognized" optB88_Unrecognized = "optB88 Unrecognized" optB88_vdW_DFPT = "optB88-vdW DFPT" optB88_vdW_DFPT_Dielectric = "optB88-vdW DFPT Dielectric" optB88_vdW_Deformation = "optB88-vdW Deformation" optB88_vdW_Dielectric = "optB88-vdW Dielectric" optB88_vdW_Molecular_Dynamics = "optB88-vdW Molecular Dynamics" optB88_vdW_NMR_Electric_Field_Gradient = "optB88-vdW NMR Electric Field Gradient" optB88_vdW_NMR_Nuclear_Shielding = "optB88-vdW NMR Nuclear Shielding" optB88_vdW_NSCF_Line = "optB88-vdW NSCF Line" optB88_vdW_NSCF_Uniform = "optB88-vdW NSCF Uniform" optB88_vdW_Optic = "optB88-vdW Optic" optB88_vdW_Static = "optB88-vdW Static" optB88_vdW_Structure_Optimization = "optB88-vdW Structure Optimization" optB88_vdW_U_DFPT = "optB88-vdW+U DFPT" optB88_vdW_U_DFPT_Dielectric = "optB88-vdW+U DFPT Dielectric" optB88_vdW_U_Deformation = "optB88-vdW+U Deformation" optB88_vdW_U_Dielectric = "optB88-vdW+U Dielectric" optB88_vdW_U_Molecular_Dynamics = "optB88-vdW+U Molecular Dynamics" optB88_vdW_U_NMR_Electric_Field_Gradient = ( "optB88-vdW+U NMR Electric Field Gradient" ) optB88_vdW_U_NMR_Nuclear_Shielding = "optB88-vdW+U NMR Nuclear Shielding" optB88_vdW_U_NSCF_Line = "optB88-vdW+U NSCF Line" optB88_vdW_U_NSCF_Uniform = "optB88-vdW+U NSCF Uniform" optB88_vdW_U_Optic = "optB88-vdW+U Optic" optB88_vdW_U_Static = "optB88-vdW+U Static" optB88_vdW_U_Structure_Optimization = "optB88-vdW+U Structure Optimization" optB88_vdW_U_Unrecognized = "optB88-vdW+U Unrecognized" optB88_vdW_Unrecognized = "optB88-vdW Unrecognized" optPBE_DFPT = "optPBE DFPT" optPBE_DFPT_Dielectric = "optPBE DFPT Dielectric" optPBE_Deformation = "optPBE Deformation" optPBE_Dielectric = "optPBE Dielectric" optPBE_Molecular_Dynamics = "optPBE Molecular Dynamics" optPBE_NMR_Electric_Field_Gradient = "optPBE NMR Electric Field Gradient" optPBE_NMR_Nuclear_Shielding = "optPBE NMR Nuclear Shielding" optPBE_NSCF_Line = "optPBE NSCF Line" optPBE_NSCF_Uniform = "optPBE NSCF Uniform" optPBE_Optic = "optPBE Optic" optPBE_Static = "optPBE Static" optPBE_Structure_Optimization = "optPBE Structure Optimization" optPBE_U_DFPT = "optPBE+U DFPT" optPBE_U_DFPT_Dielectric = "optPBE+U DFPT Dielectric" optPBE_U_Deformation = "optPBE+U Deformation" optPBE_U_Dielectric = "optPBE+U Dielectric" optPBE_U_Molecular_Dynamics = "optPBE+U Molecular Dynamics" optPBE_U_NMR_Electric_Field_Gradient = "optPBE+U NMR Electric Field Gradient" optPBE_U_NMR_Nuclear_Shielding = "optPBE+U NMR Nuclear Shielding" optPBE_U_NSCF_Line = "optPBE+U NSCF Line" optPBE_U_NSCF_Uniform = "optPBE+U NSCF Uniform" optPBE_U_Optic = "optPBE+U Optic" optPBE_U_Static = "optPBE+U Static" optPBE_U_Structure_Optimization = "optPBE+U Structure Optimization" optPBE_U_Unrecognized = "optPBE+U Unrecognized" optPBE_Unrecognized = "optPBE Unrecognized" optPBE_vdW_DFPT = "optPBE-vdW DFPT" optPBE_vdW_DFPT_Dielectric = "optPBE-vdW DFPT Dielectric" optPBE_vdW_Deformation = "optPBE-vdW Deformation" optPBE_vdW_Dielectric = "optPBE-vdW Dielectric" optPBE_vdW_Molecular_Dynamics = "optPBE-vdW Molecular Dynamics" optPBE_vdW_NMR_Electric_Field_Gradient = "optPBE-vdW NMR Electric Field Gradient" optPBE_vdW_NMR_Nuclear_Shielding = "optPBE-vdW NMR Nuclear Shielding" optPBE_vdW_NSCF_Line = "optPBE-vdW NSCF Line" optPBE_vdW_NSCF_Uniform = "optPBE-vdW NSCF Uniform" optPBE_vdW_Optic = "optPBE-vdW Optic" optPBE_vdW_Static = "optPBE-vdW Static" optPBE_vdW_Structure_Optimization = "optPBE-vdW Structure Optimization" optPBE_vdW_U_DFPT = "optPBE-vdW+U DFPT" optPBE_vdW_U_DFPT_Dielectric = "optPBE-vdW+U DFPT Dielectric" optPBE_vdW_U_Deformation = "optPBE-vdW+U Deformation" optPBE_vdW_U_Dielectric = "optPBE-vdW+U Dielectric" optPBE_vdW_U_Molecular_Dynamics = "optPBE-vdW+U Molecular Dynamics" optPBE_vdW_U_NMR_Electric_Field_Gradient = ( "optPBE-vdW+U NMR Electric Field Gradient" ) optPBE_vdW_U_NMR_Nuclear_Shielding = "optPBE-vdW+U NMR Nuclear Shielding" optPBE_vdW_U_NSCF_Line = "optPBE-vdW+U NSCF Line" optPBE_vdW_U_NSCF_Uniform = "optPBE-vdW+U NSCF Uniform" optPBE_vdW_U_Optic = "optPBE-vdW+U Optic" optPBE_vdW_U_Static = "optPBE-vdW+U Static" optPBE_vdW_U_Structure_Optimization = "optPBE-vdW+U Structure Optimization" optPBE_vdW_U_Unrecognized = "optPBE-vdW+U Unrecognized" optPBE_vdW_Unrecognized = "optPBE-vdW Unrecognized" r2SCAN_DFPT = "r2SCAN DFPT" r2SCAN_DFPT_Dielectric = "r2SCAN DFPT Dielectric" r2SCAN_Deformation = "r2SCAN Deformation" r2SCAN_Dielectric = "r2SCAN Dielectric" r2SCAN_Molecular_Dynamics = "r2SCAN Molecular Dynamics" r2SCAN_NMR_Electric_Field_Gradient = "r2SCAN NMR Electric Field Gradient" r2SCAN_NMR_Nuclear_Shielding = "r2SCAN NMR Nuclear Shielding" r2SCAN_NSCF_Line = "r2SCAN NSCF Line" r2SCAN_NSCF_Uniform = "r2SCAN NSCF Uniform" r2SCAN_Optic = "r2SCAN Optic" r2SCAN_Static = "r2SCAN Static" r2SCAN_Structure_Optimization = "r2SCAN Structure Optimization" r2SCAN_U_DFPT = "r2SCAN+U DFPT" r2SCAN_U_DFPT_Dielectric = "r2SCAN+U DFPT Dielectric" r2SCAN_U_Deformation = "r2SCAN+U Deformation" r2SCAN_U_Dielectric = "r2SCAN+U Dielectric" r2SCAN_U_Molecular_Dynamics = "r2SCAN+U Molecular Dynamics" r2SCAN_U_NMR_Electric_Field_Gradient = "r2SCAN+U NMR Electric Field Gradient" r2SCAN_U_NMR_Nuclear_Shielding = "r2SCAN+U NMR Nuclear Shielding" r2SCAN_U_NSCF_Line = "r2SCAN+U NSCF Line" r2SCAN_U_NSCF_Uniform = "r2SCAN+U NSCF Uniform" r2SCAN_U_Optic = "r2SCAN+U Optic" r2SCAN_U_Static = "r2SCAN+U Static" r2SCAN_U_Structure_Optimization = "r2SCAN+U Structure Optimization" r2SCAN_U_Unrecognized = "r2SCAN+U Unrecognized" r2SCAN_Unrecognized = "r2SCAN Unrecognized" r2SCAN_rVV10_DFPT = "r2SCAN-rVV10 DFPT" r2SCAN_rVV10_DFPT_Dielectric = "r2SCAN-rVV10 DFPT Dielectric" r2SCAN_rVV10_Deformation = "r2SCAN-rVV10 Deformation" r2SCAN_rVV10_Dielectric = "r2SCAN-rVV10 Dielectric" r2SCAN_rVV10_Molecular_Dynamics = "r2SCAN-rVV10 Molecular Dynamics" r2SCAN_rVV10_NMR_Electric_Field_Gradient = ( "r2SCAN-rVV10 NMR Electric Field Gradient" ) r2SCAN_rVV10_NMR_Nuclear_Shielding = "r2SCAN-rVV10 NMR Nuclear Shielding" r2SCAN_rVV10_NSCF_Line = "r2SCAN-rVV10 NSCF Line" r2SCAN_rVV10_NSCF_Uniform = "r2SCAN-rVV10 NSCF Uniform" r2SCAN_rVV10_Optic = "r2SCAN-rVV10 Optic" r2SCAN_rVV10_Static = "r2SCAN-rVV10 Static" r2SCAN_rVV10_Structure_Optimization = "r2SCAN-rVV10 Structure Optimization" r2SCAN_rVV10_U_DFPT = "r2SCAN-rVV10+U DFPT" r2SCAN_rVV10_U_DFPT_Dielectric = "r2SCAN-rVV10+U DFPT Dielectric" r2SCAN_rVV10_U_Deformation = "r2SCAN-rVV10+U Deformation" r2SCAN_rVV10_U_Dielectric = "r2SCAN-rVV10+U Dielectric" r2SCAN_rVV10_U_Molecular_Dynamics = "r2SCAN-rVV10+U Molecular Dynamics" r2SCAN_rVV10_U_NMR_Electric_Field_Gradient = ( "r2SCAN-rVV10+U NMR Electric Field Gradient" ) r2SCAN_rVV10_U_NMR_Nuclear_Shielding = "r2SCAN-rVV10+U NMR Nuclear Shielding" r2SCAN_rVV10_U_NSCF_Line = "r2SCAN-rVV10+U NSCF Line" r2SCAN_rVV10_U_NSCF_Uniform = "r2SCAN-rVV10+U NSCF Uniform" r2SCAN_rVV10_U_Optic = "r2SCAN-rVV10+U Optic" r2SCAN_rVV10_U_Static = "r2SCAN-rVV10+U Static" r2SCAN_rVV10_U_Structure_Optimization = "r2SCAN-rVV10+U Structure Optimization" r2SCAN_rVV10_U_Unrecognized = "r2SCAN-rVV10+U Unrecognized" r2SCAN_rVV10_Unrecognized = "r2SCAN-rVV10 Unrecognized" revPBE_DFPT = "revPBE DFPT" revPBE_DFPT_Dielectric = "revPBE DFPT Dielectric" revPBE_Deformation = "revPBE Deformation" revPBE_Dielectric = "revPBE Dielectric" revPBE_Molecular_Dynamics = "revPBE Molecular Dynamics" revPBE_NMR_Electric_Field_Gradient = "revPBE NMR Electric Field Gradient" revPBE_NMR_Nuclear_Shielding = "revPBE NMR Nuclear Shielding" revPBE_NSCF_Line = "revPBE NSCF Line" revPBE_NSCF_Uniform = "revPBE NSCF Uniform" revPBE_Optic = "revPBE Optic" revPBE_PADE_DFPT = "revPBE+PADE DFPT" revPBE_PADE_DFPT_Dielectric = "revPBE+PADE DFPT Dielectric" revPBE_PADE_Deformation = "revPBE+PADE Deformation" revPBE_PADE_Dielectric = "revPBE+PADE Dielectric" revPBE_PADE_Molecular_Dynamics = "revPBE+PADE Molecular Dynamics" revPBE_PADE_NMR_Electric_Field_Gradient = "revPBE+PADE NMR Electric Field Gradient" revPBE_PADE_NMR_Nuclear_Shielding = "revPBE+PADE NMR Nuclear Shielding" revPBE_PADE_NSCF_Line = "revPBE+PADE NSCF Line" revPBE_PADE_NSCF_Uniform = "revPBE+PADE NSCF Uniform" revPBE_PADE_Optic = "revPBE+PADE Optic" revPBE_PADE_Static = "revPBE+PADE Static" revPBE_PADE_Structure_Optimization = "revPBE+PADE Structure Optimization" revPBE_PADE_U_DFPT = "revPBE+PADE+U DFPT" revPBE_PADE_U_DFPT_Dielectric = "revPBE+PADE+U DFPT Dielectric" revPBE_PADE_U_Deformation = "revPBE+PADE+U Deformation" revPBE_PADE_U_Dielectric = "revPBE+PADE+U Dielectric" revPBE_PADE_U_Molecular_Dynamics = "revPBE+PADE+U Molecular Dynamics" revPBE_PADE_U_NMR_Electric_Field_Gradient = ( "revPBE+PADE+U NMR Electric Field Gradient" ) revPBE_PADE_U_NMR_Nuclear_Shielding = "revPBE+PADE+U NMR Nuclear Shielding" revPBE_PADE_U_NSCF_Line = "revPBE+PADE+U NSCF Line" revPBE_PADE_U_NSCF_Uniform = "revPBE+PADE+U NSCF Uniform" revPBE_PADE_U_Optic = "revPBE+PADE+U Optic" revPBE_PADE_U_Static = "revPBE+PADE+U Static" revPBE_PADE_U_Structure_Optimization = "revPBE+PADE+U Structure Optimization" revPBE_PADE_U_Unrecognized = "revPBE+PADE+U Unrecognized" revPBE_PADE_Unrecognized = "revPBE+PADE Unrecognized" revPBE_Static = "revPBE Static" revPBE_Structure_Optimization = "revPBE Structure Optimization" revPBE_U_DFPT = "revPBE+U DFPT" revPBE_U_DFPT_Dielectric = "revPBE+U DFPT Dielectric" revPBE_U_Deformation = "revPBE+U Deformation" revPBE_U_Dielectric = "revPBE+U Dielectric" revPBE_U_Molecular_Dynamics = "revPBE+U Molecular Dynamics" revPBE_U_NMR_Electric_Field_Gradient = "revPBE+U NMR Electric Field Gradient" revPBE_U_NMR_Nuclear_Shielding = "revPBE+U NMR Nuclear Shielding" revPBE_U_NSCF_Line = "revPBE+U NSCF Line" revPBE_U_NSCF_Uniform = "revPBE+U NSCF Uniform" revPBE_U_Optic = "revPBE+U Optic" revPBE_U_Static = "revPBE+U Static" revPBE_U_Structure_Optimization = "revPBE+U Structure Optimization" revPBE_U_Unrecognized = "revPBE+U Unrecognized" revPBE_Unrecognized = "revPBE Unrecognized" revPBE_vdW_DFPT = "revPBE-vdW DFPT" revPBE_vdW_DFPT_Dielectric = "revPBE-vdW DFPT Dielectric" revPBE_vdW_Deformation = "revPBE-vdW Deformation" revPBE_vdW_Dielectric = "revPBE-vdW Dielectric" revPBE_vdW_Molecular_Dynamics = "revPBE-vdW Molecular Dynamics" revPBE_vdW_NMR_Electric_Field_Gradient = "revPBE-vdW NMR Electric Field Gradient" revPBE_vdW_NMR_Nuclear_Shielding = "revPBE-vdW NMR Nuclear Shielding" revPBE_vdW_NSCF_Line = "revPBE-vdW NSCF Line" revPBE_vdW_NSCF_Uniform = "revPBE-vdW NSCF Uniform" revPBE_vdW_Optic = "revPBE-vdW Optic" revPBE_vdW_Static = "revPBE-vdW Static" revPBE_vdW_Structure_Optimization = "revPBE-vdW Structure Optimization" revPBE_vdW_U_DFPT = "revPBE-vdW+U DFPT" revPBE_vdW_U_DFPT_Dielectric = "revPBE-vdW+U DFPT Dielectric" revPBE_vdW_U_Deformation = "revPBE-vdW+U Deformation" revPBE_vdW_U_Dielectric = "revPBE-vdW+U Dielectric" revPBE_vdW_U_Molecular_Dynamics = "revPBE-vdW+U Molecular Dynamics" revPBE_vdW_U_NMR_Electric_Field_Gradient = ( "revPBE-vdW+U NMR Electric Field Gradient" ) revPBE_vdW_U_NMR_Nuclear_Shielding = "revPBE-vdW+U NMR Nuclear Shielding" revPBE_vdW_U_NSCF_Line = "revPBE-vdW+U NSCF Line" revPBE_vdW_U_NSCF_Uniform = "revPBE-vdW+U NSCF Uniform" revPBE_vdW_U_Optic = "revPBE-vdW+U Optic" revPBE_vdW_U_Static = "revPBE-vdW+U Static" revPBE_vdW_U_Structure_Optimization = "revPBE-vdW+U Structure Optimization" revPBE_vdW_U_Unrecognized = "revPBE-vdW+U Unrecognized" revPBE_vdW_Unrecognized = "revPBE-vdW Unrecognized" rev_vdW_DF2_DFPT = "rev-vdW-DF2 DFPT" rev_vdW_DF2_DFPT_Dielectric = "rev-vdW-DF2 DFPT Dielectric" rev_vdW_DF2_Deformation = "rev-vdW-DF2 Deformation" rev_vdW_DF2_Dielectric = "rev-vdW-DF2 Dielectric" rev_vdW_DF2_Molecular_Dynamics = "rev-vdW-DF2 Molecular Dynamics" rev_vdW_DF2_NMR_Electric_Field_Gradient = "rev-vdW-DF2 NMR Electric Field Gradient" rev_vdW_DF2_NMR_Nuclear_Shielding = "rev-vdW-DF2 NMR Nuclear Shielding" rev_vdW_DF2_NSCF_Line = "rev-vdW-DF2 NSCF Line" rev_vdW_DF2_NSCF_Uniform = "rev-vdW-DF2 NSCF Uniform" rev_vdW_DF2_Optic = "rev-vdW-DF2 Optic" rev_vdW_DF2_Static = "rev-vdW-DF2 Static" rev_vdW_DF2_Structure_Optimization = "rev-vdW-DF2 Structure Optimization" rev_vdW_DF2_U_DFPT = "rev-vdW-DF2+U DFPT" rev_vdW_DF2_U_DFPT_Dielectric = "rev-vdW-DF2+U DFPT Dielectric" rev_vdW_DF2_U_Deformation = "rev-vdW-DF2+U Deformation" rev_vdW_DF2_U_Dielectric = "rev-vdW-DF2+U Dielectric" rev_vdW_DF2_U_Molecular_Dynamics = "rev-vdW-DF2+U Molecular Dynamics" rev_vdW_DF2_U_NMR_Electric_Field_Gradient = ( "rev-vdW-DF2+U NMR Electric Field Gradient" ) rev_vdW_DF2_U_NMR_Nuclear_Shielding = "rev-vdW-DF2+U NMR Nuclear Shielding" rev_vdW_DF2_U_NSCF_Line = "rev-vdW-DF2+U NSCF Line" rev_vdW_DF2_U_NSCF_Uniform = "rev-vdW-DF2+U NSCF Uniform" rev_vdW_DF2_U_Optic = "rev-vdW-DF2+U Optic" rev_vdW_DF2_U_Static = "rev-vdW-DF2+U Static" rev_vdW_DF2_U_Structure_Optimization = "rev-vdW-DF2+U Structure Optimization" rev_vdW_DF2_U_Unrecognized = "rev-vdW-DF2+U Unrecognized" rev_vdW_DF2_Unrecognized = "rev-vdW-DF2 Unrecognized" vdW_DF2_DFPT = "vdW-DF2 DFPT" vdW_DF2_DFPT_Dielectric = "vdW-DF2 DFPT Dielectric" vdW_DF2_Deformation = "vdW-DF2 Deformation" vdW_DF2_Dielectric = "vdW-DF2 Dielectric" vdW_DF2_Molecular_Dynamics = "vdW-DF2 Molecular Dynamics" vdW_DF2_NMR_Electric_Field_Gradient = "vdW-DF2 NMR Electric Field Gradient" vdW_DF2_NMR_Nuclear_Shielding = "vdW-DF2 NMR Nuclear Shielding" vdW_DF2_NSCF_Line = "vdW-DF2 NSCF Line" vdW_DF2_NSCF_Uniform = "vdW-DF2 NSCF Uniform" vdW_DF2_Optic = "vdW-DF2 Optic" vdW_DF2_Static = "vdW-DF2 Static" vdW_DF2_Structure_Optimization = "vdW-DF2 Structure Optimization" vdW_DF2_U_DFPT = "vdW-DF2+U DFPT" vdW_DF2_U_DFPT_Dielectric = "vdW-DF2+U DFPT Dielectric" vdW_DF2_U_Deformation = "vdW-DF2+U Deformation" vdW_DF2_U_Dielectric = "vdW-DF2+U Dielectric" vdW_DF2_U_Molecular_Dynamics = "vdW-DF2+U Molecular Dynamics" vdW_DF2_U_NMR_Electric_Field_Gradient = "vdW-DF2+U NMR Electric Field Gradient" vdW_DF2_U_NMR_Nuclear_Shielding = "vdW-DF2+U NMR Nuclear Shielding" vdW_DF2_U_NSCF_Line = "vdW-DF2+U NSCF Line" vdW_DF2_U_NSCF_Uniform = "vdW-DF2+U NSCF Uniform" vdW_DF2_U_Optic = "vdW-DF2+U Optic" vdW_DF2_U_Static = "vdW-DF2+U Static" vdW_DF2_U_Structure_Optimization = "vdW-DF2+U Structure Optimization" vdW_DF2_U_Unrecognized = "vdW-DF2+U Unrecognized" vdW_DF2_Unrecognized = "vdW-DF2 Unrecognized" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/calc_types/utils.py0000644000175100001770000001042414673360562022134 0ustar00runnerdocker"""Module to define various calculation types as Enums for VASP.""" from pathlib import Path from typing import Dict, Literal from monty.serialization import loadfn from emmet.core.vasp.calc_types.enums import CalcType, RunType, TaskType _RUN_TYPE_DATA = loadfn( str(Path(__file__).parent.joinpath("calc_types.yaml").resolve()) )["RUN_TYPES"] __all__ = ["run_type", "task_type", "calc_type"] def run_type(parameters: Dict) -> RunType: """ Determine run type from the VASP parameters dict. This is adapted from pymatgen to be far less unstable Args: parameters: Dictionary of VASP parameters from vasprun.xml. Returns: The run type. Warning: VASP mangles the LDAU* fields in the parameters field. If you're not using the TaskDocument.run_type, copy over LDAU* fields from the incar rather than trust parameters. """ is_hubbard = "+U" if parameters.get("LDAU", False) else "" def _variant_equal(v1, v2) -> bool: """Check two strings equal.""" if isinstance(v1, str) and isinstance(v2, str): return v1.strip().upper() == v2.strip().upper() return v1 == v2 # This is to force an order of evaluation for functional_class in ["HF", "VDW", "METAGGA", "GGA"]: for special_type, params in _RUN_TYPE_DATA[functional_class].items(): if all( _variant_equal(parameters.get(param, None), value) for param, value in params.items() ): return RunType(f"{special_type}{is_hubbard}") return RunType(f"LDA{is_hubbard}") def task_type( inputs: Dict[Literal["incar", "poscar", "kpoints", "potcar"], Dict] ) -> TaskType: """ Determine task type from vasp inputs. Args: inputs: inputs dict with an incar, kpoints, potcar, and poscar dictionaries. Returns: The task type. """ calc_type = [] incar = inputs.get("incar", {}) kpts = inputs.get("kpoints") or {} # kpoints can be None, then want a dict if not isinstance(kpts, dict): kpts = kpts.as_dict() if incar.get("ICHARG", 0) > 10: try: kpt_labels = kpts.get("labels") or [] num_kpt_labels = len(list(filter(None.__ne__, kpt_labels))) except Exception as e: raise Exception("Couldn't identify total number of kpt labels") from e if num_kpt_labels > 0: calc_type.append("NSCF Line") else: calc_type.append("NSCF Uniform") elif len([x for x in kpts.get("labels") or [] if x is not None]) > 0: calc_type.append("NSCF Line") elif incar.get("LEPSILON", False): if incar.get("IBRION", 0) > 6: calc_type.append("DFPT") calc_type.append("Dielectric") elif incar.get("IBRION", 0) > 6: calc_type.append("DFPT") elif incar.get("LCHIMAG", False): calc_type.append("NMR Nuclear Shielding") elif incar.get("LEFG", False): calc_type.append("NMR Electric Field Gradient") elif incar.get("NSW", 1) == 0: if incar.get("LOPTICS", False) is True and incar.get("ALGO", None) == "Exact": calc_type.append("Optic") elif incar.get("ALGO", None) == "CHI": calc_type.append("Optic") else: calc_type.append("Static") elif incar.get("LOPTICS", False) is True or incar.get("ALGO", None) == "CHI": calc_type.append("Optic") elif incar.get("ISIF", 2) == 3 and incar.get("IBRION", 0) > 0: calc_type.append("Structure Optimization") elif incar.get("ISIF", 3) == 2 and incar.get("IBRION", 0) > 0: calc_type.append("Deformation") elif incar.get("IBRION", 1) == 0: calc_type.append("Molecular Dynamics") if len(calc_type) == 0: return TaskType("Unrecognized") return TaskType(" ".join(calc_type)) def calc_type( inputs: Dict[Literal["incar", "poscar", "kpoints", "potcar"], Dict], parameters: Dict, ) -> CalcType: """ Determine the calc type. Args: inputs: inputs dict with an incar, kpoints, potcar, and poscar dictionaries. parameters: Dictionary of VASP parameters from vasprun.xml. Returns: The calc type. """ rt = run_type(parameters).value tt = task_type(inputs).value return CalcType(f"{rt} {tt}") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/calculation.py0000644000175100001770000012005314673360562021144 0ustar00runnerdocker"""Core definitions of a VASP calculation documents.""" # mypy: ignore-errors import logging from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union import numpy as np from pydantic import BaseModel, Extra, Field from pymatgen.command_line.bader_caller import bader_analysis_from_path from pymatgen.command_line.chargemol_caller import ChargemolAnalysis from pymatgen.core.lattice import Lattice from pymatgen.core.structure import Structure from pymatgen.core.trajectory import Trajectory from pymatgen.electronic_structure.bandstructure import BandStructure from pymatgen.electronic_structure.core import OrbitalType from pymatgen.electronic_structure.dos import CompleteDos, Dos from pymatgen.io.vasp import ( BSVasprun, Kpoints, Locpot, Oszicar, Outcar, Poscar, Potcar, PotcarSingle, Vasprun, VolumetricData, ) from emmet.core.math import ListMatrix3D, Matrix3D, Vector3D from emmet.core.utils import ValueEnum from emmet.core.vasp.calc_types import ( CalcType, RunType, TaskType, calc_type, run_type, task_type, ) from emmet.core.vasp.task_valid import TaskState logger = logging.getLogger(__name__) class VaspObject(ValueEnum): """Types of VASP data objects.""" BANDSTRUCTURE = "bandstructure" DOS = "dos" CHGCAR = "chgcar" AECCAR0 = "aeccar0" AECCAR1 = "aeccar1" AECCAR2 = "aeccar2" TRAJECTORY = "trajectory" ELFCAR = "elfcar" WAVECAR = "wavecar" LOCPOT = "locpot" OPTIC = "optic" PROCAR = "procar" class StoreTrajectoryOption(ValueEnum): FULL = "full" PARTIAL = "partial" NO = "no" class CalculationBaseModel(BaseModel): """Wrapper around pydantic BaseModel with extra functionality.""" def get(self, key: Any, default_value: Optional[Any] = None) -> Any: return getattr(self, key, default_value) class PotcarSpec(BaseModel): """Document defining a VASP POTCAR specification.""" titel: Optional[str] = Field(None, description="TITEL field from POTCAR header") hash: Optional[str] = Field(None, description="md5 hash of POTCAR file") summary_stats: Optional[dict] = Field( None, description="summary statistics used to ID POTCARs without hashing" ) @classmethod def from_potcar_single(cls, potcar_single: PotcarSingle) -> "PotcarSpec": """ Get a PotcarSpec from a PotcarSingle. Parameters ---------- potcar_single A potcar single object. Returns ------- PotcarSpec A potcar spec. """ return cls( titel=potcar_single.symbol, hash=potcar_single.md5_header_hash, summary_stats=potcar_single._summary_stats, ) @classmethod def from_potcar(cls, potcar: Potcar) -> List["PotcarSpec"]: """ Get a list of PotcarSpecs from a Potcar. Parameters ---------- potcar A potcar object. Returns ------- list[PotcarSpec] A list of potcar specs. """ return [cls.from_potcar_single(p) for p in potcar] class CalculationInput(CalculationBaseModel): """Document defining VASP calculation inputs.""" incar: Optional[Dict[str, Any]] = Field( None, description="INCAR parameters for the calculation" ) kpoints: Optional[Union[Dict[str, Any], Kpoints]] = Field( None, description="KPOINTS for the calculation" ) nkpoints: Optional[int] = Field(None, description="Total number of k-points") potcar: Optional[List[str]] = Field( None, description="POTCAR symbols in the calculation" ) potcar_spec: Optional[List[PotcarSpec]] = Field( None, description="Title and hash of POTCAR files used in the calculation" ) potcar_type: Optional[List[str]] = Field( None, description="List of POTCAR functional types." ) parameters: Optional[dict] = Field(None, description="Parameters from vasprun") lattice_rec: Optional[Lattice] = Field( None, description="Reciprocal lattice of the structure" ) structure: Optional[Structure] = Field( None, description="Input structure for the calculation" ) is_hubbard: bool = Field( default=False, description="Is this a Hubbard +U calculation" ) hubbards: Optional[dict] = Field(None, description="The hubbard parameters used") @classmethod def from_vasprun(cls, vasprun: Vasprun) -> "CalculationInput": """ Create a VASP input document from a Vasprun object. Parameters ---------- vasprun A vasprun object. Returns ------- CalculationInput The input document. """ kpoints_dict = vasprun.kpoints.as_dict() kpoints_dict["actual_kpoints"] = [ {"abc": list(k), "weight": w} for k, w in zip(vasprun.actual_kpoints, vasprun.actual_kpoints_weights) ] parameters = dict(vasprun.parameters).copy() incar = dict(vasprun.incar) if metagga := incar.get("METAGGA"): # Per issue #960, the METAGGA tag is populated in the # INCAR field of vasprun.xml, and not parameters parameters.update({"METAGGA": metagga}) return cls( structure=vasprun.initial_structure, incar=incar, kpoints=kpoints_dict, nkpoints=len(kpoints_dict["actual_kpoints"]), potcar=[s.split()[0] for s in vasprun.potcar_symbols], potcar_spec=vasprun.potcar_spec, potcar_type=[s.split()[0] for s in vasprun.potcar_symbols], parameters=parameters, lattice_rec=vasprun.initial_structure.lattice.reciprocal_lattice, is_hubbard=vasprun.is_hubbard, hubbards=vasprun.hubbards, ) class RunStatistics(BaseModel): """Summary of the run statistics for a VASP calculation.""" average_memory: float = Field(0, description="The average memory used in kb") max_memory: float = Field(0, description="The maximum memory used in kb") elapsed_time: float = Field(0, description="The real time elapsed in seconds") system_time: float = Field(0, description="The system CPU time in seconds") user_time: float = Field( 0, description="The user CPU time spent by VASP in seconds" ) total_time: float = Field(0, description="The total CPU time for this calculation") cores: int = Field(0, description="The number of cores used by VASP") @classmethod def from_outcar(cls, outcar: Outcar) -> "RunStatistics": """ Create a run statistics document from an Outcar object. Parameters ---------- outcar An Outcar object. Returns ------- RunStatistics The run statistics. """ # rename these statistics mapping = { "Average memory used (kb)": "average_memory", "Maximum memory used (kb)": "max_memory", "Elapsed time (sec)": "elapsed_time", "System time (sec)": "system_time", "User time (sec)": "user_time", "Total CPU time used (sec)": "total_time", "cores": "cores", } run_stats = {} for k, v in mapping.items(): stat = outcar.run_stats.get(k) or 0 try: stat = float(stat) except ValueError: # sometimes the statistics are misformatted stat = 0 run_stats[v] = stat return cls(**run_stats) class FrequencyDependentDielectric(BaseModel): """Frequency-dependent dielectric data.""" real: Optional[List[List[float]]] = Field( None, description="Real part of the frequency dependent dielectric constant, given at" " each energy as 6 components according to XX, YY, ZZ, XY, YZ, ZX", ) imaginary: Optional[List[List[float]]] = Field( None, description="Imaginary part of the frequency dependent dielectric constant, " "given at each energy as 6 components according to XX, YY, ZZ, XY, " "YZ, ZX", ) energy: Optional[List[float]] = Field( None, description="Energies at which the real and imaginary parts of the dielectric" "constant are given", ) @classmethod def from_vasprun(cls, vasprun: Vasprun) -> "FrequencyDependentDielectric": """ Create a frequency-dependent dielectric calculation document from a vasprun. Parameters ---------- vasprun : Vasprun A vasprun object. Returns ------- FrequencyDependentDielectric A frequency-dependent dielectric document. """ energy, real, imag = vasprun.dielectric return cls(real=real, imaginary=imag, energy=energy) class ElectronPhononDisplacedStructures(BaseModel): """Document defining electron phonon displaced structures.""" temperatures: Optional[List[float]] = Field( None, description="The temperatures at which the electron phonon displacements " "were generated.", ) structures: Optional[List[Structure]] = Field( None, description="The displaced structures corresponding to each temperature." ) class ElectronicStep(BaseModel, extra=Extra.allow): # type: ignore """Document defining the information at each electronic step. Note, not all the information will be available at every step. """ alphaZ: Optional[float] = Field(None, description="The alpha Z term.") ewald: Optional[float] = Field(None, description="The ewald energy.") hartreedc: Optional[float] = Field(None, description="Negative Hartree energy.") XCdc: Optional[float] = Field(None, description="Negative exchange energy.") pawpsdc: Optional[float] = Field( None, description="Negative potential energy with exchange-correlation energy." ) pawaedc: Optional[float] = Field(None, description="The PAW double counting term.") eentropy: Optional[float] = Field(None, description="The entropy (T * S).") bandstr: Optional[float] = Field( None, description="The band energy (from eigenvalues)." ) atom: Optional[float] = Field(None, description="The atomic energy.") e_fr_energy: Optional[float] = Field(None, description="The free energy.") e_wo_entrp: Optional[float] = Field(None, description="The energy without entropy.") e_0_energy: Optional[float] = Field(None, description="The internal energy.") class IonicStep(BaseModel, extra=Extra.allow): # type: ignore """Document defining the information at each ionic step.""" e_fr_energy: Optional[float] = Field(None, description="The free energy.") e_wo_entrp: Optional[float] = Field(None, description="The energy without entropy.") e_0_energy: Optional[float] = Field(None, description="The internal energy.") forces: Optional[List[Vector3D]] = Field( None, description="The forces on each atom." ) stress: Optional[Matrix3D] = Field(None, description="The stress on the lattice.") electronic_steps: Optional[List[ElectronicStep]] = Field( None, description="The electronic convergence steps." ) structure: Optional[Structure] = Field( None, description="The structure at this step." ) class CalculationOutput(BaseModel): """Document defining VASP calculation outputs.""" energy: Optional[float] = Field( None, description="The final total DFT energy for the calculation" ) energy_per_atom: Optional[float] = Field( None, description="The final DFT energy per atom for the calculation" ) structure: Optional[Structure] = Field( None, description="The final structure from the calculation" ) efermi: Optional[float] = Field( None, description="The Fermi level from the calculation in eV" ) is_metal: Optional[bool] = Field(None, description="Whether the system is metallic") bandgap: Optional[float] = Field( None, description="The band gap from the calculation in eV" ) cbm: Optional[float] = Field( None, description="The conduction band minimum in eV (if system is not metallic)", ) vbm: Optional[float] = Field( None, description="The valence band maximum in eV (if system is not metallic)" ) is_gap_direct: Optional[bool] = Field( None, description="Whether the band gap is direct" ) direct_gap: Optional[float] = Field( None, description="Direct band gap in eV (if system is not metallic)" ) transition: Optional[str] = Field( None, description="Band gap transition given by CBM and VBM k-points" ) mag_density: Optional[float] = Field( None, description="The magnetization density, defined as total_mag/volume " "(units of A^-3)", ) dielectric: Optional[dict[str, list]] = Field( None, description="Energy of incident photons in ev and real and imaginary parts of the dielectric tensor", ) optical_absorption_coeff: Optional[list] = Field( None, description="Optical absorption coefficient in cm^-1" ) epsilon_static: Optional[ListMatrix3D] = Field( None, description="The high-frequency dielectric constant" ) epsilon_static_wolfe: Optional[ListMatrix3D] = Field( None, description="The high-frequency dielectric constant w/o local field effects", ) epsilon_ionic: Optional[ListMatrix3D] = Field( None, description="The ionic part of the dielectric constant" ) frequency_dependent_dielectric: Optional[FrequencyDependentDielectric] = Field( None, description="Frequency-dependent dielectric information from an LOPTICS " "calculation", ) ionic_steps: Optional[List[IonicStep]] = Field( None, description="Energy, forces, structure, etc. for each ionic step" ) locpot: Optional[Dict[int, List[float]]] = Field( None, description="Average of the local potential along the crystal axes" ) outcar: Optional[Dict[str, Any]] = Field( None, description="Information extracted from the OUTCAR file" ) force_constants: Optional[List[List[Matrix3D]]] = Field( None, description="Force constants between every pair of atoms in the structure" ) normalmode_frequencies: Optional[List[float]] = Field( None, description="Frequencies in THz of the normal modes at Gamma" ) normalmode_eigenvals: Optional[List[float]] = Field( None, description="Normal mode eigenvalues of phonon modes at Gamma. " "Note the unit changed between VASP 5 and 6.", ) normalmode_eigenvecs: Optional[List[List[Vector3D]]] = Field( None, description="Normal mode eigenvectors of phonon modes at Gamma" ) elph_displaced_structures: Optional[ElectronPhononDisplacedStructures] = Field( None, description="Electron-phonon displaced structures, generated by setting " "PHON_LMC = True.", ) dos_properties: Optional[Dict[str, Dict[str, Dict[str, float]]]] = Field( None, description="Element- and orbital-projected band properties (in eV) for the " "DOS. All properties are with respect to the Fermi level.", ) run_stats: Optional[RunStatistics] = Field( None, description="Summary of runtime statistics for this calculation" ) @classmethod def from_vasp_outputs( cls, vasprun: Vasprun, outcar: Optional[Outcar], contcar: Optional[Poscar], locpot: Optional[Locpot] = None, elph_poscars: Optional[List[Path]] = None, store_trajectory: StoreTrajectoryOption = StoreTrajectoryOption.NO, store_onsite_density_matrices: bool = False, ) -> "CalculationOutput": """ Create a VASP output document from VASP outputs. Parameters ---------- vasprun A Vasprun object. outcar An Outcar object. contcar A Poscar object. locpot A Locpot object. elph_poscars Path to displaced electron-phonon coupling POSCAR files generated using ``PHON_LMC = True``. store_trajectory Whether to store ionic steps as a pymatgen Trajectory object. Different value tune the amount of data from the ionic_steps stored in the Trajectory. If not NO, the `ionic_steps` field is left as None. store_onsite_density_matrices Whether to store the onsite density matrices from the OUTCAR. Returns ------- The VASP calculation output document. """ try: bandstructure = vasprun.get_band_structure(efermi="smart") bandgap_info = bandstructure.get_band_gap() electronic_output = dict( efermi=bandstructure.efermi, vbm=bandstructure.get_vbm()["energy"], cbm=bandstructure.get_cbm()["energy"], bandgap=bandgap_info["energy"], is_gap_direct=bandgap_info["direct"], is_metal=bandstructure.is_metal(), direct_gap=bandstructure.get_direct_band_gap(), transition=bandgap_info["transition"], ) except Exception: logger.warning("Error in parsing bandstructure") if vasprun.incar["IBRION"] == 1: logger.warning("VASP doesn't properly output efermi for IBRION == 1") electronic_output = {} freq_dependent_diel: Union[dict, FrequencyDependentDielectric] = {} try: freq_dependent_diel = FrequencyDependentDielectric.from_vasprun(vasprun) except KeyError: pass locpot_avg = None if locpot: locpot_avg = { i: locpot.get_average_along_axis(i).tolist() for i in range(3) } # parse force constants phonon_output = {} if hasattr(vasprun, "force_constants"): # convert eigenvalues to frequency eigs = -vasprun.normalmode_eigenvals frequencies = np.sqrt(np.abs(eigs)) * np.sign(eigs) # convert to THz in VASP 5 and lower; VASP 6 uses THz internally major_version = int(vasprun.vasp_version.split(".")[0]) if major_version < 6: frequencies *= 15.633302 phonon_output = dict( force_constants=vasprun.force_constants.tolist(), normalmode_frequencies=frequencies.tolist(), normalmode_eigenvals=vasprun.normalmode_eigenvals.tolist(), normalmode_eigenvecs=vasprun.normalmode_eigenvecs.tolist(), ) if outcar and contcar: outcar_dict = outcar.as_dict() outcar_dict.pop("run_stats") if not store_onsite_density_matrices and outcar.has_onsite_density_matrices: outcar_dict.pop("onsite_density_matrices") # use structure from CONTCAR as it is written to # greater precision than in the vasprun # but still need to copy the charge over structure = contcar.structure structure._charge = vasprun.final_structure._charge mag_density = ( outcar.total_mag / structure.volume if outcar.total_mag else None ) if len(outcar.magnetization) != 0: # patch calculated magnetic moments into final structure magmoms = [m["tot"] for m in outcar.magnetization] structure.add_site_property("magmom", magmoms) else: logger.warning( "No OUTCAR/CONTCAR available, some information will be missing from TaskDoc." ) outcar_dict = {} structure = vasprun.final_structure mag_density = None # Parse DOS properties dosprop_dict = ( _get_band_props(vasprun.complete_dos, structure) if hasattr(vasprun, "complete_dos") and vasprun.parameters["LORBIT"] >= 11 else {} ) elph_structures: Dict[str, List[Any]] = {} if elph_poscars is not None: elph_structures.update({"temperatures": [], "structures": []}) for elph_poscar in elph_poscars: temp = str(elph_poscar.name).replace("POSCAR.T=", "").replace(".gz", "") elph_structures["temperatures"].append(temp) elph_structures["structures"].append(Structure.from_file(elph_poscar)) return cls( structure=structure, energy=vasprun.final_energy, energy_per_atom=vasprun.final_energy / len(structure), mag_density=mag_density, epsilon_static=vasprun.epsilon_static or None, epsilon_static_wolfe=vasprun.epsilon_static_wolfe or None, epsilon_ionic=vasprun.epsilon_ionic or None, frequency_dependent_dielectric=freq_dependent_diel, elph_displaced_structures=elph_structures, dos_properties=dosprop_dict, ionic_steps=vasprun.ionic_steps if store_trajectory == StoreTrajectoryOption.NO else None, locpot=locpot_avg, outcar=outcar_dict, run_stats=RunStatistics.from_outcar(outcar) if outcar else None, **electronic_output, **phonon_output, ) class Calculation(CalculationBaseModel): """Full VASP calculation inputs and outputs.""" dir_name: Optional[str] = Field( None, description="The directory for this VASP calculation" ) vasp_version: Optional[str] = Field( None, description="VASP version used to perform the calculation" ) has_vasp_completed: Optional[Union[TaskState, bool]] = Field( None, description="Whether VASP completed the calculation successfully" ) input: Optional[CalculationInput] = Field( None, description="VASP input settings for the calculation" ) output: Optional[CalculationOutput] = Field( None, description="The VASP calculation output" ) completed_at: Optional[str] = Field( None, description="Timestamp for when the calculation was completed" ) task_name: Optional[str] = Field( None, description="Name of task given by custodian (e.g., relax1, relax2)" ) output_file_paths: Optional[Dict[str, str]] = Field( None, description="Paths (relative to dir_name) of the VASP output files " "associated with this calculation", ) bader: Optional[dict] = Field(None, description="Output from bader charge analysis") ddec6: Optional[dict] = Field(None, description="Output from DDEC6 charge analysis") run_type: Optional[RunType] = Field( None, description="Calculation run type (e.g., HF, HSE06, PBE)" ) task_type: Optional[TaskType] = Field( None, description="Calculation task type (e.g., Structure Optimization)." ) calc_type: Optional[CalcType] = Field( None, description="Return calculation type (run type + task_type)." ) @classmethod def from_vasp_files( cls, dir_name: Union[Path, str], task_name: str, vasprun_file: Union[Path, str], outcar_file: Union[Path, str], contcar_file: Union[Path, str], volumetric_files: List[str] = None, elph_poscars: List[Path] = None, oszicar_file: Optional[Union[Path, str]] = None, parse_dos: Union[str, bool] = False, parse_bandstructure: Union[str, bool] = False, average_locpot: bool = True, run_bader: bool = False, run_ddec6: Union[bool, str] = False, strip_bandstructure_projections: bool = False, strip_dos_projections: bool = False, store_volumetric_data: Optional[Tuple[str]] = None, store_trajectory: StoreTrajectoryOption = StoreTrajectoryOption.NO, store_onsite_density_matrices: bool = False, vasprun_kwargs: Optional[Dict] = None, ) -> Tuple["Calculation", Dict[VaspObject, Dict]]: """ Create a VASP calculation document from a directory and file paths. Parameters ---------- dir_name The directory containing the calculation outputs. task_name The task name. vasprun_file Path to the vasprun.xml file, relative to dir_name. outcar_file Path to the OUTCAR file, relative to dir_name. contcar_file Path to the CONTCAR file, relative to dir_name volumetric_files Path to volumetric files, relative to dir_name. elph_poscars Path to displaced electron-phonon coupling POSCAR files generated using ``PHON_LMC = True``, given relative to dir_name. oszicar_file Path to the OSZICAR file, relative to dir_name parse_dos Whether to parse the DOS. Can be: - "auto": Only parse DOS if there are no ionic steps (NSW = 0). - True: Always parse DOS. - False: Never parse DOS. parse_bandstructure How to parse the bandstructure. Can be: - "auto": Parse the bandstructure with projections for NSCF calculations and decide automatically if it's line or uniform mode. - "line": Parse the bandstructure as a line mode calculation with projections - True: Parse the bandstructure as a uniform calculation with projections . - False: Parse the band structure without projects and just store vbm, cbm, band_gap, is_metal and efermi rather than the full band structure object. average_locpot Whether to store the average of the LOCPOT along the crystal axes. run_bader : bool = False Whether to run bader on the charge density. run_ddec6 : Union[bool , str] = False Whether to run DDEC6 on the charge density. If a string, it's interpreted as the path to the atomic densities directory. Can also be set via the DDEC6_ATOMIC_DENSITIES_DIR environment variable. The files are available at https://sourceforge.net/projects/ddec/files. strip_dos_projections Whether to strip the element and site projections from the density of states. This can help reduce the size of DOS objects in systems with many atoms. strip_bandstructure_projections Whether to strip the element and site projections from the band structure. This can help reduce the size of DOS objects in systems with many atoms. store_volumetric_data Which volumetric files to store. store_trajectory Whether to store the ionic steps in a pymatgen Trajectory object and the amount of data to store from the ionic_steps. Can be: - FULL: Store the Trajectory. All the properties from the ionic_steps are stored in the frame_properties except for the Structure, to avoid redundancy. - PARTIAL: Store the Trajectory. All the properties from the ionic_steps are stored in the frame_properties except from Structure and ElectronicStep. - NO: Trajectory is not Stored. If not NO, :obj:'.CalculationOutput.ionic_steps' is set to None to reduce duplicating information. store_onsite_density_matrices Whether to store the onsite density matrices from the OUTCAR. vasprun_kwargs Additional keyword arguments that will be passed to the Vasprun init. Returns ------- Calculation A VASP calculation document. """ dir_name = Path(dir_name) vasprun_file = dir_name / vasprun_file outcar_file = dir_name / outcar_file contcar_file = dir_name / contcar_file vasprun_kwargs = vasprun_kwargs if vasprun_kwargs else {} volumetric_files = [] if volumetric_files is None else volumetric_files vasprun = Vasprun(vasprun_file, **vasprun_kwargs) outcar = Outcar(outcar_file) contcar = Poscar.from_file(contcar_file) completed_at = str(datetime.fromtimestamp(vasprun_file.stat().st_mtime)) output_file_paths = _get_output_file_paths(volumetric_files) vasp_objects: Dict[VaspObject, Any] = _get_volumetric_data( dir_name, output_file_paths, store_volumetric_data ) dos = _parse_dos(parse_dos, vasprun) if dos is not None: if strip_dos_projections: dos = Dos(dos.efermi, dos.energies, dos.densities) vasp_objects[VaspObject.DOS] = dos # type: ignore bandstructure = _parse_bandstructure(parse_bandstructure, vasprun) if bandstructure is not None: if strip_bandstructure_projections: bandstructure.projections = {} vasp_objects[VaspObject.BANDSTRUCTURE] = bandstructure # type: ignore bader = None if run_bader and VaspObject.CHGCAR in output_file_paths: suffix = "" if task_name == "standard" else f".{task_name}" bader = bader_analysis_from_path(dir_name, suffix=suffix) ddec6 = None if run_ddec6 and VaspObject.CHGCAR in output_file_paths: densities_path = run_ddec6 if isinstance(run_ddec6, (str, Path)) else None ddec6 = ChargemolAnalysis( path=dir_name, atomic_densities_path=densities_path ).summary locpot = None if average_locpot: if VaspObject.LOCPOT in vasp_objects: locpot = vasp_objects[VaspObject.LOCPOT] # type: ignore elif VaspObject.LOCPOT in output_file_paths: locpot_file = output_file_paths[VaspObject.LOCPOT] # type: ignore locpot = Locpot.from_file(dir_name / locpot_file) input_doc = CalculationInput.from_vasprun(vasprun) output_doc = CalculationOutput.from_vasp_outputs( vasprun, outcar, contcar, locpot=locpot, elph_poscars=elph_poscars, store_trajectory=store_trajectory, store_onsite_density_matrices=store_onsite_density_matrices, ) if store_trajectory != StoreTrajectoryOption.NO: exclude_from_trajectory = ["structure"] if store_trajectory == StoreTrajectoryOption.PARTIAL: exclude_from_trajectory.append("electronic_steps") frame_properties = [ IonicStep(**x).model_dump(exclude=exclude_from_trajectory) for x in vasprun.ionic_steps ] if oszicar_file: try: oszicar = Oszicar(oszicar_file) if "T" in oszicar.ionic_steps[0]: for frame_property, oszicar_is in zip( frame_properties, oszicar.ionic_steps ): frame_property["temperature"] = oszicar_is.get("T") except ValueError: # there can be errors in parsing the floats from OSZICAR pass traj = Trajectory.from_structures( [d["structure"] for d in vasprun.ionic_steps], frame_properties=frame_properties, constant_lattice=False, ) vasp_objects[VaspObject.TRAJECTORY] = traj # type: ignore # MD run if vasprun.parameters.get("IBRION", -1) == 0: if vasprun.parameters.get("NSW", 0) == vasprun.md_n_steps: has_vasp_completed = TaskState.SUCCESS else: has_vasp_completed = TaskState.FAILED # others else: has_vasp_completed = ( TaskState.SUCCESS if vasprun.converged else TaskState.FAILED ) return ( cls( dir_name=str(dir_name), task_name=task_name, vasp_version=vasprun.vasp_version, has_vasp_completed=has_vasp_completed, completed_at=completed_at, input=input_doc, output=output_doc, output_file_paths={ k.name.lower(): v for k, v in output_file_paths.items() }, bader=bader, ddec6=ddec6, run_type=run_type(input_doc.parameters), task_type=task_type(input_doc.model_dump()), calc_type=calc_type(input_doc.model_dump(), input_doc.parameters), ), vasp_objects, ) @classmethod def from_vasprun( cls, path: Union[Path, str], task_name: str = "Unknown vapsrun.xml", vasprun_kwargs: Optional[Dict] = None, ) -> Tuple["Calculation", Dict[VaspObject, Dict]]: """ Create a VASP calculation document from a directory and file paths. Parameters ---------- path Path to the vasprun.xml file. task_name The task name. vasprun_kwargs Additional keyword arguments that will be passed to the Vasprun init. Returns ------- Calculation A VASP calculation document. """ path = Path(path) vasprun_kwargs = vasprun_kwargs if vasprun_kwargs else {} vasprun = Vasprun(path, **vasprun_kwargs) completed_at = str(datetime.fromtimestamp(path.stat().st_mtime)) input_doc = CalculationInput.from_vasprun(vasprun) output_doc = CalculationOutput.from_vasp_outputs( vasprun, outcar=None, contcar=None, ) # MD run if vasprun.parameters.get("IBRION", -1) == 0: if vasprun.parameters.get("NSW", 0) == vasprun.nionic_steps: has_vasp_completed = TaskState.SUCCESS else: has_vasp_completed = TaskState.FAILED # others else: has_vasp_completed = ( TaskState.SUCCESS if vasprun.converged else TaskState.FAILED ) return cls( dir_name=str(path.resolve().parent), task_name=task_name, vasp_version=vasprun.vasp_version, has_vasp_completed=has_vasp_completed, completed_at=completed_at, input=input_doc, output=output_doc, output_file_paths={}, run_type=run_type(input_doc.parameters), task_type=task_type(input_doc.model_dump()), calc_type=calc_type(input_doc.model_dump(), input_doc.parameters), ) def _get_output_file_paths(volumetric_files: List[str]) -> Dict[VaspObject, str]: """ Get the output file paths for VASP output files from the list of volumetric files. Parameters ---------- volumetric_files A list of volumetric files associated with the calculation. Returns ------- Dict[VaspObject, str] A mapping between the VASP object type and the file path. """ output_file_paths = {} for vasp_object in VaspObject: # type: ignore for volumetric_file in volumetric_files: if vasp_object.name in str(volumetric_file): output_file_paths[vasp_object] = str(volumetric_file) return output_file_paths def _get_volumetric_data( dir_name: Path, output_file_paths: Dict[VaspObject, str], store_volumetric_data: Optional[Tuple[str]], ) -> Dict[VaspObject, VolumetricData]: """ Load volumetric data files from a directory. Parameters ---------- dir_name The directory containing the files. output_file_paths A dictionary mapping the data type to file path relative to dir_name. store_volumetric_data The volumetric data files to load. E.g., `("chgcar", "locpot")`. Provided as a list of strings note you can use either the keys or the values available in the `VaspObject` enum (e.g., "locpot" or "LOCPOT") are both valid. Returns ------- Dict[VaspObject, VolumetricData] A dictionary mapping the VASP object data type (`VaspObject.LOCPOT`, `VaspObject.CHGCAR`, etc) to the volumetric data object. """ from pymatgen.io.vasp import Chgcar if store_volumetric_data is None or len(store_volumetric_data) == 0: return {} volumetric_data = {} for file_type, file in output_file_paths.items(): if ( file_type.name not in store_volumetric_data and file_type.value not in store_volumetric_data ): continue try: # assume volumetric data is all in CHGCAR format volumetric_data[file_type] = Chgcar.from_file(dir_name / file) except Exception: raise ValueError(f"Failed to parse {file_type} at {file}.") return volumetric_data def _parse_dos(parse_mode: Union[str, bool], vasprun: Vasprun) -> Optional[Dos]: """Parse DOS. See Calculation.from_vasp_files for supported arguments.""" nsw = vasprun.incar.get("NSW", 0) dos = None if parse_mode is True or (parse_mode == "auto" and nsw < 1): dos = vasprun.complete_dos return dos def _parse_bandstructure( parse_mode: Union[str, bool], vasprun: Vasprun ) -> Optional[BandStructure]: """Parse band structure. See Calculation.from_vasp_files for supported arguments.""" vasprun_file = vasprun.filename if parse_mode == "auto": if vasprun.incar.get("ICHARG", 0) > 10: # NSCF calculation bs_vrun = BSVasprun(vasprun_file, parse_projected_eigen=True) try: # try parsing line mode bs = bs_vrun.get_band_structure(line_mode=True, efermi="smart") except Exception: # treat as a regular calculation bs = bs_vrun.get_band_structure(efermi="smart") else: # Not a NSCF calculation bs_vrun = BSVasprun(vasprun_file, parse_projected_eigen=False) bs = bs_vrun.get_band_structure(efermi="smart") # only save the bandstructure if not moving ions if vasprun.incar.get("NSW", 0) <= 1: return bs elif parse_mode: # legacy line/True behavior for bandstructure_mode bs_vrun = BSVasprun(vasprun_file, parse_projected_eigen=True) bs = bs_vrun.get_band_structure(line_mode=parse_mode == "line", efermi="smart") return bs return None def _get_band_props( complete_dos: CompleteDos, structure: Structure ) -> Dict[str, Dict[str, Dict[str, float]]]: """ Calculate band properties from a CompleteDos object and Structure. Parameters ---------- complete_dos A CompleteDos object. structure a pymatgen Structure object. Returns ------- Dict A dictionary of element and orbital-projected DOS properties. """ dosprop_dict: Dict[str, Dict[str, Dict[str, float]]] = {} for el in structure.composition.elements: el_name = el.name dosprop_dict[el_name] = {} for orb_type in [ OrbitalType.s, OrbitalType.p, OrbitalType.d, ]: orb_name = orb_type.name if ( (el.block == "s" and orb_name in ["p", "d", "f"]) or (el.block == "p" and orb_name in ["d", "f"]) or (el.block == "d" and orb_name == "f") ): continue dosprops = { "filling": complete_dos.get_band_filling(band=orb_type, elements=[el]), "center": complete_dos.get_band_center(band=orb_type, elements=[el]), "bandwidth": complete_dos.get_band_width(band=orb_type, elements=[el]), "skewness": complete_dos.get_band_skewness( band=orb_type, elements=[el] ), "kurtosis": complete_dos.get_band_kurtosis( band=orb_type, elements=[el] ), "upper_edge": complete_dos.get_upper_band_edge( band=orb_type, elements=[el] ), } dosprop_dict[el_name][orb_name] = dosprops return dosprop_dict ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/material.py0000644000175100001770000002477714673360562020464 0ustar00runnerdocker""" Core definition of a Materials Document """ from typing import Dict, List, Mapping, Optional from pydantic import BaseModel, Field from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.analysis.structure_matcher import StructureMatcher from pymatgen.entries.computed_entries import ComputedStructureEntry from emmet.core.base import EmmetMeta from emmet.core.material import MaterialsDoc as CoreMaterialsDoc from emmet.core.material import PropertyOrigin from emmet.core.settings import EmmetSettings from emmet.core.structure import StructureMetadata from emmet.core.tasks import TaskDoc from emmet.core.vasp.calc_types import CalcType, RunType, TaskType SETTINGS = EmmetSettings() class BlessedCalcs(BaseModel): GGA: Optional[ComputedStructureEntry] = None GGA_U: Optional[ComputedStructureEntry] = Field(None, alias="GGA+U") PBESol: Optional[ComputedStructureEntry] = None SCAN: Optional[ComputedStructureEntry] = None R2SCAN: Optional[ComputedStructureEntry] = None HSE: Optional[ComputedStructureEntry] = None class MaterialsDoc(CoreMaterialsDoc, StructureMetadata): calc_types: Mapping[str, CalcType] = Field( # type: ignore None, description="Calculation types for all the calculations that make up this material", ) task_types: Optional[Mapping[str, TaskType]] = Field( None, description="Task types for all the calculations that make up this material", ) run_types: Optional[Mapping[str, RunType]] = Field( None, description="Run types for all the calculations that make up this material", ) origins: Optional[List[PropertyOrigin]] = Field( None, description="Mappingionary for tracking the provenance of properties" ) entries: Optional[BlessedCalcs] = Field( None, description="Dictionary for tracking entries for VASP calculations" ) @classmethod def from_tasks( cls, task_group: List[TaskDoc], structure_quality_scores: Dict[ str, int ] = SETTINGS.VASP_STRUCTURE_QUALITY_SCORES, use_statics: bool = SETTINGS.VASP_USE_STATICS, commercial_license: bool = True, ) -> "MaterialsDoc": """ Converts a group of tasks into one material Args: task_group: List of task document structure_quality_scores: quality scores for various calculation types use_statics: Use statics to define a material commercial_license: Whether the data should be licensed with BY-C (otherwise BY-NC). """ if len(task_group) == 0: raise Exception("Must have more than one task in the group.") # Metadata last_updated = max(task.last_updated for task in task_group) created_at = min(task.completed_at for task in task_group) task_ids = list({task.task_id for task in task_group}) deprecated_tasks = {task.task_id for task in task_group if not task.is_valid} run_types = {task.task_id: task.run_type for task in task_group} task_types = {task.task_id: task.task_type for task in task_group} calc_types = {task.task_id: task.calc_type for task in task_group} structure_optimizations = [ task for task in task_group if task.task_type == TaskType.Structure_Optimization # type: ignore ] statics = [task for task in task_group if task.task_type == TaskType.Static] # type: ignore structure_calcs = ( structure_optimizations + statics if use_statics else structure_optimizations ) validity_check = [doc for doc in structure_calcs if doc.is_valid] if not validity_check: raise ValueError("Group must contain at least one valid task") # Material ID possible_mat_ids = [task.task_id for task in structure_optimizations] if use_statics: possible_mat_ids += [task.task_id for task in statics] material_id = min(possible_mat_ids) # Always prefer a static over a structure opt structure_task_quality_scores = {"Structure Optimization": 1, "Static": 2} def _structure_eval(task: TaskDoc): """ Helper function to order structures optimization and statics calcs by - Functional Type - Spin polarization - Special Tags - Energy """ task_run_type = task.run_type _SPECIAL_TAGS = ["LASPH", "ISPIN"] special_tags = sum( ( task.input.parameters.get(tag, False) if task.input.parameters else False ) for tag in _SPECIAL_TAGS ) return ( -1 * int(task.is_valid), -1 * structure_quality_scores.get(task_run_type.value, 0), -1 * structure_task_quality_scores.get(task.task_type.value, 0), -1 * special_tags, task.output.energy_per_atom, ) best_structure_calc = sorted(structure_calcs, key=_structure_eval)[0] structure = best_structure_calc.output.structure # Initial Structures initial_structures = [task.input.structure for task in task_group] sm = StructureMatcher( ltol=0.1, stol=0.1, angle_tol=0.1, scale=False, attempt_supercell=False ) initial_structures = [ group[0] for group in sm.group_structures(initial_structures) ] # Deprecated deprecated = all(task.task_id in deprecated_tasks for task in structure_calcs) deprecated = deprecated or best_structure_calc.task_id in deprecated_tasks # Origins origins = [ PropertyOrigin( name="structure", task_id=best_structure_calc.task_id, last_updated=best_structure_calc.last_updated, ) ] # Entries # **current materials docs must contain at last one GGA or GGA+U entry # Always prefer a static over a structure opt entry_task_quality_scores = {"Structure Optimization": 1, "Static": 2} def _entry_eval(task: TaskDoc): """ Helper function to order entries and statics calcs by - Spin polarization - Special Tags - Energy """ _SPECIAL_TAGS = ["LASPH", "ISPIN"] special_tags = sum( ( task.input.parameters.get(tag, False) if task.input.parameters else False ) for tag in _SPECIAL_TAGS ) return ( -1 * int(task.is_valid), -1 * entry_task_quality_scores.get(task.task_type.value, 0), -1 * special_tags, task.output.energy_per_atom, ) # Entries # **current materials docs must contain at last one GGA or GGA+U entry entries = {} all_run_types = set(run_types.values()) for rt in all_run_types: relevant_calcs = sorted( [doc for doc in structure_calcs if doc.run_type == rt and doc.is_valid], key=_entry_eval, ) if len(relevant_calcs) > 0: best_task_doc = relevant_calcs[0] entry = best_task_doc.structure_entry entry.data["task_id"] = entry.entry_id entry.data["material_id"] = material_id entry.entry_id = "{}-{}".format(material_id, rt.value) entry.parameters["is_hubbard"] = best_task_doc.input.is_hubbard entry.parameters["hubbards"] = best_task_doc.input.hubbards entries[rt] = entry if RunType.GGA not in entries and RunType.GGA_U not in entries: raise ValueError( "Individual material entry must contain at least one GGA or GGA+U calculation" ) # Builder meta and license builder_meta = EmmetMeta(license="BY-C" if commercial_license else "BY-NC") return cls.from_structure( structure=structure, material_id=material_id, last_updated=last_updated, created_at=created_at, task_ids=task_ids, calc_types=calc_types, run_types=run_types, task_types=task_types, initial_structures=initial_structures, deprecated=deprecated, deprecated_tasks=deprecated_tasks, origins=origins, entries=entries, builder_meta=builder_meta, ) @classmethod def construct_deprecated_material( cls, task_group: List[TaskDoc], commercial_license: bool = True, ) -> "MaterialsDoc": """ Converts a group of tasks into a deprecated material Args: task_group: List of task document commercial_license: Whether the data should be licensed with BY-C (otherwise BY-NC). """ if len(task_group) == 0: raise Exception("Must have more than one task in the group.") # Metadata last_updated = max(task.last_updated for task in task_group) created_at = min(task.completed_at for task in task_group) task_ids = list({task.task_id for task in task_group}) deprecated_tasks = {task.task_id for task in task_group} run_types = {task.task_id: task.run_type for task in task_group} task_types = {task.task_id: task.task_type for task in task_group} calc_types = {task.task_id: task.calc_type for task in task_group} # Material ID material_id = min([task.task_id for task in task_group]) # Choose any random structure for metadata structure = SpacegroupAnalyzer( task_group[0].output.structure, symprec=0.1 ).get_conventional_standard_structure() # Deprecated deprecated = True # Builder meta and license builder_meta = EmmetMeta(license="BY-C" if commercial_license else "BY-NC") return cls.from_structure( structure=structure, material_id=material_id, last_updated=last_updated, created_at=created_at, task_ids=task_ids, calc_types=calc_types, run_types=run_types, task_types=task_types, deprecated=deprecated, deprecated_tasks=deprecated_tasks, builder_meta=builder_meta, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/task_valid.py0000644000175100001770000001551114673360562020771 0ustar00runnerdocker# mypy: ignore-errors """ Core definition of a VASP Task Document """ from typing import Any, Dict, List, Union, Optional from pydantic import BaseModel, Field from pymatgen.analysis.structure_analyzer import oxide_type from pymatgen.core.structure import Structure from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.math import Matrix3D, Vector3D from emmet.core.task import BaseTaskDocument from emmet.core.structure import StructureMetadata from emmet.core.utils import ValueEnum from emmet.core.vasp.calc_types import RunType, calc_type, run_type, task_type class TaskState(ValueEnum): """ VASP Calculation State """ SUCCESS = "successful" FAILED = "failed" ERROR = "error" class InputSummary(BaseModel): """ Summary of inputs for a VASP calculation """ structure: Optional[Structure] = Field( None, description="The input structure object" ) parameters: Dict = Field( {}, description="Input parameters from VASPRUN for the last calculation in the series", ) pseudo_potentials: Dict = Field( {}, description="Summary of the pseudopotentials used in this calculation" ) potcar_spec: List[Dict] = Field( [], description="Potcar specification as a title and hash" ) is_hubbard: bool = Field(False, description="Is this a Hubbard +U calculation.") hubbards: Dict = Field({}, description="The hubbard parameters used.") class OutputSummary(BaseModel): """ Summary of the outputs for a VASP calculation """ structure: Optional[Structure] = Field( None, description="The output structure object" ) energy: Optional[float] = Field( None, description="The final total DFT energy for the last calculation" ) energy_per_atom: Optional[float] = Field( None, description="The final DFT energy per atom for the last calculation" ) bandgap: Optional[float] = Field( None, description="The DFT bandgap for the last calculation" ) forces: Optional[List[Vector3D]] = Field( None, description="Forces on atoms from the last calculation" ) stress: Optional[Matrix3D] = Field( None, description="Stress on the unitcell from the last calculation" ) class RunStatistics(BaseModel): """ Summary of the Run statistics for a VASP calculation """ average_memory: Optional[float] = Field( None, description="The average memory used in kb" ) max_memory: Optional[float] = Field( None, description="The maximum memory used in kb" ) elapsed_time: Optional[float] = Field( None, description="The real time elapsed in seconds" ) system_time: Optional[float] = Field( None, description="The system CPU time in seconds" ) user_time: Optional[float] = Field( None, description="The user CPU time spent by VASP in seconds" ) total_time: Optional[float] = Field( None, description="The total CPU time for this calculation" ) cores: Optional[Union[int, str]] = Field( None, description="The number of cores used by VASP (some clusters print `mpi-ranks` here)", ) class TaskDocument(BaseTaskDocument, StructureMetadata): """ Definition of VASP Task Document """ calc_code: str = "VASP" run_stats: Dict[str, RunStatistics] = Field( {}, description="Summary of runtime statistics for each calculation in this task", ) is_valid: bool = Field( True, description="Whether this task document passed validation or not" ) input: InputSummary = Field(InputSummary()) output: OutputSummary = Field(OutputSummary()) state: Optional[TaskState] = Field(None, description="State of this calculation") orig_inputs: Dict[str, Any] = Field( {}, description="Summary of the original VASP inputs" ) calcs_reversed: List[Dict] = Field( [], description="The 'raw' calculation docs used to assembled this task" ) tags: Union[List[str], None] = Field( [], description="Metadata tags for this task document" ) warnings: Optional[List[str]] = Field( None, description="Any warnings related to this property" ) @property def run_type(self) -> RunType: params = self.calcs_reversed[0].get("input", {}).get("parameters", {}) incar = self.calcs_reversed[0].get("input", {}).get("incar", {}) return run_type({**params, **incar}) @property def task_type(self): return task_type(self.orig_inputs) @property def calc_type(self): inputs = ( self.calcs_reversed[0].get("input", {}) if len(self.calcs_reversed) > 0 else self.orig_inputs ) params = self.calcs_reversed[0].get("input", {}).get("parameters", {}) incar = self.calcs_reversed[0].get("input", {}).get("incar", {}) return calc_type(inputs, {**params, **incar}) @property def entry(self) -> ComputedEntry: """Turns a Task Doc into a ComputedEntry""" entry_dict = { "correction": 0.0, "entry_id": self.task_id, "composition": self.output.structure.composition, "energy": self.output.energy, "parameters": { "potcar_spec": self.input.potcar_spec, "is_hubbard": self.input.is_hubbard, "hubbards": self.input.hubbards, # This is done to be compatible with MontyEncoder for the ComputedEntry "run_type": str(self.run_type), }, "data": { "oxide_type": oxide_type(self.output.structure), "aspherical": self.input.parameters.get("LASPH", True), "last_updated": self.last_updated, }, } return ComputedEntry.from_dict(entry_dict) @property def structure_entry(self) -> ComputedStructureEntry: """Turns a Task Doc into a ComputedStructureEntry""" entry_dict = { "correction": 0.0, "entry_id": self.task_id, "composition": self.output.structure.composition, "energy": self.output.energy, "parameters": { "potcar_spec": self.input.potcar_spec, "is_hubbard": self.input.is_hubbard, "hubbards": self.input.hubbards, # This is done to be compatible with MontyEncoder for the ComputedEntry "run_type": str(self.run_type), }, "data": { "oxide_type": oxide_type(self.output.structure), "aspherical": self.input.parameters.get("LASPH", False), "last_updated": self.last_updated, }, "structure": self.output.structure, } return ComputedStructureEntry.from_dict(entry_dict) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/vasp/validation.py0000644000175100001770000004235614673360562021011 0ustar00runnerdockerfrom datetime import datetime from typing import Dict, List, Union, Optional import numpy as np from pydantic import ConfigDict, Field, ImportString from pymatgen.core.structure import Structure from pymatgen.io.vasp.inputs import Kpoints from pymatgen.io.vasp.sets import VaspInputSet from emmet.core.settings import EmmetSettings from emmet.core.base import EmmetBaseModel from emmet.core.mpid import MPID from emmet.core.utils import DocEnum from emmet.core.tasks import TaskDoc from emmet.core.vasp.calc_types.enums import CalcType, TaskType from emmet.core.vasp.task_valid import TaskDocument SETTINGS = EmmetSettings() class DeprecationMessage(DocEnum): MANUAL = "M", "Manual deprecation" SYMMETRY = ( "S001", "Could not determine crystalline space group, needed for input set check.", ) KPTS = "C001", "Too few KPoints" KSPACING = "C002", "KSpacing not high enough" ENCUT = "C002", "ENCUT too low" FORCES = "C003", "Forces too large" MAG = "C004", "At least one site magnetization is too large" POTCAR = ( "C005", "At least one POTCAR used does not agree with the pymatgen input set", ) CONVERGENCE = "E001", "Calculation did not converge" MAX_SCF = "E002", "Max SCF gradient too large" LDAU = "I001", "LDAU Parameters don't match the inputset" SET = ("I002", "Cannot validate due to missing or problematic input set") UNKNOWN = "U001", "Cannot validate due to unknown calc type" class ValidationDoc(EmmetBaseModel): """ Validation document for a VASP calculation """ task_id: MPID = Field(..., description="The task_id for this validation document") valid: bool = Field(False, description="Whether this task is valid or not") last_updated: datetime = Field( description="Last updated date for this document", default_factory=datetime.utcnow, ) reasons: Optional[List[Union[DeprecationMessage, str]]] = Field( None, description="List of deprecation tags detailing why this task isn't valid" ) warnings: List[str] = Field( [], description="List of potential warnings about this calculation" ) data: Dict = Field( description="Dictioary of data used to perform validation." " Useful for post-mortem analysis" ) model_config = ConfigDict(extra="allow") nelements: Optional[int] = Field(None, description="Number of elements.") symmetry_number: Optional[int] = Field( None, title="Space Group Number", description="The spacegroup number for the lattice.", ) @classmethod def from_task_doc( cls, task_doc: Union[TaskDoc, TaskDocument], kpts_tolerance: float = SETTINGS.VASP_KPTS_TOLERANCE, kspacing_tolerance: float = SETTINGS.VASP_KSPACING_TOLERANCE, input_sets: Dict[str, ImportString] = SETTINGS.VASP_DEFAULT_INPUT_SETS, LDAU_fields: List[str] = SETTINGS.VASP_CHECKED_LDAU_FIELDS, max_allowed_scf_gradient: float = SETTINGS.VASP_MAX_SCF_GRADIENT, max_magmoms: Dict[str, float] = SETTINGS.VASP_MAX_MAGMOM, potcar_stats: Optional[Dict[CalcType, Dict[str, str]]] = None, ) -> "ValidationDoc": """ Determines if a calculation is valid based on expected input parameters from a pymatgen inputset Args: task_doc: the task document to process kpts_tolerance: the tolerance to allow kpts to lag behind the input set settings kspacing_tolerance: the tolerance to allow kspacing to lag behind the input set settings input_sets: a dictionary of task_types -> pymatgen input set for validation pseudo_dir: directory of pseudopotential directory to ensure correct hashes LDAU_fields: LDAU fields to check for consistency max_allowed_scf_gradient: maximum uphill gradient allowed for SCF steps after the initial equillibriation period potcar_stats: Dictionary of potcar stat data. Mapping is calculation type -> potcar symbol -> hash value. """ nelements = task_doc.nelements or None symmetry_number = task_doc.symmetry.number if task_doc.symmetry else None bandgap = task_doc.output.bandgap calc_type = task_doc.calc_type task_type = task_doc.task_type run_type = task_doc.run_type inputs = task_doc.orig_inputs chemsys = task_doc.chemsys calcs_reversed = [ calc if not hasattr(calc, "model_dump") else calc.model_dump() for calc in task_doc.calcs_reversed ] if calcs_reversed[0].get("input", {}).get("structure", None): structure = calcs_reversed[0]["input"]["structure"] else: structure = task_doc.input.structure or task_doc.output.structure if isinstance(structure, dict): structure = Structure.from_dict(structure) reasons = [] data = {} # type: ignore warnings: List[str] = [] if str(calc_type) in input_sets: try: valid_input_set = _get_input_set( run_type, task_type, calc_type, structure, input_sets, bandgap ) except (TypeError, KeyError, ValueError): reasons.append(DeprecationMessage.SET) valid_input_set = None try: # Sometimes spglib can't determine space group with the default # `symprec` and `angle_tolerance`. In these cases, # `Structure.get_space_group_info()` fails valid_input_set.structure.get_space_group_info() except Exception: reasons.append(DeprecationMessage.SYMMETRY) valid_input_set = None if valid_input_set: # Checking POTCAR summary_stats if a directory is supplied if potcar_stats: if _potcar_stats_check(task_doc, potcar_stats): if task_type in [ TaskType.NSCF_Line, TaskType.NSCF_Uniform, TaskType.DFPT_Dielectric, TaskType.Dielectric, ]: warnings.append(DeprecationMessage.POTCAR.__doc__) # type: ignore else: reasons.append(DeprecationMessage.POTCAR) # Checking K-Points # Calculations that use KSPACING will not have a .kpoints attr if task_type != TaskType.NSCF_Line: # Not validating k-point data for line-mode calculations as constructing # the k-path is too costly for the builder and the uniform input set is used. if valid_input_set.kpoints is not None: if _kpoint_check( valid_input_set, inputs, calcs_reversed, data, kpts_tolerance, ): reasons.append(DeprecationMessage.KPTS) else: # warnings _kspacing_warnings( valid_input_set, inputs, data, warnings, kspacing_tolerance ) # warn, but don't invalidate if wrong ISMEAR valid_ismear = valid_input_set.incar.get("ISMEAR", 1) incar = inputs.get("incar", {}) curr_ismear = incar.get("ISMEAR", 1) if curr_ismear != valid_ismear: warnings.append( f"Inappropriate smearing settings. Set to {curr_ismear}," f" but should be {valid_ismear}" ) # Checking ENCUT encut = incar.get("ENCUT") valid_encut = valid_input_set.incar["ENCUT"] data["encut_ratio"] = float(encut) / valid_encut # type: ignore if data["encut_ratio"] < 1: reasons.append(DeprecationMessage.ENCUT) # U-value checks if _u_value_checks(task_doc, valid_input_set, warnings): reasons.append(DeprecationMessage.LDAU) # Check the max upwards SCF step if _scf_upward_check( calcs_reversed, inputs, data, max_allowed_scf_gradient, warnings ): reasons.append(DeprecationMessage.MAX_SCF) # Check for Am and Po elements. These currently do not have proper elemental entries # and will not get treated properly by the thermo builder. if ("Am" in chemsys) or ("Po" in chemsys): reasons.append(DeprecationMessage.MANUAL) # Check for magmom anomalies for specific elements if _magmom_check(calcs_reversed, structure, max_magmoms=max_magmoms): reasons.append(DeprecationMessage.MAG) else: if "Unrecognized" in str(calc_type): reasons.append(DeprecationMessage.UNKNOWN) else: reasons.append(DeprecationMessage.SET) doc = ValidationDoc( task_id=task_doc.task_id, calc_type=calc_type, run_type=task_doc.run_type, valid=len(reasons) == 0, reasons=reasons, data=data, warnings=warnings, nelements=nelements, symmetry_number=symmetry_number, ) return doc def _get_input_set(run_type, task_type, calc_type, structure, input_sets, bandgap): # Ensure inputsets get proper additional input values if "SCAN" in run_type.value: valid_input_set: VaspInputSet = input_sets[str(calc_type)](structure, bandgap=bandgap) # type: ignore elif task_type == TaskType.NSCF_Uniform or task_type == TaskType.NSCF_Line: # Constructing the k-path for line-mode calculations is too costly, so # the uniform input set is used instead and k-points are not checked. valid_input_set = input_sets[str(calc_type)](structure, mode="uniform") elif task_type == TaskType.NMR_Electric_Field_Gradient: valid_input_set = input_sets[str(calc_type)](structure, mode="efg") else: valid_input_set = input_sets[str(calc_type)](structure) return valid_input_set def _scf_upward_check(calcs_reversed, inputs, data, max_allowed_scf_gradient, warnings): skip = abs(inputs.get("incar", {}).get("NLEMDL", -5)) - 1 energies = [ d["e_fr_energy"] for d in calcs_reversed[0]["output"]["ionic_steps"][-1]["electronic_steps"] ] if len(energies) > skip: max_gradient = np.max(np.gradient(energies)[skip:]) data["max_gradient"] = max_gradient if max_gradient > max_allowed_scf_gradient: return True else: warnings.append( "Not enough electronic steps to compute valid gradient" " and compare with max SCF gradient tolerance" ) return False def _u_value_checks(task_doc, valid_input_set, warnings): # NOTE: Reverting to old method of just using input.hubbards which is wrong in many instances input_hubbards = {} if task_doc.input.hubbards is None else task_doc.input.hubbards if valid_input_set.incar.get("LDAU", False) or len(input_hubbards) > 0: # Assemble required input_set LDAU params into dictionary input_set_hubbards = dict( zip( valid_input_set.poscar.site_symbols, valid_input_set.incar.get("LDAUU", []), ) ) all_elements = list(set(input_set_hubbards.keys()) | set(input_hubbards.keys())) diff_ldau_params = { el: (input_set_hubbards.get(el, 0), input_hubbards.get(el, 0)) for el in all_elements if not np.allclose(input_set_hubbards.get(el, 0), input_hubbards.get(el, 0)) } if len(diff_ldau_params) > 0: warnings.extend( [ f"U-value for {el} should be {good} but was {bad}" for el, (good, bad) in diff_ldau_params.items() ] ) return True return False def _kpoint_check(input_set, inputs, calcs_reversed, data, kpts_tolerance): """ Checks to make sure the total number of kpoints is correct """ valid_num_kpts = input_set.kpoints.num_kpts or np.prod(input_set.kpoints.kpts[0]) if calcs_reversed: input_dict = calcs_reversed[0].get("input", {}) if not input_dict: input_dict = inputs else: input_dict = inputs kpoints = input_dict.get("kpoints", {}) if isinstance(kpoints, Kpoints): kpoints = kpoints.as_dict() elif kpoints is None: kpoints = {} num_kpts = kpoints.get("nkpoints", 0) or np.prod(kpoints.get("kpoints", [1, 1, 1])) data["kpts_ratio"] = num_kpts / valid_num_kpts return data["kpts_ratio"] < kpts_tolerance def _kspacing_warnings(input_set, inputs, data, warnings, kspacing_tolerance): """ Issues warnings based on KSPACING values """ valid_kspacing = input_set.incar.get("KSPACING", 0) if kspacing := inputs.get("incar", {}).get("KSPACING"): data["kspacing_delta"] = kspacing - valid_kspacing # larger KSPACING means fewer k-points if data["kspacing_delta"] > kspacing_tolerance: warnings.append( f"KSPACING is greater than input set: {data['kspacing_delta']}" f" lower than {kspacing_tolerance} " ) elif data["kspacing_delta"] < kspacing_tolerance: warnings.append( f"KSPACING is lower than input set: {data['kspacing_delta']}" f" lower than {kspacing_tolerance} " ) def _potcar_stats_check(task_doc, potcar_stats: dict): """ Checks to make sure the POTCAR summary stats is equal to the correct value from the pymatgen input set. """ data_tol = 1.0e-6 try: potcar_details = task_doc.calcs_reversed[0].model_dump()["input"]["potcar_spec"] except KeyError: # Assume it is an old calculation without potcar_spec data and treat it as passing POTCAR hash check return False use_legacy_hash_check = False if any(entry.get("summary_stats", None) is None for entry in potcar_details): # potcar_spec doesn't include summary_stats kwarg needed to check potcars # fall back to header hash checking use_legacy_hash_check = True all_match = True for entry in potcar_details: if not entry["titel"]: all_match = False break symbol = entry["titel"].split(" ")[1] ref_summ_stats = potcar_stats[str(task_doc.calc_type)].get(symbol, None) if not ref_summ_stats: # Symbol differs from reference set - deprecate all_match = False break if use_legacy_hash_check: all_match = any( all( entry[key] == ref_stat[key] for key in ( "hash", "titel", ) ) for ref_stat in ref_summ_stats ) else: all_match = False for ref_stat in ref_summ_stats: key_match = all( set(ref_stat["keywords"][key]) == set(entry["summary_stats"]["keywords"][key]) for key in ["header", "data"] ) data_match = False if key_match: data_match = all( abs( ref_stat["stats"][key][stat] - entry["summary_stats"]["stats"][key][stat] ) < data_tol for stat in ["MEAN", "ABSMEAN", "VAR", "MIN", "MAX"] for key in ["header", "data"] ) all_match = key_match and data_match if all_match: # Found at least one match to reference POTCAR summary stats, # that suffices for the check break if not all_match: break return not all_match def _magmom_check( calcs_reversed: list, structure: Structure, max_magmoms: dict[str, float] ): """ Checks for maximum magnetization values for specific elements. Returns True if the maximum absolute value outlined below is exceded for the associated element. """ if (outcar := calcs_reversed[0]["output"]["outcar"]) and ( mag_info := outcar.get("magnetization", []) ): return any( abs(mag_info[isite].get("tot", 0.0)) > abs(max_magmoms.get(site.label, np.inf)) for isite, site in enumerate(structure) ) return False def _get_unsorted_symbol_set(structure: Structure): """ Have to build structure_symbol set manually to ensure we get the right order since pymatgen sorts its symbol_set list. """ return list( { str(sp): 1 for site in structure for sp, v in site.species.items() if v != 0 }.keys() ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/xas.py0000644000175100001770000002172514673360562016476 0ustar00runnerdockerimport warnings from itertools import groupby from typing import List import numpy as np from pydantic import Field from pymatgen.analysis.xas.spectrum import XAS, site_weighted_spectrum from pymatgen.core.periodic_table import Element from pymatgen.symmetry.analyzer import SpacegroupAnalyzer from emmet.core.feff.task import TaskDocument from emmet.core.mpid import MPID from emmet.core.spectrum import SpectrumDoc from emmet.core.utils import ValueEnum class Edge(ValueEnum): """ The interaction edge for XAS There are 2n-1 sub-components to each edge where K: n=1 L: n=2 M: n=3 N: n=4 """ K = "K" L2 = "L2" L3 = "L3" L2_3 = "L2,3" class Type(ValueEnum): """ The type of XAS Spectrum XANES - Just the near-edge region EXAFS - Just the extended region XAFS - Fully stitched XANES + EXAFS """ XANES = "XANES" EXAFS = "EXAFS" XAFS = "XAFS" class XASDoc(SpectrumDoc): """ Document describing a XAS Spectrum. """ spectrum_name: str = "XAS" spectrum: XAS task_ids: List[str] = Field( ..., title="Calculation IDs", description="List of Calculations IDs used to make this XAS spectrum.", ) absorbing_element: Element = Field(..., description="Absoring element.") spectrum_type: Type = Field(..., description="XAS spectrum type.") edge: Edge = Field( ..., title="Absorption Edge", description="The interaction edge for XAS." ) @classmethod def from_spectrum( cls, xas_spectrum: XAS, material_id: MPID, **kwargs, ): spectrum_type = xas_spectrum.spectrum_type el = xas_spectrum.absorbing_element edge = xas_spectrum.edge xas_id = f"{material_id}-{spectrum_type}-{el}-{edge}" if xas_spectrum.absorbing_index is not None: xas_id += f"-{xas_spectrum.absorbing_index}" return super().from_structure( meta_structure=xas_spectrum.structure, material_id=material_id, spectrum=xas_spectrum, edge=edge, spectrum_type=spectrum_type, absorbing_element=xas_spectrum.absorbing_element, spectrum_id=xas_id, **kwargs, ) @classmethod def from_task_docs( cls, all_tasks: List[TaskDocument], material_id: MPID, num_samples: int = 200 ) -> List["XASDoc"]: """ Converts a set of FEFF Task Documents into XASDocs by merging XANES + EXAFS into XAFS spectra first and then merging along equivalent elements to get element averaged spectra Args: all_tasks: FEFF Task documents that have matching structure material_id: The material ID for the generated XASDocs num_samples: number of sampled points for site-weighted averaging """ all_spectra: List[XAS] = [] averaged_spectra: List[XAS] = [] # This is a hack using extra attributes within this function to carry some extra information # without generating new objects for task in all_tasks: spectrum = task.xas_spectrum spectrum.last_updated = task.last_updated spectrum.task_ids = [task.task_id] all_spectra.append(spectrum) # Pre sort by keys to remove needing to sort in the group by stage all_spectra = sorted( all_spectra, key=lambda x: ( x.absorbing_index, x.edge, x.spectrum_type, -1 * x.last_updated, ), ) # Generate Merged Spectra # Dictionary of all site to spectra mapping sites_to_spectra = { index: list(group) for index, group in groupby( all_spectra, key=lambda x: x.absorbing_index, ) } # perform spectra merging for site, spectra in sites_to_spectra.items(): type_to_spectra = { index: list(group) for index, group in groupby( spectra, key=lambda x: (x.edge, x.spectrum_type), ) } # Make K-edge XAFS spectra by merging XANES + EXAFS if ("K", "XANES") in type_to_spectra and ("K", "EXAFS") in type_to_spectra: xanes = type_to_spectra[("K", "XANES")][-1] exafs = type_to_spectra[("K", "EXAFS")][-1] try: total_spectrum = xanes.stitch(exafs, mode="XAFS") total_spectrum.absorbing_index = site total_spectrum.task_ids = xanes.task_ids + exafs.task_ids # type: ignore[attr-defined] all_spectra.append(total_spectrum) except ValueError as e: warnings.warn(f"Warning during spectral merging in XASDoC: {e}") # Make L2,3 XANES spectra by merging L2 and L3 spectra if ("L2", "XANES") in type_to_spectra and ( "L3", "XANES", ) in type_to_spectra: l2 = type_to_spectra[("L2", "XANES")][-1] l3 = type_to_spectra[("L3", "XANES")][-1] try: total_spectrum = l2.stitch(l3, mode="L23") total_spectrum.absorbing_index = site total_spectrum.task_ids = l2.task_ids + l3.task_ids # type: ignore[attr-defined] all_spectra.append(total_spectrum) except ValueError as e: warnings.warn(f"Warning during spectral merging in XASDoC: {e}") # We don't have L2,3 EXAFS yet so don't have any merging # Site-weighted averaging spectra_to_average = [ list(group) for _, group in groupby( sorted( all_spectra, key=lambda x: (x.absorbing_element, x.edge, x.spectrum_type), ), key=lambda x: (x.absorbing_element, x.edge, x.spectrum_type), ) ] for relevant_spectra in spectra_to_average: if len(relevant_spectra) > 0 and not _is_missing_sites(relevant_spectra): if len(relevant_spectra) > 1: try: avg_spectrum = site_weighted_spectrum( relevant_spectra, num_samples=num_samples ) avg_spectrum.task_ids = [ # type: ignore[attr-defined] id for spectrum in relevant_spectra for id in spectrum.task_ids ] avg_spectrum.last_updated = max( # type: ignore[attr-defined, type-var] [spectrum.last_updated for spectrum in relevant_spectra] ) averaged_spectra.append(avg_spectrum) except ValueError as e: warnings.warn( f"Warning during site-weighted averaging in XASDoC: {e}" ) else: averaged_spectra.append(relevant_spectra[0]) spectra_docs = [] for spectrum in averaged_spectra: doc = XASDoc.from_spectrum( xas_spectrum=spectrum, material_id=material_id, task_ids=spectrum.task_ids, last_updated=spectrum.last_updated, ) spectra_docs.append(doc) return spectra_docs def _is_missing_sites(spectra: List[XAS]): """ Determines if the collection of spectra are missing any indicies for the given element """ structure = spectra[0].structure element = spectra[0].absorbing_element # Find missing symmeterically inequivalent sites symm_sites = SymmSites(structure) absorption_indicies = {spectrum.absorbing_index for spectrum in spectra} missing_site_spectra_indicies = ( set(structure.indices_from_symbol(element)) - absorption_indicies ) for site_index in absorption_indicies: missing_site_spectra_indicies -= set( symm_sites.get_equivalent_site_indices(site_index) ) return len(missing_site_spectra_indicies) != 0 class SymmSites: """ Wrapper to get equivalent site indicies from SpacegroupAnalyzer """ def __init__(self, structure): self.structure = structure sa = SpacegroupAnalyzer(self.structure) symm_data = sa.get_symmetry_dataset() # equivalency mapping for the structure # i'th site in the input structure equivalent to eq_atoms[i]'th site self.eq_atoms = symm_data["equivalent_atoms"] def get_equivalent_site_indices(self, i): """ Site indices in the structure that are equivalent to the given site i. """ rv = np.argwhere(self.eq_atoms == self.eq_atoms[i]).squeeze().tolist() if isinstance(rv, int): rv = [rv] return rv ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/emmet/core/xrd.py0000644000175100001770000000652114673360562016475 0ustar00runnerdockerfrom typing import Dict, Optional import numpy as np from pydantic import model_validator, Field from pymatgen.analysis.diffraction.xrd import ( WAVELENGTHS, DiffractionPattern, XRDCalculator, ) from pymatgen.core import Structure from pymatgen.core.periodic_table import Element from emmet.core.mpid import MPID from emmet.core.spectrum import SpectrumDoc from emmet.core.utils import ValueEnum class Edge(ValueEnum): K_Alpha = "Ka" K_Alpha1 = "Ka1" K_Alpha2 = "Ka2" K_Beta = "Kb" K_Beta1 = "Kb1" K_Beta2 = "Kb2" class XRDDoc(SpectrumDoc): """ Document describing a XRD Diffraction Pattern """ spectrum_name: str = "XRD" spectrum: DiffractionPattern min_two_theta: float max_two_theta: float wavelength: float = Field(..., description="Wavelength for the diffraction source.") target: Optional[Element] = Field( None, description="Target element for the diffraction source." ) edge: Optional[Edge] = Field( None, description="Atomic edge for the diffraction source." ) @model_validator(mode="before") @classmethod def get_target_and_edge(cls, values: Dict): print("Validations") # Only do this if neither target not edge is defined if "target" not in values and "edge" not in values: try: pymatgen_wavelength = next( k for k, v in WAVELENGTHS.items() if np.allclose(values["wavelength"], v) ) values["target"] = pymatgen_wavelength[:2] values["edge"] = pymatgen_wavelength[2:] except Exception: return values return values @classmethod def from_structure( # type: ignore[override] cls, material_id: MPID, spectrum_id: str, structure: Structure, wavelength: float, min_two_theta=0, max_two_theta=180, symprec=0.1, **kwargs, ) -> "XRDDoc": calc = XRDCalculator(wavelength=wavelength, symprec=symprec) pattern = calc.get_pattern( structure, two_theta_range=(min_two_theta, max_two_theta) ) return super().from_structure( material_id=material_id, spectrum_id=spectrum_id, meta_structure=structure, spectrum=pattern, wavelength=wavelength, min_two_theta=min_two_theta, max_two_theta=max_two_theta, **kwargs, ) @classmethod def from_target( cls, material_id: MPID, structure: Structure, target: Element, edge: Edge, min_two_theta=0, max_two_theta=180, symprec=0.1, **kwargs, ) -> "XRDDoc": if f"{target}{edge}" not in WAVELENGTHS: raise ValueError(f"{target}{edge} not in pymatgen wavelenghts dictionarty") wavelength = WAVELENGTHS[f"{target}{edge}"] spectrum_id = f"{material_id}-{target}{edge}" return cls.from_structure( material_id=material_id, spectrum_id=spectrum_id, structure=structure, wavelength=wavelength, target=target, edge=edge, min_two_theta=min_two_theta, max_two_theta=max_two_theta, **kwargs, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0532901 emmet-core-0.84.2/emmet_core.egg-info/0000755000175100001770000000000014673360566017100 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865781.0 emmet-core-0.84.2/emmet_core.egg-info/PKG-INFO0000644000175100001770000000156514673360565020203 0ustar00runnerdockerMetadata-Version: 2.1 Name: emmet-core Version: 0.84.2 Summary: Core Emmet Library Home-page: https://github.com/materialsproject/emmet Author: The Materials Project Author-email: feedback@materialsproject.org License: modified BSD Platform: UNKNOWN Requires-Python: >=3.9 Description-Content-Type: text/markdown Provides-Extra: all Provides-Extra: ml Provides-Extra: test Provides-Extra: docs # ![Emmet](docs/images/logo_w_text.svg) [![Pytest Status](https://github.com/materialsproject/emmet/workflows/testing/badge.svg)](https://github.com/materialsproject/emmet/actions?query=workflow%3Atesting) [![Code Coverage](https://codecov.io/gh/materialsproject/emmet/branch/main/graph/badge.svg)](https://codecov.io/gh/materialsproject/emmet) The Materials API Toolkit for the Materials Project. Emmet defines the core models, data pipelines, the API server, and the convenience CLI. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865782.0 emmet-core-0.84.2/emmet_core.egg-info/SOURCES.txt0000644000175100001770000001052014673360566020762 0ustar00runnerdockerredox_doc_test.json setup.py dev_scripts/generate_enums.py emmet/core/__init__.py emmet/core/_general_store.py emmet/core/_messages.py emmet/core/_user_settings.py emmet/core/absorption.py emmet/core/alloys.py emmet/core/base.py emmet/core/bonds.py emmet/core/charge_density.py emmet/core/chemenv.py emmet/core/common.py emmet/core/corrected_entries.py emmet/core/defect.py emmet/core/dois.py emmet/core/elasticity.py emmet/core/elasticity_legacy.py emmet/core/electrode.py emmet/core/electronic_structure.py emmet/core/eos.py emmet/core/fermi.py emmet/core/find_structure.py emmet/core/formula_autocomplete.py emmet/core/grain_boundary.py emmet/core/magnetism.py emmet/core/material.py emmet/core/material_property.py emmet/core/math.py emmet/core/ml.py emmet/core/molecules_jcesr.py emmet/core/mpcomplete.py emmet/core/mpid.py emmet/core/optimade.py emmet/core/oxidation_states.py emmet/core/phonon.py emmet/core/polar.py emmet/core/provenance.py emmet/core/qc_tasks.py emmet/core/robocrys.py emmet/core/settings.py emmet/core/similarity.py emmet/core/spectrum.py emmet/core/structure.py emmet/core/structure_group.py emmet/core/stubs.py emmet/core/substrates.py emmet/core/summary.py emmet/core/surface_properties.py emmet/core/symmetry.py emmet/core/task.py emmet/core/tasks.py emmet/core/thermo.py emmet/core/utils.py emmet/core/xas.py emmet/core/xrd.py emmet/core/feff/__init__.py emmet/core/feff/task.py emmet/core/mobility/migrationgraph.py emmet/core/molecules/__init__.py emmet/core/molecules/atomic.py emmet/core/molecules/bonds.py emmet/core/molecules/metal_binding.py emmet/core/molecules/molecule_property.py emmet/core/molecules/orbitals.py emmet/core/molecules/redox.py emmet/core/molecules/summary.py emmet/core/molecules/thermo.py emmet/core/molecules/vibration.py emmet/core/openff/__init__.py emmet/core/openff/benchmarking.py emmet/core/openff/solvation.py emmet/core/openff/tasks.py emmet/core/openmm/__init__.py emmet/core/openmm/calculations.py emmet/core/openmm/tasks.py emmet/core/qchem/__init__.py emmet/core/qchem/calculation.py emmet/core/qchem/molecule.py emmet/core/qchem/task.py emmet/core/qchem/calc_types/__init__.py emmet/core/qchem/calc_types/calc_types.py emmet/core/qchem/calc_types/calc_types.yaml emmet/core/qchem/calc_types/em_utils.py emmet/core/qchem/calc_types/enums.py emmet/core/qchem/calc_types/utils.py emmet/core/synthesis/__init__.py emmet/core/synthesis/core.py emmet/core/synthesis/materials.py emmet/core/synthesis/operations.py emmet/core/synthesis/reaction.py emmet/core/vasp/__init__.py emmet/core/vasp/calculation.py emmet/core/vasp/material.py emmet/core/vasp/task_valid.py emmet/core/vasp/validation.py emmet/core/vasp/calc_types/__init__.py emmet/core/vasp/calc_types/calc_types.yaml emmet/core/vasp/calc_types/enums.py emmet/core/vasp/calc_types/utils.py emmet_core.egg-info/PKG-INFO emmet_core.egg-info/SOURCES.txt emmet_core.egg-info/dependency_links.txt emmet_core.egg-info/not-zip-safe emmet_core.egg-info/requires.txt emmet_core.egg-info/top_level.txt requirements/deployment.txt requirements/ubuntu-latest_py3.10.txt requirements/ubuntu-latest_py3.10_extras.txt requirements/ubuntu-latest_py3.11.txt requirements/ubuntu-latest_py3.11_extras.txt tests/__init__.py tests/conftest.py tests/conftest_qchem.py tests/test_absorption.py tests/test_calculation.py tests/test_chemenv.py tests/test_defects.py tests/test_elasticity.py tests/test_electrodes.py tests/test_electronic_structure.py tests/test_magnetism.py tests/test_ml.py tests/test_molecule_metadata.py tests/test_mpid.py tests/test_optimade.py tests/test_oxidation_states.py tests/test_polar.py tests/test_provenance.py tests/test_qc_task.py tests/test_robocrys.py tests/test_settings.py tests/test_structure_group.py tests/test_structure_metadata.py tests/test_task.py tests/test_thermo.py tests/test_utils.py tests/test_xrd.py tests/mobility/test_migrationgraph.py tests/molecules/__init__.py tests/molecules/test_atomic.py tests/molecules/test_bonds.py tests/molecules/test_metal_binding.py tests/molecules/test_mol_thermo.py tests/molecules/test_orbitals.py tests/molecules/test_redox.py tests/molecules/test_summary.py tests/molecules/test_vibration.py tests/openmm_md/__init__.py tests/openmm_md/test_tasks.py tests/qchem/__init__.py tests/qchem/test_calc_types.py tests/qchem/test_molecules.py tests/qchem/test_qchem.py tests/vasp/test_calc_types.py tests/vasp/test_materials.py tests/vasp/test_vasp.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865781.0 emmet-core-0.84.2/emmet_core.egg-info/dependency_links.txt0000644000175100001770000000000114673360565023145 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865781.0 emmet-core-0.84.2/emmet_core.egg-info/not-zip-safe0000644000175100001770000000000114673360565021325 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865781.0 emmet-core-0.84.2/emmet_core.egg-info/requires.txt0000644000175100001770000000124614673360565021502 0ustar00runnerdockernumpy<2 pymatgen monty>=2024.2.2 pydantic>=2.0 pydantic-settings>=2.0 pybtex~=0.24 typing-extensions>=3.7 [all] matcalc>=0.0.4 seekpath>=2.0.1 robocrys>=0.2.8 pymatgen-analysis-defects>=2024.7.18 pymatgen-analysis-diffusion>=2024.7.15 pymatgen-analysis-alloys>=0.0.6 solvation-analysis>=0.4.1 MDAnalysis>=2.7.0 [docs] mkdocs mkdocs-material<8.3 mkdocs-material-extensions mkdocs-minify-plugin mkdocstrings mkdocs-awesome-pages-plugin mkdocs-markdownextradata-plugin mkdocstrings[python] livereload jinja2 [ml] chgnet matgl dgl<=2.1 [test] pre-commit pytest pytest-cov pycodestyle pydocstyle flake8 mypy mypy-extensions types-setuptools types-requests wincertstore custodian ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865781.0 emmet-core-0.84.2/emmet_core.egg-info/top_level.txt0000644000175100001770000000000614673360565021625 0ustar00runnerdockeremmet ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/redox_doc_test.json0000644000175100001770000000604614673360562017171 0ustar00runnerdocker{"builder_meta": {"emmet_version": "0.1.1a1.dev1669+g3a8fe1f3.d20221122", "pymatgen_version": "2022.9.21", "pull_request": null, "database_version": null, "build_date": {"@module": "datetime", "@class": "datetime", "string": "2023-01-04 17:17:51.460366"}}, "charge": 0, "spin_multiplicity": 1, "natoms": null, "elements": [{"@module": "pymatgen.core.periodic_table", "@class": "Element", "element": "C", "@version": null}, {"@module": "pymatgen.core.periodic_table", "@class": "Element", "element": "H", "@version": null}, {"@module": "pymatgen.core.periodic_table", "@class": "Element", "element": "O", "@version": null}], "nelements": 3, "composition": {"O": 3.0, "C": 3.0, "H": 4.0, "@module": "pymatgen.core.composition", "@class": "Composition", "@version": null}, "formula_alphabetical": "C3 H4 O3", "chemsys": "C-H-O", "symmetry": {"point_group": "C1", "rotation_number": 1.0, "linear": false, "tolerance": 0.3, "eigen_tolerance": 0.01, "matrix_tolerance": 0.1}, "property_name": "redox", "property_id": "d53d44787678d835a672ec1eba2a8a56a8605d81a3a3e20b3f0eb7b686935593e435048eaed080212aa9722110a0201447833a5594018328728478096507359f", "molecule_id": "a973cfc2c805031802753d1e1bdddbe4-C3H4O3-0-1", "deprecated": false, "deprecation_reasons": null, "level_of_theory": "wB97X-V/def2-TZVPPD/SMD", "solvent": "DIELECTRIC=18,500;N=1,415;ALPHA=0,000;BETA=0,735;GAMMA=20,200;PHI=0,000;PSI=0,000", "lot_solvent": "wB97X-V/def2-TZVPPD/SMD(DIELECTRIC=18,500;N=1,415;ALPHA=0,000;BETA=0,735;GAMMA=20,200;PHI=0,000;PSI=0,000)", "last_updated": {"@module": "datetime", "@class": "datetime", "string": "2023-01-04 17:17:51.460441"}, "origins": [{"name": "electron_affinity", "task_id": "845805", "last_updated": {"@module": "datetime", "@class": "datetime", "string": "2023-01-04 17:17:51.444227"}}, {"name": "ionization_energy", "task_id": "889281", "last_updated": {"@module": "datetime", "@class": "datetime", "string": "2023-01-04 17:17:51.444237"}}], "warnings": [], "base_property_id": "9e126e31c4e8358bf59c213d49b8d17a4d99bbe181546beaf367999686d6e42b631fcbe28fd9d8bd12cc4a0679e95cb134aed0fd811ca51b589c49e95fed732a", "electron_affinity": -3.3024638499209686, "ea_task_id": "845805", "ionization_energy": 4.903294672107222, "ie_task_id": "889281", "reduction_energy": -4.207728314804626, "reduction_free_energy": -4.237271030198826, "red_molecule_id": "e5dcb67c00ed630ddc67c1841a916d12-C3H4O3-m1-2", "red_property_id": "f1e27ada382ec79418af854bd483855cfcf6e348694b0e6aae12c7547767573e2a740347f23f843c4d1aa861f9bda3c62db7fba7ca0cf659d1334dacf5b4d6af", "oxidation_energy": 3.9564857093027967, "oxidation_free_energy": 3.9880055108133092, "ox_molecule_id": "fd54c4321e8fee2777b772729584ea38-C3H4O3-1-2", "ox_property_id": "1a758b1d0423cda774504f48c8ac0c78fe1355bcc279e8c441e806b5825851fe97f05ef2abe985f6ff1a5203a509657929e40db334f56447a2db04ffcc0ef56d", "reduction_potentials": {"H": -0.20272896980117405, "Li": 2.8372710301988264, "Mg": 2.1772710301988263, "Ca": 2.6372710301988262}, "oxidation_potentials": {"H": -0.45199448918669116, "Li": 2.5880055108133093, "Mg": 1.9280055108133092, "Ca": 2.388005510813309}} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0542903 emmet-core-0.84.2/requirements/0000755000175100001770000000000014673360566016012 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/requirements/deployment.txt0000644000175100001770000000473414673360562020737 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=emmet/emmet-core/requirements/deployment.txt emmet/emmet-core/setup.py python/requirements.txt # annotated-types==0.7.0 # via pydantic certifi==2024.8.30 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.3.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.53.1 # via matplotlib idna==3.10 # via requests joblib==1.4.2 # via pymatgen kiwisolver==1.4.7 # via matplotlib latexcodec==3.0.0 # via pybtex matplotlib==3.9.2 # via # -r python/requirements.txt # pymatgen monty==2024.7.30 # via # emmet-core (emmet/emmet-core/setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.3 # via pymatgen numpy==1.26.4 # via # -r python/requirements.txt # contourpy # emmet-core (emmet/emmet-core/setup.py) # matplotlib # pandas # pymatgen # scipy # spglib packaging==24.1 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.2.2 # via # -r python/requirements.txt # pymatgen pillow==10.4.0 # via matplotlib plotly==5.24.1 # via pymatgen pybtex==0.24.0 # via # emmet-core (emmet/emmet-core/setup.py) # pymatgen pydantic==2.9.2 # via # emmet-core (emmet/emmet-core/setup.py) # pydantic-settings pydantic-core==2.23.4 # via pydantic pydantic-settings==2.5.2 # via emmet-core (emmet/emmet-core/setup.py) pymatgen==2024.9.17.1 # via emmet-core (emmet/emmet-core/setup.py) pyparsing==3.1.4 # via matplotlib python-dateutil==2.9.0.post0 # via # matplotlib # pandas python-dotenv==1.0.1 # via pydantic-settings pytz==2024.2 # via pandas pyyaml==6.0.2 # via pybtex requests==2.32.3 # via pymatgen ruamel-yaml==0.18.6 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.14.1 # via # -r python/requirements.txt # pymatgen six==1.16.0 # via # pybtex # python-dateutil spglib==2.5.0 # via pymatgen sympy==1.13.3 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==9.0.0 # via plotly tqdm==4.66.5 # via pymatgen typing-extensions==4.12.2 # via # emmet-core (emmet/emmet-core/setup.py) # pydantic # pydantic-core tzdata==2024.1 # via pandas uncertainties==3.2.2 # via pymatgen urllib3==2.2.3 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/requirements/ubuntu-latest_py3.10.txt0000644000175100001770000000421014673360562022372 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --output-file=requirements/ubuntu-latest_py3.10.txt # annotated-types==0.7.0 # via pydantic certifi==2024.8.30 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.3.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.53.1 # via matplotlib idna==3.10 # via requests joblib==1.4.2 # via pymatgen kiwisolver==1.4.7 # via matplotlib latexcodec==3.0.0 # via pybtex matplotlib==3.9.2 # via pymatgen monty==2024.7.30 # via # emmet-core (setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.3 # via pymatgen numpy==1.26.4 # via # contourpy # emmet-core (setup.py) # matplotlib # pandas # pymatgen # scipy # spglib packaging==24.1 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.2.2 # via pymatgen pillow==10.4.0 # via matplotlib plotly==5.24.1 # via pymatgen pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen pydantic==2.9.2 # via # emmet-core (setup.py) # pydantic-settings pydantic-core==2.23.4 # via pydantic pydantic-settings==2.5.2 # via emmet-core (setup.py) pymatgen==2024.9.17.1 # via emmet-core (setup.py) pyparsing==3.1.4 # via matplotlib python-dateutil==2.9.0.post0 # via # matplotlib # pandas python-dotenv==1.0.1 # via pydantic-settings pytz==2024.2 # via pandas pyyaml==6.0.2 # via pybtex requests==2.32.3 # via pymatgen ruamel-yaml==0.18.6 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.14.1 # via pymatgen six==1.16.0 # via # pybtex # python-dateutil spglib==2.5.0 # via pymatgen sympy==1.13.3 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==9.0.0 # via plotly tqdm==4.66.5 # via pymatgen typing-extensions==4.12.2 # via # emmet-core (setup.py) # pydantic # pydantic-core tzdata==2024.1 # via pandas uncertainties==3.2.2 # via pymatgen urllib3==2.2.3 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/requirements/ubuntu-latest_py3.10_extras.txt0000644000175100001770000003206414673360562023770 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile --all-extras --output-file=requirements/ubuntu-latest_py3.10_extras.txt # aiohappyeyeballs==2.4.0 # via aiohttp aiohttp==3.10.5 # via fsspec aioitertools==0.12.0 # via maggma aiosignal==1.3.1 # via aiohttp annotated-types==0.7.0 # via pydantic ase==3.23.0 # via # chgnet # matcalc # matgl # pymatgen-analysis-diffusion async-timeout==4.0.3 # via aiohttp attrs==24.2.0 # via # aiohttp # jsonlines # jsonschema # referencing bcrypt==4.2.0 # via paramiko boto3==1.35.23 # via maggma botocore==1.35.23 # via # boto3 # s3transfer bracex==2.5 # via wcmatch certifi==2024.8.30 # via requests cffi==1.17.1 # via # cryptography # pynacl cfgv==3.4.0 # via pre-commit charset-normalizer==3.3.2 # via requests chgnet==0.4.0 # via emmet-core (setup.py) click==8.1.7 # via # mkdocs # mkdocstrings colorama==0.4.6 # via griffe contourpy==1.3.0 # via matplotlib coverage[toml]==7.6.1 # via pytest-cov cryptography==43.0.1 # via paramiko csscompressor==0.9.5 # via mkdocs-minify-plugin custodian==2024.6.24 # via emmet-core (setup.py) cycler==0.12.1 # via matplotlib cython==3.0.11 # via chgnet dgl==2.1.0 # via # emmet-core (setup.py) # matgl distlib==0.3.8 # via virtualenv dnspython==2.6.1 # via # maggma # pymongo emmet-core==0.84.2rc10 # via mp-api exceptiongroup==1.2.2 # via pytest fasteners==0.19 # via mdanalysis filelock==3.16.1 # via # torch # triton # virtualenv flake8==7.1.1 # via emmet-core (setup.py) fonttools==4.53.1 # via matplotlib frozenlist==1.4.1 # via # aiohttp # aiosignal fsspec[http]==2024.9.0 # via # lightning # pytorch-lightning # torch ghp-import==2.1.0 # via mkdocs griddataformats==1.0.2 # via mdanalysis griffe==1.3.1 # via mkdocstrings-python h5py==3.11.0 # via phonopy htmlmin2==0.1.13 # via mkdocs-minify-plugin identify==2.6.1 # via pre-commit idna==3.10 # via # requests # yarl imageio==2.35.1 # via scikit-image inflect==7.4.0 # via robocrys iniconfig==2.0.0 # via pytest jinja2==3.1.4 # via # emmet-core (setup.py) # mkdocs # mkdocs-material # mkdocstrings # torch jmespath==1.0.1 # via # boto3 # botocore joblib==1.4.2 # via # matcalc # mdanalysis # pymatgen # pymatgen-analysis-diffusion # scikit-learn jsmin==3.0.1 # via mkdocs-minify-plugin jsonlines==4.0.0 # via maggma jsonschema==4.23.0 # via maggma jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.7 # via matplotlib latexcodec==3.0.0 # via pybtex lazy-loader==0.4 # via scikit-image lightning==2.4.0 # via matgl lightning-utilities==0.11.7 # via # lightning # pytorch-lightning # torchmetrics livereload==2.7.0 # via emmet-core (setup.py) maggma==0.69.3 # via mp-api markdown==3.7 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions markupsafe==2.1.5 # via # jinja2 # mkdocs # mkdocs-autorefs # mkdocstrings matcalc==0.0.4 # via emmet-core (setup.py) matgl==1.1.3 # via emmet-core (setup.py) matminer==0.9.2 # via robocrys matplotlib==3.9.2 # via # ase # mdanalysis # phonopy # pymatgen # seaborn # solvation-analysis mccabe==0.7.0 # via flake8 mda-xdrlib==0.2.0 # via mdanalysis mdanalysis==2.7.0 # via # emmet-core (setup.py) # solvation-analysis mergedeep==1.3.4 # via # mkdocs # mkdocs-get-deps mkdocs==1.6.1 # via # emmet-core (setup.py) # mkdocs-autorefs # mkdocs-awesome-pages-plugin # mkdocs-markdownextradata-plugin # mkdocs-material # mkdocs-minify-plugin # mkdocstrings mkdocs-autorefs==1.2.0 # via # mkdocstrings # mkdocstrings-python mkdocs-awesome-pages-plugin==2.9.3 # via emmet-core (setup.py) mkdocs-get-deps==0.2.0 # via mkdocs mkdocs-markdownextradata-plugin==0.2.6 # via emmet-core (setup.py) mkdocs-material==8.2.16 # via emmet-core (setup.py) mkdocs-material-extensions==1.3.1 # via # emmet-core (setup.py) # mkdocs-material mkdocs-minify-plugin==0.8.0 # via emmet-core (setup.py) mkdocstrings[python]==0.26.1 # via # emmet-core (setup.py) # mkdocstrings-python mkdocstrings-python==1.11.1 # via mkdocstrings mmtf-python==1.1.3 # via mdanalysis mongomock==4.2.0.post1 # via maggma monty==2024.7.30 # via # custodian # emmet-core # emmet-core (setup.py) # maggma # matminer # mp-api # pymatgen # robocrys more-itertools==10.5.0 # via inflect mp-api==0.42.2 # via robocrys mp-pyrho==0.4.4 # via pymatgen-analysis-defects mpmath==1.3.0 # via sympy mrcfile==1.5.3 # via griddataformats msgpack==1.1.0 # via # maggma # mmtf-python # mp-api multidict==6.1.0 # via # aiohttp # yarl mypy==1.11.2 # via emmet-core (setup.py) mypy-extensions==1.0.0 # via # emmet-core (setup.py) # mypy natsort==8.4.0 # via mkdocs-awesome-pages-plugin networkx==3.3 # via # dgl # pymatgen # robocrys # scikit-image # torch nodeenv==1.9.1 # via pre-commit numpy==1.26.4 # via # ase # chgnet # contourpy # dgl # emmet-core # emmet-core (setup.py) # griddataformats # h5py # imageio # maggma # matminer # matplotlib # mdanalysis # mrcfile # pandas # patsy # phonopy # pymatgen # pymatgen-analysis-defects # pymatgen-analysis-diffusion # rdkit # robocrys # scikit-image # scikit-learn # scipy # seaborn # seekpath # shapely # solvation-analysis # spglib # statsmodels # tifffile # torchmetrics nvidia-cublas-cu12==12.1.3.1 # via # nvidia-cudnn-cu12 # nvidia-cusolver-cu12 # torch nvidia-cuda-cupti-cu12==12.1.105 # via torch nvidia-cuda-nvrtc-cu12==12.1.105 # via torch nvidia-cuda-runtime-cu12==12.1.105 # via torch nvidia-cudnn-cu12==9.1.0.70 # via torch nvidia-cufft-cu12==11.0.2.54 # via torch nvidia-curand-cu12==10.3.2.106 # via torch nvidia-cusolver-cu12==11.4.5.107 # via torch nvidia-cusparse-cu12==12.1.0.106 # via # nvidia-cusolver-cu12 # torch nvidia-ml-py3==7.352.0 # via chgnet nvidia-nccl-cu12==2.20.5 # via torch nvidia-nvjitlink-cu12==12.6.68 # via # nvidia-cusolver-cu12 # nvidia-cusparse-cu12 nvidia-nvtx-cu12==12.1.105 # via torch orjson==3.10.7 # via maggma packaging==24.1 # via # lazy-loader # lightning # lightning-utilities # matplotlib # mdanalysis # mkdocs # mongomock # plotly # pytest # pytorch-lightning # scikit-image # statsmodels # torchmetrics palettable==3.3.3 # via pymatgen pandas==2.2.2 # via # maggma # matminer # pymatgen # seaborn # solvation-analysis # statsmodels paramiko==3.5.0 # via sshtunnel pathspec==0.12.1 # via mkdocs patsy==0.5.6 # via statsmodels phonopy==2.28.0 # via matcalc pillow==10.4.0 # via # imageio # matplotlib # rdkit # scikit-image platformdirs==4.3.6 # via # mkdocs-get-deps # mkdocstrings # virtualenv plotly==5.24.1 # via # pymatgen # solvation-analysis pluggy==1.5.0 # via pytest pre-commit==3.8.0 # via emmet-core (setup.py) psutil==6.0.0 # via # custodian # dgl pubchempy==1.0.4 # via robocrys pybtex==0.24.0 # via # emmet-core # emmet-core (setup.py) # pymatgen # robocrys pycodestyle==2.12.1 # via # emmet-core (setup.py) # flake8 pycparser==2.22 # via cffi pydantic==2.9.2 # via # emmet-core # emmet-core (setup.py) # maggma # matgl # pydantic-settings pydantic-core==2.23.4 # via pydantic pydantic-settings==2.5.2 # via # emmet-core # emmet-core (setup.py) # maggma pydash==8.0.3 # via maggma pydocstyle==6.3.0 # via emmet-core (setup.py) pyflakes==3.2.0 # via flake8 pygments==2.18.0 # via mkdocs-material pymatgen==2024.9.17.1 # via # chgnet # emmet-core # emmet-core (setup.py) # matcalc # matgl # matminer # mp-api # mp-pyrho # pymatgen-analysis-alloys # pymatgen-analysis-defects # pymatgen-analysis-diffusion # robocrys pymatgen-analysis-alloys==0.0.6 # via emmet-core (setup.py) pymatgen-analysis-defects==2024.7.19 # via emmet-core (setup.py) pymatgen-analysis-diffusion==2024.7.15 # via emmet-core (setup.py) pymdown-extensions==10.9 # via # mkdocs-material # mkdocstrings pymongo==4.9.1 # via # maggma # matminer pynacl==1.5.0 # via paramiko pyparsing==3.1.4 # via matplotlib pytest==8.3.3 # via # emmet-core (setup.py) # pytest-cov # solvation-analysis pytest-cov==5.0.0 # via emmet-core (setup.py) python-dateutil==2.9.0.post0 # via # botocore # ghp-import # maggma # matplotlib # pandas python-dotenv==1.0.1 # via pydantic-settings pytorch-lightning==2.4.0 # via lightning pytz==2024.2 # via # mongomock # pandas pyyaml==6.0.2 # via # lightning # mkdocs # mkdocs-get-deps # mkdocs-markdownextradata-plugin # phonopy # pre-commit # pybtex # pymdown-extensions # pytorch-lightning # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs pyzmq==26.2.0 # via maggma rdkit==2024.3.5 # via solvation-analysis referencing==0.35.1 # via # jsonschema # jsonschema-specifications requests==2.32.3 # via # dgl # matminer # mp-api # pymatgen # torchdata robocrys==0.2.9 # via emmet-core (setup.py) rpds-py==0.20.0 # via # jsonschema # referencing ruamel-yaml==0.18.6 # via # custodian # maggma # pymatgen # robocrys ruamel-yaml-clib==0.2.8 # via ruamel-yaml s3transfer==0.10.2 # via boto3 scikit-image==0.24.0 # via pymatgen-analysis-defects scikit-learn==1.5.2 # via matminer scipy==1.14.1 # via # ase # dgl # griddataformats # mdanalysis # pymatgen # robocrys # scikit-image # scikit-learn # solvation-analysis # statsmodels seaborn==0.13.2 # via pymatgen-analysis-diffusion seekpath==2.1.0 # via emmet-core (setup.py) sentinels==1.0.0 # via mongomock shapely==2.0.6 # via pymatgen-analysis-alloys six==1.16.0 # via # patsy # pybtex # python-dateutil smart-open==7.0.4 # via mp-api snowballstemmer==2.2.0 # via pydocstyle solvation-analysis==0.4.1 # via emmet-core (setup.py) spglib==2.5.0 # via # phonopy # pymatgen # robocrys # seekpath sshtunnel==0.4.0 # via maggma statsmodels==0.14.3 # via solvation-analysis sympy==1.13.3 # via # matminer # pymatgen # torch tabulate==0.9.0 # via pymatgen tenacity==9.0.0 # via plotly threadpoolctl==3.5.0 # via # mdanalysis # scikit-learn tifffile==2024.8.30 # via scikit-image tomli==2.0.1 # via # coverage # mypy # pytest torch==2.4.1 # via # chgnet # lightning # matgl # pytorch-lightning # torchdata # torchmetrics torchdata==0.7.1 # via # dgl # matgl torchmetrics==1.4.2 # via # lightning # pytorch-lightning tornado==6.4.1 # via livereload tqdm==4.66.5 # via # dgl # lightning # maggma # matminer # mdanalysis # pymatgen # pytorch-lightning triton==3.0.0 # via torch typeguard==4.3.0 # via inflect types-requests==2.32.0.20240914 # via emmet-core (setup.py) types-setuptools==75.1.0.20240917 # via emmet-core (setup.py) typing-extensions==4.12.2 # via # chgnet # emmet-core # emmet-core (setup.py) # lightning # lightning-utilities # mp-api # multidict # mypy # pydantic # pydantic-core # pydash # pytorch-lightning # torch # typeguard tzdata==2024.1 # via pandas uncertainties==3.2.2 # via pymatgen urllib3==2.2.3 # via # botocore # requests # torchdata # types-requests virtualenv==20.26.5 # via pre-commit watchdog==5.0.2 # via mkdocs wcmatch==9.0 # via mkdocs-awesome-pages-plugin wincertstore==0.2.1 # via emmet-core (setup.py) wrapt==1.16.0 # via smart-open yarl==1.11.1 # via aiohttp # The following packages are considered to be unsafe in a requirements file: # setuptools ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/requirements/ubuntu-latest_py3.11.txt0000644000175100001770000000421014673360562022373 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile --output-file=requirements/ubuntu-latest_py3.11.txt # annotated-types==0.7.0 # via pydantic certifi==2024.8.30 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.3.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.53.1 # via matplotlib idna==3.10 # via requests joblib==1.4.2 # via pymatgen kiwisolver==1.4.7 # via matplotlib latexcodec==3.0.0 # via pybtex matplotlib==3.9.2 # via pymatgen monty==2024.7.30 # via # emmet-core (setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.3 # via pymatgen numpy==1.26.4 # via # contourpy # emmet-core (setup.py) # matplotlib # pandas # pymatgen # scipy # spglib packaging==24.1 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.2.2 # via pymatgen pillow==10.4.0 # via matplotlib plotly==5.24.1 # via pymatgen pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen pydantic==2.9.2 # via # emmet-core (setup.py) # pydantic-settings pydantic-core==2.23.4 # via pydantic pydantic-settings==2.5.2 # via emmet-core (setup.py) pymatgen==2024.9.17.1 # via emmet-core (setup.py) pyparsing==3.1.4 # via matplotlib python-dateutil==2.9.0.post0 # via # matplotlib # pandas python-dotenv==1.0.1 # via pydantic-settings pytz==2024.2 # via pandas pyyaml==6.0.2 # via pybtex requests==2.32.3 # via pymatgen ruamel-yaml==0.18.6 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.14.1 # via pymatgen six==1.16.0 # via # pybtex # python-dateutil spglib==2.5.0 # via pymatgen sympy==1.13.3 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==9.0.0 # via plotly tqdm==4.66.5 # via pymatgen typing-extensions==4.12.2 # via # emmet-core (setup.py) # pydantic # pydantic-core tzdata==2024.1 # via pandas uncertainties==3.2.2 # via pymatgen urllib3==2.2.3 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/requirements/ubuntu-latest_py3.11_extras.txt0000644000175100001770000003162014673360562023766 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # pip-compile --all-extras --output-file=requirements/ubuntu-latest_py3.11_extras.txt # aiohappyeyeballs==2.4.0 # via aiohttp aiohttp==3.10.5 # via fsspec aioitertools==0.12.0 # via maggma aiosignal==1.3.1 # via aiohttp annotated-types==0.7.0 # via pydantic ase==3.23.0 # via # chgnet # matcalc # matgl # pymatgen-analysis-diffusion attrs==24.2.0 # via # aiohttp # jsonlines # jsonschema # referencing bcrypt==4.2.0 # via paramiko boto3==1.35.23 # via maggma botocore==1.35.23 # via # boto3 # s3transfer bracex==2.5 # via wcmatch certifi==2024.8.30 # via requests cffi==1.17.1 # via # cryptography # pynacl cfgv==3.4.0 # via pre-commit charset-normalizer==3.3.2 # via requests chgnet==0.4.0 # via emmet-core (setup.py) click==8.1.7 # via # mkdocs # mkdocstrings colorama==0.4.6 # via griffe contourpy==1.3.0 # via matplotlib coverage[toml]==7.6.1 # via pytest-cov cryptography==43.0.1 # via paramiko csscompressor==0.9.5 # via mkdocs-minify-plugin custodian==2024.6.24 # via emmet-core (setup.py) cycler==0.12.1 # via matplotlib cython==3.0.11 # via chgnet dgl==2.1.0 # via # emmet-core (setup.py) # matgl distlib==0.3.8 # via virtualenv dnspython==2.6.1 # via # maggma # pymongo emmet-core==0.84.2rc10 # via mp-api fasteners==0.19 # via mdanalysis filelock==3.16.1 # via # torch # triton # virtualenv flake8==7.1.1 # via emmet-core (setup.py) fonttools==4.53.1 # via matplotlib frozenlist==1.4.1 # via # aiohttp # aiosignal fsspec[http]==2024.9.0 # via # lightning # pytorch-lightning # torch ghp-import==2.1.0 # via mkdocs griddataformats==1.0.2 # via mdanalysis griffe==1.3.1 # via mkdocstrings-python h5py==3.11.0 # via phonopy htmlmin2==0.1.13 # via mkdocs-minify-plugin identify==2.6.1 # via pre-commit idna==3.10 # via # requests # yarl imageio==2.35.1 # via scikit-image inflect==7.4.0 # via robocrys iniconfig==2.0.0 # via pytest jinja2==3.1.4 # via # emmet-core (setup.py) # mkdocs # mkdocs-material # mkdocstrings # torch jmespath==1.0.1 # via # boto3 # botocore joblib==1.4.2 # via # matcalc # mdanalysis # pymatgen # pymatgen-analysis-diffusion # scikit-learn jsmin==3.0.1 # via mkdocs-minify-plugin jsonlines==4.0.0 # via maggma jsonschema==4.23.0 # via maggma jsonschema-specifications==2023.12.1 # via jsonschema kiwisolver==1.4.7 # via matplotlib latexcodec==3.0.0 # via pybtex lazy-loader==0.4 # via scikit-image lightning==2.4.0 # via matgl lightning-utilities==0.11.7 # via # lightning # pytorch-lightning # torchmetrics livereload==2.7.0 # via emmet-core (setup.py) maggma==0.69.3 # via mp-api markdown==3.7 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions markupsafe==2.1.5 # via # jinja2 # mkdocs # mkdocs-autorefs # mkdocstrings matcalc==0.0.4 # via emmet-core (setup.py) matgl==1.1.3 # via emmet-core (setup.py) matminer==0.9.2 # via robocrys matplotlib==3.9.2 # via # ase # mdanalysis # phonopy # pymatgen # seaborn # solvation-analysis mccabe==0.7.0 # via flake8 mda-xdrlib==0.2.0 # via mdanalysis mdanalysis==2.7.0 # via # emmet-core (setup.py) # solvation-analysis mergedeep==1.3.4 # via # mkdocs # mkdocs-get-deps mkdocs==1.6.1 # via # emmet-core (setup.py) # mkdocs-autorefs # mkdocs-awesome-pages-plugin # mkdocs-markdownextradata-plugin # mkdocs-material # mkdocs-minify-plugin # mkdocstrings mkdocs-autorefs==1.2.0 # via # mkdocstrings # mkdocstrings-python mkdocs-awesome-pages-plugin==2.9.3 # via emmet-core (setup.py) mkdocs-get-deps==0.2.0 # via mkdocs mkdocs-markdownextradata-plugin==0.2.6 # via emmet-core (setup.py) mkdocs-material==8.2.16 # via emmet-core (setup.py) mkdocs-material-extensions==1.3.1 # via # emmet-core (setup.py) # mkdocs-material mkdocs-minify-plugin==0.8.0 # via emmet-core (setup.py) mkdocstrings[python]==0.26.1 # via # emmet-core (setup.py) # mkdocstrings-python mkdocstrings-python==1.11.1 # via mkdocstrings mmtf-python==1.1.3 # via mdanalysis mongomock==4.2.0.post1 # via maggma monty==2024.7.30 # via # custodian # emmet-core # emmet-core (setup.py) # maggma # matminer # mp-api # pymatgen # robocrys more-itertools==10.5.0 # via inflect mp-api==0.42.2 # via robocrys mp-pyrho==0.4.4 # via pymatgen-analysis-defects mpmath==1.3.0 # via sympy mrcfile==1.5.3 # via griddataformats msgpack==1.1.0 # via # maggma # mmtf-python # mp-api multidict==6.1.0 # via # aiohttp # yarl mypy==1.11.2 # via emmet-core (setup.py) mypy-extensions==1.0.0 # via # emmet-core (setup.py) # mypy natsort==8.4.0 # via mkdocs-awesome-pages-plugin networkx==3.3 # via # dgl # pymatgen # robocrys # scikit-image # torch nodeenv==1.9.1 # via pre-commit numpy==1.26.4 # via # ase # chgnet # contourpy # dgl # emmet-core # emmet-core (setup.py) # griddataformats # h5py # imageio # maggma # matminer # matplotlib # mdanalysis # mrcfile # pandas # patsy # phonopy # pymatgen # pymatgen-analysis-defects # pymatgen-analysis-diffusion # rdkit # robocrys # scikit-image # scikit-learn # scipy # seaborn # seekpath # shapely # solvation-analysis # spglib # statsmodels # tifffile # torchmetrics nvidia-cublas-cu12==12.1.3.1 # via # nvidia-cudnn-cu12 # nvidia-cusolver-cu12 # torch nvidia-cuda-cupti-cu12==12.1.105 # via torch nvidia-cuda-nvrtc-cu12==12.1.105 # via torch nvidia-cuda-runtime-cu12==12.1.105 # via torch nvidia-cudnn-cu12==9.1.0.70 # via torch nvidia-cufft-cu12==11.0.2.54 # via torch nvidia-curand-cu12==10.3.2.106 # via torch nvidia-cusolver-cu12==11.4.5.107 # via torch nvidia-cusparse-cu12==12.1.0.106 # via # nvidia-cusolver-cu12 # torch nvidia-ml-py3==7.352.0 # via chgnet nvidia-nccl-cu12==2.20.5 # via torch nvidia-nvjitlink-cu12==12.6.68 # via # nvidia-cusolver-cu12 # nvidia-cusparse-cu12 nvidia-nvtx-cu12==12.1.105 # via torch orjson==3.10.7 # via maggma packaging==24.1 # via # lazy-loader # lightning # lightning-utilities # matplotlib # mdanalysis # mkdocs # mongomock # plotly # pytest # pytorch-lightning # scikit-image # statsmodels # torchmetrics palettable==3.3.3 # via pymatgen pandas==2.2.2 # via # maggma # matminer # pymatgen # seaborn # solvation-analysis # statsmodels paramiko==3.5.0 # via sshtunnel pathspec==0.12.1 # via mkdocs patsy==0.5.6 # via statsmodels phonopy==2.28.0 # via matcalc pillow==10.4.0 # via # imageio # matplotlib # rdkit # scikit-image platformdirs==4.3.6 # via # mkdocs-get-deps # mkdocstrings # virtualenv plotly==5.24.1 # via # pymatgen # solvation-analysis pluggy==1.5.0 # via pytest pre-commit==3.8.0 # via emmet-core (setup.py) psutil==6.0.0 # via # custodian # dgl pubchempy==1.0.4 # via robocrys pybtex==0.24.0 # via # emmet-core # emmet-core (setup.py) # pymatgen # robocrys pycodestyle==2.12.1 # via # emmet-core (setup.py) # flake8 pycparser==2.22 # via cffi pydantic==2.9.2 # via # emmet-core # emmet-core (setup.py) # maggma # matgl # pydantic-settings pydantic-core==2.23.4 # via pydantic pydantic-settings==2.5.2 # via # emmet-core # emmet-core (setup.py) # maggma pydash==8.0.3 # via maggma pydocstyle==6.3.0 # via emmet-core (setup.py) pyflakes==3.2.0 # via flake8 pygments==2.18.0 # via mkdocs-material pymatgen==2024.9.17.1 # via # chgnet # emmet-core # emmet-core (setup.py) # matcalc # matgl # matminer # mp-api # mp-pyrho # pymatgen-analysis-alloys # pymatgen-analysis-defects # pymatgen-analysis-diffusion # robocrys pymatgen-analysis-alloys==0.0.6 # via emmet-core (setup.py) pymatgen-analysis-defects==2024.7.19 # via emmet-core (setup.py) pymatgen-analysis-diffusion==2024.7.15 # via emmet-core (setup.py) pymdown-extensions==10.9 # via # mkdocs-material # mkdocstrings pymongo==4.9.1 # via # maggma # matminer pynacl==1.5.0 # via paramiko pyparsing==3.1.4 # via matplotlib pytest==8.3.3 # via # emmet-core (setup.py) # pytest-cov # solvation-analysis pytest-cov==5.0.0 # via emmet-core (setup.py) python-dateutil==2.9.0.post0 # via # botocore # ghp-import # maggma # matplotlib # pandas python-dotenv==1.0.1 # via pydantic-settings pytorch-lightning==2.4.0 # via lightning pytz==2024.2 # via # mongomock # pandas pyyaml==6.0.2 # via # lightning # mkdocs # mkdocs-get-deps # mkdocs-markdownextradata-plugin # phonopy # pre-commit # pybtex # pymdown-extensions # pytorch-lightning # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs pyzmq==26.2.0 # via maggma rdkit==2024.3.5 # via solvation-analysis referencing==0.35.1 # via # jsonschema # jsonschema-specifications requests==2.32.3 # via # dgl # matminer # mp-api # pymatgen # torchdata robocrys==0.2.9 # via emmet-core (setup.py) rpds-py==0.20.0 # via # jsonschema # referencing ruamel-yaml==0.18.6 # via # custodian # maggma # pymatgen # robocrys ruamel-yaml-clib==0.2.8 # via ruamel-yaml s3transfer==0.10.2 # via boto3 scikit-image==0.24.0 # via pymatgen-analysis-defects scikit-learn==1.5.2 # via matminer scipy==1.14.1 # via # ase # dgl # griddataformats # mdanalysis # pymatgen # robocrys # scikit-image # scikit-learn # solvation-analysis # statsmodels seaborn==0.13.2 # via pymatgen-analysis-diffusion seekpath==2.1.0 # via emmet-core (setup.py) sentinels==1.0.0 # via mongomock shapely==2.0.6 # via pymatgen-analysis-alloys six==1.16.0 # via # patsy # pybtex # python-dateutil smart-open==7.0.4 # via mp-api snowballstemmer==2.2.0 # via pydocstyle solvation-analysis==0.4.1 # via emmet-core (setup.py) spglib==2.5.0 # via # phonopy # pymatgen # robocrys # seekpath sshtunnel==0.4.0 # via maggma statsmodels==0.14.3 # via solvation-analysis sympy==1.13.3 # via # matminer # pymatgen # torch tabulate==0.9.0 # via pymatgen tenacity==9.0.0 # via plotly threadpoolctl==3.5.0 # via # mdanalysis # scikit-learn tifffile==2024.8.30 # via scikit-image torch==2.4.1 # via # chgnet # lightning # matgl # pytorch-lightning # torchdata # torchmetrics torchdata==0.7.1 # via # dgl # matgl torchmetrics==1.4.2 # via # lightning # pytorch-lightning tornado==6.4.1 # via livereload tqdm==4.66.5 # via # dgl # lightning # maggma # matminer # mdanalysis # pymatgen # pytorch-lightning triton==3.0.0 # via torch typeguard==4.3.0 # via inflect types-requests==2.32.0.20240914 # via emmet-core (setup.py) types-setuptools==75.1.0.20240917 # via emmet-core (setup.py) typing-extensions==4.12.2 # via # chgnet # emmet-core # emmet-core (setup.py) # lightning # lightning-utilities # mp-api # mypy # pydantic # pydantic-core # pydash # pytorch-lightning # torch # typeguard tzdata==2024.1 # via pandas uncertainties==3.2.2 # via pymatgen urllib3==2.2.3 # via # botocore # requests # torchdata # types-requests virtualenv==20.26.5 # via pre-commit watchdog==5.0.2 # via mkdocs wcmatch==9.0 # via mkdocs-awesome-pages-plugin wincertstore==0.2.1 # via emmet-core (setup.py) wrapt==1.16.0 # via smart-open yarl==1.11.1 # via aiohttp # The following packages are considered to be unsafe in a requirements file: # setuptools ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0622902 emmet-core-0.84.2/setup.cfg0000644000175100001770000000004614673360566015110 0ustar00runnerdocker[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/setup.py0000644000175100001770000000450614673360562015002 0ustar00runnerdockerimport os from setuptools import find_namespace_packages, setup readme_path = os.path.join(os.path.dirname(__file__), "..", "README.md") if os.path.exists(readme_path): with open(readme_path) as f: long_description = f.read() else: long_description = "Core Emmet Library" setup( name="emmet-core", use_scm_version={"root": "..", "relative_to": __file__}, setup_requires=["setuptools_scm"], description="Core Emmet Library", author="The Materials Project", author_email="feedback@materialsproject.org", long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/materialsproject/emmet", packages=find_namespace_packages(include=["emmet.*"]), package_data={ "emmet.core.vasp.calc_types": ["*.yaml"], "emmet.core.qchem.calc_types": ["*.yaml"], "emmet.core.subtrates": ["*.json"], }, include_package_data=True, install_requires=[ "numpy<2", "pymatgen", "monty>=2024.2.2", "pydantic>=2.0", "pydantic-settings>=2.0", "pybtex~=0.24", "typing-extensions>=3.7", ], extras_require={ "all": [ "matcalc>=0.0.4", "seekpath>=2.0.1", "robocrys>=0.2.8", "pymatgen-analysis-defects>=2024.7.18", "pymatgen-analysis-diffusion>=2024.7.15", "pymatgen-analysis-alloys>=0.0.6", "solvation-analysis>=0.4.1", "MDAnalysis>=2.7.0", ], "ml": ["chgnet", "matgl", "dgl<=2.1"], "test": [ "pre-commit", "pytest", "pytest-cov", "pycodestyle", "pydocstyle", "flake8", "mypy", "mypy-extensions", "types-setuptools", "types-requests", "wincertstore", "custodian", ], "docs": [ "mkdocs", "mkdocs-material<8.3", "mkdocs-material-extensions", "mkdocs-minify-plugin", "mkdocstrings", "mkdocs-awesome-pages-plugin", "mkdocs-markdownextradata-plugin", "mkdocstrings[python]", "livereload", "jinja2", ], }, python_requires=">=3.9", license="modified BSD", zip_safe=False, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0582902 emmet-core-0.84.2/tests/0000755000175100001770000000000014673360566014431 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/__init__.py0000644000175100001770000000056014673360562016537 0ustar00runnerdockerfrom pymatgen.util.testing import PymatgenTest from pymatgen.core import Structure struct_names = ( "SiO2 Li2O LiFePO4 TlBiSe2 K2O2 Li3V2(PO4)3 Li2O2 CsCl NaFePO4 Pb2TiZrO6 " "SrTiO3 TiO2 BaNiO3 VO2".split() ) test_structures = { name.stem: Structure.from_file(name) for name in PymatgenTest.TEST_STRUCTURES.keys() if name.stem in struct_names } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/conftest.py0000644000175100001770000002152414673360562016630 0ustar00runnerdockerimport os from pathlib import Path import pytest from tempfile import mkdtemp from shutil import rmtree @pytest.fixture(scope="session") def test_dir(): return Path(__file__).parent.parent.parent.joinpath("test_files").resolve() @pytest.fixture def tmp_dir(): """Make temporary directory for tests.""" old_cwd = os.getcwd() new_path = mkdtemp() os.chdir(new_path) yield os.chdir(old_cwd) rmtree(new_path) def assert_schemas_equal(test_schema, valid_schema): """ Recursively test all items in valid_schema are present and equal in test_schema. While test_schema can be a pydantic schema or dictionary, the valid schema must be a (nested) dictionary. This function automatically handles accessing the attributes of classes in the test_schema. Args: test_schema: A pydantic schema or dictionary of the schema. valid_schema: A (nested) dictionary specifying the key and values that must be present in test_schema. """ from pydantic import BaseModel if isinstance(valid_schema, dict): for key, sub_valid_schema in valid_schema.items(): if isinstance(key, str) and hasattr(test_schema, key): sub_test_schema = getattr(test_schema, key) elif not isinstance(test_schema, BaseModel): sub_test_schema = test_schema[key] else: raise ValueError(f"{type(test_schema)} does not have field: {key}") return assert_schemas_equal(sub_test_schema, sub_valid_schema) elif isinstance(valid_schema, list): for i, sub_valid_schema in enumerate(valid_schema): return assert_schemas_equal(test_schema[i], sub_valid_schema) elif isinstance(valid_schema, float): assert test_schema == pytest.approx(valid_schema) else: assert test_schema == valid_schema class SchemaTestData: """Dummy class to be used to contain all test data information.""" class SiOptimizeDouble(SchemaTestData): folder = "Si_old_double_relax" task_files = { "relax2": { "vasprun_file": "vasprun.xml.relax2.gz", "outcar_file": "OUTCAR.relax2.gz", "volumetric_files": ["CHGCAR.relax2.gz"], "contcar_file": "CONTCAR.relax2.gz", }, "relax1": { "vasprun_file": "vasprun.xml.relax1.gz", "outcar_file": "OUTCAR.relax1.gz", "volumetric_files": ["CHGCAR.relax1.gz"], "contcar_file": "CONTCAR.relax1.gz", }, } objects = {"relax2": []} task_doc = { "calcs_reversed": [ { "output": { "vbm": 5.6147, "cbm": 6.2652, "bandgap": 0.6505, "is_gap_direct": False, "is_metal": False, "transition": "(0.000,0.000,0.000)-(0.375,0.375,0.000)", "direct_gap": 2.5561, "run_stats": { "average_memory": 0, "max_memory": 28096.0, "cores": 16, }, }, "input": { "incar": {"NSW": 99}, "nkpoints": 29, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "structure": {"volume": 40.036816205493494}, "is_hubbard": False, "hubbards": None, }, } ], "analysis": {"delta_volume": 0.8638191769757384, "max_force": 0}, "input": { "structure": {"volume": 40.036816205493494}, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "parameters": {"NSW": 99}, "is_hubbard": False, "hubbards": None, }, "output": { "structure": {"volume": 40.90063538246923}, "energy": -10.84687704, "bandgap": 0.6505, }, "custodian": [{"job": {"settings_override": None, "suffix": ".relax1"}}], "included_objects": (), } class SiNonSCFUniform(SchemaTestData): from emmet.core.vasp.calculation import VaspObject folder = "Si_uniform" task_files = { "standard": { "vasprun_file": "vasprun.xml.gz", "outcar_file": "OUTCAR.gz", "volumetric_files": ["CHGCAR.gz"], "contcar_file": "CONTCAR.gz", } } objects = {"standard": []} task_doc = { "calcs_reversed": [ { "output": { "vbm": 5.6162, "cbm": 6.2243, "bandgap": 0.6103, "is_gap_direct": False, "is_metal": False, "transition": "(0.000,0.000,0.000)-(0.000,0.421,0.000)", "direct_gap": 2.5563, "run_stats": { "average_memory": 0, "max_memory": 31004.0, "cores": 16, }, }, "input": { "incar": {"NSW": 0}, "nkpoints": 220, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "structure": {"volume": 40.88829843008916}, "is_hubbard": False, "hubbards": None, }, } ], "analysis": {"delta_volume": 0, "max_force": 0.5350159115036506}, "input": { "structure": {"volume": 40.88829843008916}, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "parameters": {"NSW": 0}, "is_hubbard": False, "hubbards": None, }, "output": { "structure": {"volume": 40.88829843008916}, "energy": -10.85064059, "bandgap": 0.6103, }, "custodian": [{"job": {"settings_override": None, "suffix": ""}}], "included_objects": (VaspObject.DOS, VaspObject.BANDSTRUCTURE), } class SiStatic(SchemaTestData): from emmet.core.vasp.calculation import VaspObject folder = "Si_static" task_files = { "standard": { "vasprun_file": "vasprun.xml.gz", "outcar_file": "OUTCAR.gz", "volumetric_files": ["CHGCAR.gz"], "contcar_file": "CONTCAR.gz", } } objects = {"standard": []} task_doc = { "calcs_reversed": [ { "output": { "vbm": 5.6163, "cbm": 6.2644, "bandgap": 0.6506, "is_gap_direct": False, "is_metal": False, "transition": "(0.000,0.000,0.000)-(0.000,0.375,0.000)", "direct_gap": 2.5563, "run_stats": { "average_memory": 0, "max_memory": 28124.0, "cores": 16, }, }, "input": { "incar": {"NSW": 1}, "nkpoints": 29, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "structure": {"volume": 40.88829843008916}, }, } ], "analysis": {"delta_volume": 0, "max_force": 0.0}, "input": { "structure": {"volume": 40.88829843008916}, "potcar_spec": [{"titel": "PAW_PBE Si 05Jan2001"}], "parameters": {"NSW": 0}, "is_hubbard": False, "hubbards": None, }, "output": { "structure": {"volume": 40.88829843008916}, "energy": -10.84678256, "bandgap": 0.6506, "dos_properties": { "Si": { "s": { "filling": 0.624669545020562, "center": -2.5151284433409815, "bandwidth": 7.338662205126851, "skewness": 0.6261990748648925, "kurtosis": 2.0074877073276904, "upper_edge": -8.105469079999999, }, "p": { "filling": 0.3911927710592045, "center": 3.339269798287516, "bandwidth": 5.999449671419663, "skewness": 0.0173776678056677, "kurtosis": 1.907790411890831, "upper_edge": -0.7536690799999999, }, } }, }, "custodian": [{"job": {"settings_override": None, "suffix": ""}}], "included_objects": (), } objects = {cls.__name__: cls for cls in SchemaTestData.__subclasses__()} def get_test_object(object_name): """Get the schema test data object from the class name.""" return objects[object_name] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/conftest_qchem.py0000644000175100001770000003505214673360562020006 0ustar00runnerdockerfrom pathlib import Path import pytest import numpy as np @pytest.fixture(scope="session") def test_dir(): return Path(__file__).parent.parent.parent.joinpath("test_files").resolve() def assert_schemas_equal(test_schema, valid_schema): """ Recursively test all items in valid_schema are present and equal in test_schema. While test_schema can be a pydantic schema or dictionary, the valid schema must be a (nested) dictionary. This function automatically handles accessing the attributes of classes in the test_schema. Args: test_schema: A pydantic schema or dictionary of the schema. valid_schema: A (nested) dictionary specifying the key and values that must be present in test_schema. This is what the generated test_schema will be tested against """ from pydantic import BaseModel if isinstance(valid_schema, dict): for key, sub_valid_schema in valid_schema.items(): if isinstance(key, str) and hasattr(test_schema, key): sub_test_schema = getattr(test_schema, key) if key == "initial_molecule": sub_test_schema = sub_test_schema.as_dict() elif key == "optimized_molecule": sub_test_schema = ( sub_test_schema.as_dict() if sub_test_schema else {} ) elif not isinstance(test_schema, BaseModel): sub_test_schema = test_schema[key] else: raise ValueError(f"{type(test_schema)} does not have field: {key}") return assert_schemas_equal(sub_test_schema, sub_valid_schema) elif isinstance(valid_schema, list): for i, sub_valid_schema in enumerate(valid_schema): return assert_schemas_equal(test_schema[i], sub_valid_schema) elif isinstance(valid_schema, np.ndarray): assert np.array_equal(test_schema, valid_schema) elif isinstance(valid_schema, float): assert test_schema == pytest.approx(valid_schema) else: assert test_schema == valid_schema class SchemaTestData: """Dummy class to be used to contain all test data information""" class SinglePointTest(SchemaTestData): folder = "qchem_sp_test" task_files = { "standard": { "qcinput_file": "mol.qin.gz", "qcoutput_file": "mol.qout.gz", } } objects = {"standard": []} task_doc = { "calcs_reversed": [ { "output": { "mulliken": [np.array([-0.713178, 0.357278, 0.3559])], "resp": [np.array([-0.872759, 0.436379, 0.436379])], "final_energy": -76.4493700739, }, "input": { "charge": 0, "rem": { "job_type": "sp", "basis": "def2-qzvppd", "max_scf_cycles": "100", "gen_scfman": "true", "xc_grid": "3", "thresh": "14", "s2thresh": "16", "scf_algorithm": "diis", "resp_charges": "true", "symmetry": "false", "sym_ignore": "true", "method": "wb97mv", "solvent_method": "smd", "ideriv": "1", }, "job_type": "sp", }, } ], "input": { "initial_molecule": { "@module": "pymatgen.core.structure", "@class": "Molecule", "charge": 0.0, "spin_multiplicity": 1, "sites": [ { "name": "O", "species": [{"element": "O", "occu": 1}], "xyz": [-0.80595, 2.22952, -0.01914], "properties": {}, "label": "O", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [0.18338, 2.20176, 0.01351], "properties": {}, "label": "H", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [-1.09531, 1.61602, 0.70231], "properties": {}, "label": "H", }, ], }, "rem": { "job_type": "sp", "basis": "def2-qzvppd", "max_scf_cycles": "100", "gen_scfman": "true", "xc_grid": "3", "thresh": "14", "s2thresh": "16", "scf_algorithm": "diis", "resp_charges": "true", "symmetry": "false", "sym_ignore": "true", "method": "wb97mv", "solvent_method": "smd", "ideriv": "1", }, "level_of_theory": "wB97M-V/def2-QZVPPD/SMD", "task_type": "Single Point", "calc_type": "wB97M-V/def2-QZVPPD/SMD Single Point", "solvation_lot_info": "wB97M-V/def2-QZVPPD/SMD(SOLVENT=WATER)", }, "output": { "mulliken": [np.array([-0.713178, 0.357278, 0.3559])], "resp": [np.array([-0.872759, 0.436379, 0.436379])], "final_energy": -76.4493700739, "dipoles": { "total": 2.4648, "dipole": [np.array([1.4227, -1.3039, 1.5333])], "RESP_total": 2.5411, "RESP_dipole": [np.array([1.4672, -1.3441, 1.5806])], }, }, "custodian": [ { "job": { "@module": "custodian.qchem.jobs", "@class": "QCJob", "@version": "2022.5.26", "qchem_command": ["qchem"], "max_cores": "40", "multimode": "openmp", "input_file": "mol.qin", "output_file": "mol.qout", "qclog_file": "mol.qclog", "suffix": "", "calc_loc": "/tmp", "nboexe": None, "save_scratch": False, "backup": "true", }, "corrections": [], } ], } class OptimizationTest(SchemaTestData): folder = "qchem_opt_test" task_files = { "standard": { "qcinput_file": "mol.qin.gz", "qcoutput_file": "mol.qout.gz", } } objects = {"standard": []} task_doc = { "calcs_reversed": [ { "output": { "optimized_molecule": { "@module": "pymatgen.core.structure", "@class": "Molecule", "charge": 0, "spin_multiplicity": 1, "sites": [ { "name": "O", "species": [{"element": "O", "occu": 1}], "xyz": [-0.8008592596, 2.2248298937, -0.0136245943], "properties": {}, "label": "O", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [0.1637955748, 2.1962925542, 0.0199393927], "properties": {}, "label": "H", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [-1.0808163152, 1.6261775521, 0.6903652017], "properties": {}, "label": "H", }, ], }, "mulliken": [-0.373491, 0.186964, 0.186527], "resp": [-0.89522, 0.44761, 0.44761], "final_energy": -76.358341626913, }, "input": { "charge": 0, "rem": { "job_type": "sp", "basis": "def2-qzvppd", "max_scf_cycles": "100", "gen_scfman": "true", "xc_grid": "3", "thresh": "14", "s2thresh": "16", "scf_algorithm": "diis", "resp_charges": "true", "symmetry": "false", "sym_ignore": "true", "method": "wb97mv", "solvent_method": "smd", "ideriv": "1", }, "job_type": "sp", }, } ], "input": { "initial_molecule": { "@module": "pymatgen.core.structure", "@class": "Molecule", "charge": 0.0, "spin_multiplicity": 1, "sites": [ { "name": "O", "species": [{"element": "O", "occu": 1}], "xyz": [-0.80595, 2.22952, -0.01914], "properties": {}, "label": "O", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [0.18338, 2.20176, 0.01351], "properties": {}, "label": "H", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [-1.09531, 1.61602, 0.70231], "properties": {}, "label": "H", }, ], }, "rem": { "job_type": "opt", "basis": "def2-svpd", "max_scf_cycles": "100", "gen_scfman": "true", "xc_grid": "3", "thresh": "14", "s2thresh": "16", "scf_algorithm": "diis", "resp_charges": "true", "symmetry": "false", "sym_ignore": "true", "method": "wb97mv", "solvent_method": "smd", "ideriv": "1", "geom_opt2": "3", }, "level_of_theory": "wB97M-V/def2-SVPD/SMD", "task_type": "Geometry Optimization", "calc_type": "wB97M-V/def2-SVPD/SMD Geometry Optimization", "solvation_lot_info": "wB97M-V/def2-SVPD/SMD(SOLVENT=WATER)", }, "output": { "initial_molecule": { "@module": "pymatgen.core.structure", "@class": "Molecule", "charge": 0.0, "spin_multiplicity": 1, "sites": [ { "name": "O", "species": [{"element": "O", "occu": 1}], "xyz": [-0.80595, 2.22952, -0.01914], "properties": {}, "label": "O", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [0.18338, 2.20176, 0.01351], "properties": {}, "label": "H", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [-1.09531, 1.61602, 0.70231], "properties": {}, "label": "H", }, ], }, "optimized_molecule": { "@module": "pymatgen.core.structure", "@class": "Molecule", "charge": 0, "spin_multiplicity": 1, "sites": [ { "name": "O", "species": [{"element": "O", "occu": 1}], "xyz": [-0.8008592596, 2.2248298937, -0.0136245943], "properties": {}, "label": "O", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [0.1637955748, 2.1962925542, 0.0199393927], "properties": {}, "label": "H", }, { "name": "H", "species": [{"element": "H", "occu": 1}], "xyz": [-1.0808163152, 1.6261775521, 0.6903652017], "properties": {}, "label": "H", }, ], }, "mulliken": [-0.373491, 0.186964, 0.186527], "resp": [-0.89522, 0.44761, 0.44761], "final_energy": -76.358341626913, }, "custodian": [ { "job": { "@module": "custodian.qchem.jobs", "@class": "QCJob", "@version": "2022.5.26", "qchem_command": ["qchem"], "max_cores": "40", "multimode": "openmp", "input_file": "mol.qin", "output_file": "mol.qout", "qclog_file": "mol.qclog", "suffix": "", "calc_loc": "/tmp", "nboexe": "null", "save_scratch": "false", "backup": "true", }, "corrections": [], } ], } objects = {cls.__name__: cls for cls in SchemaTestData.__subclasses__()} def get_test_object(object_name): """Get the schema test data object from the class name.""" return objects[object_name] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0582902 emmet-core-0.84.2/tests/mobility/0000755000175100001770000000000014673360566016261 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/mobility/test_migrationgraph.py0000644000175100001770000001060314673360562022701 0ustar00runnerdockerimport numpy as np import pytest from monty.serialization import loadfn from pymatgen.analysis.structure_matcher import StructureMatcher from pymatgen.entries.computed_entries import ComputedEntry from emmet.core.mobility.migrationgraph import MigrationGraphDoc @pytest.fixture(scope="session") def get_entries(test_dir): entry_Li = ComputedEntry("Li", -1.90753119) entries = loadfn(test_dir / "mobility/LiMnP2O7_batt.json") return (entries, entry_Li) @pytest.fixture(scope="session") def migration_graph_prop(): """ set the expected parameters for the migrationgraph """ expected_properties = { "LiMnP2O7": { "max_distance": 5, "num_uhops": 8, "longest_hop": 4.92647, "shortest_hop": 2.77240, "min_length_sc": 7, "minmax_num_atoms": (80, 160), } } return expected_properties @pytest.fixture(scope="session") def mg_for_sc_fields(test_dir): """ get MigrationGraph object generated with methods from pymatgen.analysis.diffusion for testing generate_sc_fields """ mg_for_sc = loadfn(test_dir / "mobility/mg_for_sc.json") return mg_for_sc @pytest.mark.skip( reason="Incompatible with Pymatgen>=2024.9.10, regression testing in progress..." ) def test_from_entries_and_distance(migration_graph_prop, get_entries): for expected in migration_graph_prop.values(): mgdoc = MigrationGraphDoc.from_entries_and_distance( battery_id="mp-1234", grouped_entries=get_entries[0], working_ion_entry=get_entries[1], hop_cutoff=5, populate_sc_fields=True, min_length_sc=7, minmax_num_atoms=(80, 160), ) mg = mgdoc.migration_graph res_d = { "max_distance": mgdoc.hop_cutoff, "num_uhops": len(mg.unique_hops), "longest_hop": sorted( mg.unique_hops.items(), key=lambda x: x[1]["hop_distance"] )[-1][1]["hop_distance"], "shortest_hop": sorted( mg.unique_hops.items(), key=lambda x: x[1]["hop_distance"] )[0][1]["hop_distance"], "min_length_sc": mgdoc.min_length_sc, "minmax_num_atoms": mgdoc.minmax_num_atoms, } for k, v in expected.items(): assert res_d[k] == pytest.approx(v, 0.01) def test_generate_sc_fields(mg_for_sc_fields): sm = StructureMatcher() ( host_sc, sc_mat, min_length, min_max_num_atoms, coords_dict, combo, ) = MigrationGraphDoc.generate_sc_fields(mg_for_sc_fields, 7, (80, 160), sm) sc_mat_inv = np.linalg.inv(sc_mat) expected_sc_list = [] for one_hop in mg_for_sc_fields.unique_hops.values(): host_sc_insert = host_sc.copy() host_sc_insert.insert(0, "Li", np.dot(one_hop["ipos"], sc_mat_inv)) host_sc_insert.insert(0, "Li", np.dot(one_hop["epos"], sc_mat_inv)) expected_sc_list.append(host_sc_insert) for one_combo in combo: hop_sc = host_sc.copy() sc_iindex, sc_eindex = list(map(int, one_combo.split("+"))) sc_isite = coords_dict[sc_iindex]["site_frac_coords"] sc_esite = coords_dict[sc_eindex]["site_frac_coords"] hop_sc.insert(0, "Li", sc_isite) hop_sc.insert(0, "Li", sc_esite) check_sc_list = [sm.fit(hop_sc, check_sc) for check_sc in expected_sc_list] assert sum(check_sc_list) >= 1 @pytest.mark.skip( reason="Incompatible with Pymatgen>=2024.9.10, regression testing in progress..." ) def test_get_distinct_hop_sites(get_entries): mgdoc = MigrationGraphDoc.from_entries_and_distance( battery_id="mp-1234", grouped_entries=get_entries[0], working_ion_entry=get_entries[1], hop_cutoff=5, populate_sc_fields=True, min_length_sc=7, minmax_num_atoms=(80, 160), ) ( dis_sites_list, dis_combo_list, combo_mapping, ) = MigrationGraphDoc.get_distinct_hop_sites( mgdoc.inserted_ion_coords, mgdoc.insert_coords_combo ) for one_test_combo in ["0+1", "0+2", "0+3", "0+4", "0+5", "0+6", "1+7", "1+2"]: assert one_test_combo in dis_combo_list assert combo_mapping == { "0+1": "9+4", "0+2": "9+8", "0+3": "9+6", "0+4": "9+16", "0+5": "9+17", "0+6": "9+13", "1+7": "4+0", "1+2": "4+8", } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0602903 emmet-core-0.84.2/tests/molecules/0000755000175100001770000000000014673360566016421 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/__init__.py0000644000175100001770000000000014673360562020514 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_atomic.py0000644000175100001770000000552114673360562021305 0ustar00runnerdockerimport json import datetime import pytest from monty.io import zopen from monty.serialization import loadfn from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.atomic import PartialChargesDoc, PartialSpinsDoc @pytest.fixture(scope="session") def test_tasks(test_dir): with zopen(test_dir / "liec_tasks.json.gz") as f: data = json.load(f) for d in data: d["last_updated"] = datetime.datetime.strptime( d["last_updated"]["string"], "%Y-%m-%d %H:%M:%S.%f" ) tasks = [TaskDocument(**t) for t in data] return tasks @pytest.fixture(scope="session") def open_shell(test_dir): task = TaskDocument(**loadfn((test_dir / "open_shell_nbo_task.json.gz"))) return task def test_partial_charges(test_tasks): # Test RESP pcd = PartialChargesDoc.from_task( test_tasks[0], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["resp"], ) assert pcd.property_name == "partial_charges" assert pcd.method == "resp" assert pcd.partial_charges == test_tasks[0].output.resp # Test Mulliken pcd = PartialChargesDoc.from_task( test_tasks[0], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["mulliken"], ) assert pcd.method == "mulliken" assert pcd.partial_charges == test_tasks[0].output.mulliken # Test Critic2 pcd = PartialChargesDoc.from_task( test_tasks[3], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["critic2"], ) assert pcd.method == "critic2" assert pcd.partial_charges == test_tasks[3].critic2["processed"]["charges"] # Test NBO pcd = PartialChargesDoc.from_task( test_tasks[4], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["nbo"], ) assert pcd.method == "nbo" nbo_charges = [ float(test_tasks[4].output.nbo["natural_populations"][0]["Charge"][str(i)]) for i in range(11) ] assert pcd.partial_charges == nbo_charges def test_partial_spins(open_shell): # Test Mulliken psd = PartialSpinsDoc.from_task( open_shell, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["mulliken"], ) assert psd.property_name == "partial_spins" assert psd.method == "mulliken" assert psd.partial_spins == [m[1] for m in open_shell.output.mulliken] # Test NBO psd = PartialSpinsDoc.from_task( open_shell, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["nbo"], ) assert psd.method == "nbo" spins = [ float(open_shell.output.nbo["natural_populations"][0]["Density"][str(i)]) for i in range(11) ] assert psd.partial_spins == spins ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_bonds.py0000644000175100001770000000377114673360562021143 0ustar00runnerdockerimport json import datetime import pytest from monty.io import zopen from monty.serialization import loadfn from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.bonds import MoleculeBondingDoc @pytest.fixture(scope="session") def test_tasks(test_dir): with zopen(test_dir / "liec_tasks.json.gz") as f: data = json.load(f) for d in data: d["last_updated"] = datetime.datetime.strptime( d["last_updated"]["string"], "%Y-%m-%d %H:%M:%S.%f" ) tasks = [TaskDocument(**t) for t in data] return tasks @pytest.fixture(scope="session") def nbo_task(test_dir): return TaskDocument(**loadfn(test_dir / "open_shell_nbo_task.json.gz")) def test_bonding(test_tasks, nbo_task): # No Critic2 or NBO ob_mee = MoleculeBondingDoc.from_task( test_tasks[0], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["OpenBabelNN + metal_edge_extender"], ) assert ob_mee.property_name == "bonding" assert ob_mee.method == "OpenBabelNN + metal_edge_extender" assert len(ob_mee.bonds) == 12 assert len(ob_mee.bonds_nometal) == 10 assert set(ob_mee.bond_types.keys()) == {"C-C", "C-H", "C-O", "Li-O"} ob_critic = MoleculeBondingDoc.from_task( test_tasks[3], molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["critic2"], ) assert ob_critic.method == "critic2" assert len(ob_critic.bonds) == 12 assert len(ob_critic.bonds_nometal) == 10 assert set(ob_critic.bond_types.keys()) == {"C-C", "C-H", "C-O", "Li-O"} assert ob_mee.molecule_graph.isomorphic_to(ob_critic.molecule_graph) nbo = MoleculeBondingDoc.from_task( nbo_task, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", preferred_methods=["nbo"], ) assert nbo.method == "nbo" assert len(nbo.bonds) == 11 assert len(nbo.bonds_nometal) == 9 assert set(nbo.bond_types.keys()) == {"C-H", "C-O", "C-Li", "Li-O"} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_metal_binding.py0000644000175100001770000000535714673360562022634 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.molecules.atomic import PartialChargesDoc, PartialSpinsDoc from emmet.core.molecules.bonds import MoleculeBondingDoc from emmet.core.molecules.thermo import MoleculeThermoDoc from emmet.core.molecules.metal_binding import MetalBindingDoc @pytest.fixture(scope="session") def base_mol(test_dir): mol = loadfn((test_dir / "metal_binding_doc" / "base_mol_doc.json").as_posix()) mol_doc = MoleculeDoc(**mol) return mol_doc @pytest.fixture(scope="session") def base_thermo(test_dir): thermo = loadfn((test_dir / "metal_binding_doc" / "thermo.json").as_posix()) thermo_doc = MoleculeThermoDoc(**thermo) return thermo_doc @pytest.fixture(scope="session") def charges(test_dir): charges = loadfn( (test_dir / "metal_binding_doc" / "partial_charges.json").as_posix() ) charges_doc = PartialChargesDoc(**charges) return charges_doc @pytest.fixture(scope="session") def spins(test_dir): spins = loadfn((test_dir / "metal_binding_doc" / "partial_spins.json").as_posix()) spins_doc = PartialSpinsDoc(**spins) return spins_doc @pytest.fixture(scope="session") def bonds(test_dir): bonds = loadfn((test_dir / "metal_binding_doc" / "bonds.json").as_posix()) bonds_doc = MoleculeBondingDoc(**bonds) return bonds_doc @pytest.fixture(scope="session") def metal_thermo(test_dir): thermo = loadfn((test_dir / "metal_binding_doc" / "metal_thermo.json").as_posix()) metal_thermo_doc = MoleculeThermoDoc(**thermo) return metal_thermo_doc @pytest.fixture(scope="session") def nometal_thermo(test_dir): thermo = loadfn((test_dir / "metal_binding_doc" / "nometal_thermo.json").as_posix()) nometal_thermo_doc = MoleculeThermoDoc(**thermo) return nometal_thermo_doc def test_metal_binding( base_mol, charges, spins, bonds, base_thermo, metal_thermo, nometal_thermo ): metal_binding = MetalBindingDoc.from_docs( method="mulliken-OB-mee", metal_indices=[5], base_molecule_doc=base_mol, partial_charges=charges, partial_spins=spins, bonding=bonds, base_thermo=base_thermo, metal_thermo={5: metal_thermo}, nometal_thermo={5: nometal_thermo}, ) assert metal_binding.binding_data[0].metal_index == 5 assert metal_binding.binding_data[0].metal_element == "Li" assert metal_binding.binding_data[0].metal_partial_charge == pytest.approx( -0.073376 ) assert metal_binding.binding_data[0].metal_assigned_charge == 0 assert metal_binding.binding_data[0].metal_assigned_spin == 2 assert metal_binding.binding_data[0].binding_free_energy == pytest.approx( 1.23790290567376 ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_mol_thermo.py0000644000175100001770000000350614673360562022177 0ustar00runnerdockerimport json import datetime import pytest from monty.io import zopen from monty.serialization import loadfn from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.thermo import MoleculeThermoDoc, get_free_energy @pytest.fixture(scope="session") def test_tasks(test_dir): with zopen(test_dir / "liec_tasks.json.gz") as f: data = json.load(f) for d in data: d["last_updated"] = datetime.datetime.strptime( d["last_updated"]["string"], "%Y-%m-%d %H:%M:%S.%f" ) tasks = [TaskDocument(**t) for t in data] return tasks @pytest.fixture(scope="session") def sp(test_dir): data = loadfn((test_dir / "closed_shell_nbo_task.json.gz").as_posix()) task = TaskDocument(**data) return task def test_thermo(test_tasks, sp): # Just energy; no free energy information doc = MoleculeThermoDoc.from_task( task=sp, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", deprecated=False, ) assert doc.property_name == "thermo" assert doc.electronic_energy == sp.output.final_energy * 27.2114 assert doc.free_energy is None # With all thermodynamic information task = test_tasks[0] doc = MoleculeThermoDoc.from_task( task, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", deprecated=False, ) assert doc.electronic_energy == task.output.final_energy * 27.2114 assert doc.total_enthalpy == task.output.enthalpy * 0.043363 assert doc.total_entropy == task.output.entropy * 0.000043363 assert doc.free_energy == get_free_energy( task.output.final_energy, task.output.enthalpy, task.output.entropy ) assert doc.rt == task.calcs_reversed[0]["gas_constant"] * 0.043363 assert doc.vibrational_enthalpy == task.calcs_reversed[0]["vib_enthalpy"] * 0.043363 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_orbitals.py0000644000175100001770000000374214673360562021653 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.orbitals import OrbitalDoc @pytest.fixture(scope="session") def closed_shell(test_dir): task = TaskDocument(**loadfn((test_dir / "closed_shell_nbo_task.json.gz"))) return task @pytest.fixture(scope="session") def open_shell(test_dir): task = TaskDocument(**loadfn((test_dir / "open_shell_nbo_task.json.gz"))) return task def test_orbital(closed_shell, open_shell): # Test closed-shell NBO parsing doc = OrbitalDoc.from_task( closed_shell, "b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", deprecated=False ) assert doc.property_name == "natural bonding orbitals" assert doc.open_shell is False assert len(doc.nbo_population) == len(closed_shell.output.initial_molecule) assert doc.nbo_population[0].valence_electrons == pytest.approx(2.75426) assert len(doc.nbo_lone_pairs) == 3 assert doc.nbo_lone_pairs[0].s_character == pytest.approx(0.02) assert doc.nbo_lone_pairs[0].atom_index == 0 assert len(doc.nbo_bonds) == 10 assert doc.nbo_bonds[0].atom1_s_character == pytest.approx(29.93) assert doc.nbo_bonds[0].atom1_index == 0 assert doc.nbo_bonds[0].atom2_index == 3 assert len(doc.nbo_interactions) == 95 assert doc.nbo_interactions[0].donor_index == 8 assert doc.nbo_interactions[0].acceptor_index == 19 assert doc.nbo_interactions[0].energy_difference == pytest.approx(0.95) assert doc.alpha_population is None assert doc.beta_population is None # Test open-shell NBO parsing doc = OrbitalDoc.from_task( open_shell, "b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2", deprecated=False ) assert doc.open_shell is True assert len(doc.nbo_population) == len(open_shell.output.initial_molecule) assert doc.alpha_population is not None assert doc.beta_population is not None assert doc.nbo_lone_pairs is None assert doc.nbo_bonds is None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_redox.py0000644000175100001770000000376314673360562021160 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.qchem.task import TaskDocument from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.molecules.thermo import MoleculeThermoDoc from emmet.core.molecules.redox import RedoxDoc @pytest.fixture(scope="session") def base_mol(test_dir): mol = loadfn((test_dir / "redox_doc" / "base_mol.json").as_posix()) mol_doc = MoleculeDoc(**mol) return mol_doc @pytest.fixture(scope="session") def base_thermo(test_dir): thermo = loadfn((test_dir / "redox_doc" / "thermo.json").as_posix()) thermo_doc = MoleculeThermoDoc(**thermo) return thermo_doc @pytest.fixture(scope="session") def red_thermo(test_dir): thermo = loadfn((test_dir / "redox_doc" / "red_thermo.json").as_posix()) thermo_doc = MoleculeThermoDoc(**thermo) return thermo_doc @pytest.fixture(scope="session") def ox_thermo(test_dir): thermo = loadfn((test_dir / "redox_doc" / "ox_thermo.json").as_posix()) thermo_doc = MoleculeThermoDoc(**thermo) return thermo_doc @pytest.fixture(scope="session") def ie_task(test_dir): task = loadfn((test_dir / "redox_doc" / "ie_task.json").as_posix()) task_doc = TaskDocument(**task) return task_doc @pytest.fixture(scope="session") def ea_task(test_dir): task = loadfn((test_dir / "redox_doc" / "ea_task.json").as_posix()) task_doc = TaskDocument(**task) return task_doc def test_redox(base_mol, base_thermo, red_thermo, ox_thermo, ie_task, ea_task): redox_doc = RedoxDoc.from_docs( base_molecule_doc=base_mol, base_thermo_doc=base_thermo, red_doc=red_thermo, ox_doc=ox_thermo, ea_doc=ea_task, ie_doc=ie_task, ) assert redox_doc.electron_affinity == pytest.approx(-3.3024638499209686) assert redox_doc.ionization_energy == pytest.approx(4.903294672107222) assert redox_doc.oxidation_free_energy == pytest.approx(3.9880055108133092) assert redox_doc.reduction_free_energy == pytest.approx(-4.237271030198826) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_summary.py0000644000175100001770000000147314673360562021530 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.molecules.summary import MoleculeSummaryDoc @pytest.fixture(scope="session") def docs_data(test_dir): raw = loadfn(test_dir / "3dfd058d8b422143d386d1ec9a723987-C1Li1O3-m1-1.json.gz") return raw def test_summary_doc(docs_data): summary_doc = MoleculeSummaryDoc.from_docs( molecule_id="3dfd058d8b422143d386d1ec9a723987-C1Li1O3-m1-1", docs=docs_data ) assert summary_doc.property_name == "summary" assert summary_doc.electronic_energy is not None assert summary_doc.total_enthalpy is not None assert summary_doc.frequencies is not None assert summary_doc.nbo_population is None assert summary_doc.electron_affinity is None assert summary_doc.bonds is not None assert summary_doc.binding_data is None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/molecules/test_vibration.py0000644000175100001770000000202114673360562022016 0ustar00runnerdockerimport json import datetime import pytest from monty.io import zopen from emmet.core.qchem.task import TaskDocument from emmet.core.molecules.vibration import VibrationDoc @pytest.fixture(scope="session") def test_tasks(test_dir): with zopen(test_dir / "liec_tasks.json.gz") as f: data = json.load(f) for d in data: d["last_updated"] = datetime.datetime.strptime( d["last_updated"]["string"], "%Y-%m-%d %H:%M:%S.%f" ) tasks = [TaskDocument(**t) for t in data] return tasks def test_vibration(test_tasks): task = test_tasks[0] vib_doc = VibrationDoc.from_task( task, molecule_id="b9ba54febc77d2a9177accf4605767db-C1Li2O3-1-2" ) assert vib_doc.property_name == "vibrations" assert len(vib_doc.frequencies) == 27 assert len(vib_doc.frequency_modes) == 27 assert len(vib_doc.ir_intensities) == 27 assert vib_doc.frequencies[0] == pytest.approx(49.47) assert vib_doc.ir_intensities[0] == 93.886 assert vib_doc.ir_activities[0] == "YES" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0602903 emmet-core-0.84.2/tests/openmm_md/0000755000175100001770000000000014673360566016404 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/openmm_md/__init__.py0000644000175100001770000000000014673360562020477 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/openmm_md/test_tasks.py0000644000175100001770000000270614673360562021143 0ustar00runnerdockerfrom pathlib import Path import numpy as np from emmet.core.openmm.tasks import CalculationOutput def test_calc_output_from_directory(test_dir): output_dir = test_dir / "openmm" / "calc_output" # Call the from_directory function calc_out = CalculationOutput.from_directory( output_dir, "state.csv", "trajectory.dcd", elapsed_time=10.0, ) # Assert the expected attributes of the CalculationOutput object assert isinstance(calc_out, CalculationOutput) assert calc_out.dir_name == str(output_dir) assert calc_out.elapsed_time == 10.0 assert calc_out.traj_file == "trajectory.dcd" assert calc_out.state_file == "state.csv" # Assert the contents of the state data assert np.array_equal(calc_out.steps_reported[:3], [100, 200, 300]) assert np.allclose(calc_out.potential_energy[:3], [-26192.4, -25648.6, -25149.6]) assert np.allclose(calc_out.kinetic_energy[:3], [609.4, 1110.4, 1576.4], atol=0.1) assert np.allclose(calc_out.total_energy[:3], [-25583.1, -24538.1, -23573.2]) assert np.allclose(calc_out.temperature[:3], [29.6, 54.0, 76.6], atol=0.1) assert np.allclose(calc_out.volume[:3], [21.9, 21.9, 21.9], atol=0.1) assert np.allclose(calc_out.density[:3], [1.0, 0.99, 0.99], atol=0.1) # Assert the existence of the DCD and state files assert Path(calc_out.dir_name, calc_out.traj_file).exists() assert Path(calc_out.dir_name, calc_out.state_file).exists() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0602903 emmet-core-0.84.2/tests/qchem/0000755000175100001770000000000014673360566015526 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/qchem/__init__.py0000644000175100001770000000000014673360562017621 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/qchem/test_calc_types.py0000644000175100001770000000125014673360562021257 0ustar00runnerdockerfrom emmet.core.qchem.calc_types.calc_types import ( FUNCTIONALS, BASIS_SETS, SOLVENT_MODELS, TASK_TYPES, ) _REFERENCE_MEMBER_COUNT = { "LevelOfTheory": len(FUNCTIONALS) * len(BASIS_SETS) * len(SOLVENT_MODELS), "TaskType": len(TASK_TYPES), } _REFERENCE_MEMBER_COUNT["CalcType"] = ( _REFERENCE_MEMBER_COUNT["LevelOfTheory"] * _REFERENCE_MEMBER_COUNT["TaskType"] ) def test_enums(): from emmet.core.qchem.calc_types import enums as qchem_enums for k, count in _REFERENCE_MEMBER_COUNT.items(): # Test that we have expected number of enum members curr_enum = getattr(qchem_enums, k, None) assert len(curr_enum) == count ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/qchem/test_molecules.py0000644000175100001770000000411114673360562021120 0ustar00runnerdockerimport json import datetime import pytest from monty.io import zopen from emmet.core.qchem.calc_types import TaskType from emmet.core.qchem.molecule import MoleculeDoc from emmet.core.qchem.task import TaskDocument try: from openbabel.openbabel import OBAlign _ = OBAlign() has_eigen = True except ImportError: has_eigen = False @pytest.fixture(scope="session") def test_tasks(test_dir): with zopen(test_dir / "liec_tasks.json.gz") as f: data = json.load(f) for d in data: d["last_updated"] = datetime.datetime.strptime( d["last_updated"]["string"], "%Y-%m-%d %H:%M:%S.%f" ) tasks = [TaskDocument(**t) for t in data] return tasks @pytest.mark.skip(reason="Pymatgen OBAlign needs fix") @pytest.mark.skipif( not has_eigen, reason="OBAlign missing, presumably due to lack of Eigen" ) def test_make_mol(test_tasks): molecule = MoleculeDoc.from_tasks(test_tasks) assert molecule.formula_alphabetical == "C3 H4 Li1 O3" assert len(molecule.task_ids) == 5 assert len(molecule.entries) == 5 bad_task_group = [ task for task in test_tasks if task.task_type not in [ TaskType.Geometry_Optimization, TaskType.Frequency_Flattening_Geometry_Optimization, ] ] with pytest.raises(Exception): MoleculeDoc.from_tasks(bad_task_group) @pytest.mark.skip(reason="Pymatgen OBAlign needs fix") @pytest.mark.skipif( not has_eigen, reason="OBAlign missing, presumably due to lack of Eigen" ) def test_make_deprecated_mol(test_tasks): bad_task_group = [ task for task in test_tasks if task.task_type not in [ TaskType.Geometry_Optimization, TaskType.Frequency_Flattening_Geometry_Optimization, ] ] molecule = MoleculeDoc.construct_deprecated_molecule(bad_task_group) assert molecule.deprecated assert molecule.formula_alphabetical == "C3 H4 Li1 O3" assert len(molecule.task_ids) == 4 assert molecule.entries is None def test_schema(): MoleculeDoc.schema() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/qchem/test_qchem.py0000644000175100001770000001325314673360562020234 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.qchem.calc_types import ( LevelOfTheory, TaskType, level_of_theory, task_type, solvent, lot_solvent_string, ) from emmet.core.qchem.task import TaskDocument from emmet.core.mpid import MPID def test_task_type(): task_types = [ "Single Point", "Geometry Optimization", "Frequency Analysis", "Frequency Flattening Geometry Optimization", "Transition State Geometry Optimization", "Frequency Flattening Transition State Geometry Optimization", ] inputs = [ {"rem": {"job_type": "sp"}}, {"rem": {"job_type": "opt"}}, {"rem": {"job_type": "freq"}}, {"rem": {"job_type": "opt"}}, {"rem": {"job_type": "ts"}}, {"rem": {"job_type": "freq"}}, ] special_run_types = [ None, None, None, "frequency_flattener", None, "ts_frequency_flattener", ] for _type, orig, special in zip(task_types, inputs, special_run_types): assert task_type(orig, special_run_type=special) == TaskType(_type) def test_level_of_theory(): lots = [ "wB97X-V/def2-TZVPPD/SMD", "wB97X-D/def2-SVPD/PCM", "wB97M-V/6-31g*/VACUUM", ] parameters = [ { "rem": { "method": "wb97xv", "basis": "def2-tzvppd", "solvent_method": "smd", }, "smx": {"solvent": "other"}, }, { "rem": {"method": "wb97xd", "basis": "def2-svpd", "solvent_method": "pcm"}, "pcm": {"theory": "cpcm"}, "solvent": {"dielectric": 78.39}, }, {"rem": {"method": "wb97mv", "basis": "6-31g*"}}, ] for lot, params in zip(lots, parameters): assert level_of_theory(params) == LevelOfTheory(lot) def test_solvent(): # Vacuum calc assert solvent({"rem": {"method": "wb97mv", "basis": "6-31g*"}}) == "NONE" # PCM - non-default assert ( solvent( { "rem": { "method": "wb97xd", "basis": "def2-svpd", "solvent_method": "pcm", }, "pcm": {"theory": "cpcm"}, "solvent": {"dielectric": 20}, } ) == "DIELECTRIC=20,00" ) # PCM - default assert ( solvent( { "rem": { "method": "wb97xd", "basis": "def2-svpd", "solvent_method": "pcm", }, "pcm": {"theory": "cpcm"}, } ) == "DIELECTRIC=78,39" ) # SMD - custom solvent assert ( solvent( { "rem": { "method": "wb97xv", "basis": "def2-tzvppd", "solvent_method": "smd", }, "smx": {"solvent": "other"}, }, custom_smd="4.9,1.558,0.0,0.576,49.94,0.667,0.0", ) == "DIELECTRIC=4,900;N=1,558;ALPHA=0,000;BETA=0,576;GAMMA=49,940;PHI=0,667;PSI=0,000" ) # SMD - missing custom_solvent with pytest.raises(ValueError): solvent( { "rem": { "method": "wb97xv", "basis": "def2-tzvppd", "solvent_method": "smd", }, "smx": {"solvent": "other"}, } ) # SMD - existing solvent assert ( solvent( { "rem": { "method": "wb97xv", "basis": "def2-tzvppd", "solvent_method": "smd", }, "smx": {"solvent": "ethanol"}, } ) == "SOLVENT=ETHANOL" ) # SMD - unknown solvent assert ( solvent( { "rem": { "method": "wb97xv", "basis": "def2-tzvppd", "solvent_method": "smd", }, } ) == "SOLVENT=WATER" ) def test_lot_solv(): answer = "wB97X-D/def2-SVPD/PCM(DIELECTRIC=78,39)" params = { "rem": {"method": "wb97xd", "basis": "def2-svpd", "solvent_method": "pcm"}, "pcm": {"theory": "cpcm"}, "solvent": {"dielectric": 78.39}, } assert lot_solvent_string(params) == answer def test_unexpected_lots(): # No method provided with pytest.raises(ValueError): level_of_theory({"rem": {"basis": "def2-qzvppd"}}) # No basis provided with pytest.raises(ValueError): level_of_theory({"rem": {"method": "b3lyp"}}) # Unknown dispersion correction with pytest.raises(ValueError): level_of_theory({"rem": {"method": "b3lyp", "dft_d": "empirical_grimme"}}) # Unknown functional with pytest.raises(ValueError): level_of_theory({"rem": {"method": "r2scan"}}) # Unknown basis with pytest.raises(ValueError): level_of_theory({"rem": {"method": "wb97xd3", "basis": "aug-cc-pVTZ"}}) @pytest.fixture(scope="session") def tasks(test_dir): data = loadfn((test_dir / "random_bh4_entries.json.gz").as_posix()) return [TaskDocument(**d) for d in data] def test_computed_entry(tasks): entries = [task.entry for task in tasks] ids = {e["entry_id"] for e in entries} expected = { MPID(i) for i in { 675022, 674849, 674968, 674490, 674950, 674338, 674322, 675078, 674385, 675041, } } assert ids == expected ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_absorption.py0000644000175100001770000000366014673360562020223 0ustar00runnerdockerimport pytest from pymatgen.core import Structure from monty.serialization import loadfn from emmet.core.absorption import AbsorptionDoc from emmet.core.utils import jsanitize import numpy as np @pytest.fixture(scope="session") def absorption_test_data(test_dir): return loadfn(test_dir / "sample_absorptions.json") def test_absorption_doc(absorption_test_data): absorption_coeff = np.array( [ 0, 5504161142.509, 16485480924.4252, 41235259342.4927, 76990619286.8861, 109929386572.273, 164921201202.527, 230913400825.579, 285790460873.292, 371002598552.062, ] ) imag_dielectric = [0.0, 0.0002, 0.0003] energies = [ 0, 0.0309, 0.0617, 0.0926, 0.1235, 0.1543, 0.1852, 0.2161, 0.2469, 0.2778, ] data = absorption_test_data structure = Structure.from_dict(jsanitize(data["input"]["structure"])) task_id = data["task_id"] kpoints = data["orig_inputs"]["kpoints"] doc = AbsorptionDoc.from_structure( structure=structure, material_id="mp-{}".format(task_id), task_id=task_id, deprecated=False, energies=data["output"]["dielectric"]["energy"], real_d=data["output"]["dielectric"]["real"], imag_d=data["output"]["dielectric"]["imag"], absorption_co=data["output"]["optical_absorption_coeff"], bandgap=data["output"]["bandgap"], nkpoints=kpoints.num_kpts, is_hubbard=False, ) assert doc is not None assert doc.property_name == "Optical absorption spectrum" assert doc.energies[0:10] == energies assert doc.material_id == "mp-1316" assert doc.absorption_coefficient[0:10] == list(absorption_coeff) assert doc.average_imaginary_dielectric[0:3] == imag_dielectric assert doc.bandgap == 4.4652 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_calculation.py0000644000175100001770000001620514673360562020340 0ustar00runnerdockerimport pytest from tests.conftest import assert_schemas_equal, get_test_object def test_init(): from emmet.core.vasp.calculation import ( Calculation, CalculationInput, CalculationOutput, RunStatistics, ) calc_input = CalculationInput() assert calc_input is not None calc_input = CalculationOutput() assert calc_input is not None calc_input = RunStatistics() assert calc_input is not None calc_input = Calculation() assert calc_input is not None @pytest.mark.parametrize( "object_name,task_name", [ pytest.param("SiOptimizeDouble", "relax1", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_calculation_input(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from pymatgen.io.vasp import Vasprun from emmet.core.vasp.calculation import CalculationInput test_object = get_test_object(object_name) vasprun_file = test_dir / "vasp" / test_object.folder vasprun_file /= test_object.task_files[task_name]["vasprun_file"] test_doc = CalculationInput.from_vasprun(Vasprun(vasprun_file)) valid_doc = test_object.task_doc["calcs_reversed"][0]["input"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( "object_name,task_name", [ pytest.param("SiOptimizeDouble", "relax2", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_calculation_output(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from pymatgen.io.vasp import Outcar, Poscar, Vasprun from emmet.core.vasp.calculation import CalculationOutput test_object = get_test_object(object_name) folder = test_dir / "vasp" / test_object.folder vasprun_file = folder / test_object.task_files[task_name]["vasprun_file"] outcar_file = folder / test_object.task_files[task_name]["outcar_file"] contcar_file = folder / test_object.task_files[task_name]["contcar_file"] vasprun = Vasprun(vasprun_file) outcar = Outcar(outcar_file) contcar = Poscar.from_file(contcar_file) test_doc = CalculationOutput.from_vasp_outputs(vasprun, outcar, contcar) valid_doc = test_object.task_doc["calcs_reversed"][0]["output"] assert_schemas_equal(test_doc, valid_doc) assert test_doc.efermi == vasprun.get_band_structure(efermi="smart").efermi # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) def test_mag_calculation_output(test_dir): from pymatgen.io.vasp import Outcar, Poscar, Vasprun from emmet.core.vasp.calculation import CalculationOutput # Test magnetic properties dir_name = test_dir / "vasp" / "magnetic_run" d = CalculationOutput.from_vasp_outputs( Vasprun(dir_name / "vasprun.xml.gz"), Outcar(dir_name / "OUTCAR.gz"), Poscar.from_file(dir_name / "CONTCAR.gz"), ) assert d.model_dump()["mag_density"] == pytest.approx(0.19384725901794095) @pytest.mark.parametrize( "object_name,task_name", [ pytest.param("SiOptimizeDouble", "relax1", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_run_statistics(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from pymatgen.io.vasp import Outcar from emmet.core.vasp.calculation import RunStatistics test_object = get_test_object(object_name) folder = test_dir / "vasp" / test_object.folder outcar_file = folder / test_object.task_files[task_name]["outcar_file"] outcar = Outcar(outcar_file) test_doc = RunStatistics.from_outcar(outcar) valid_doc = test_object.task_doc["calcs_reversed"][0]["output"]["run_stats"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( "object_name,task_name", [ pytest.param("SiOptimizeDouble", "relax2", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_calculation(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from emmet.core.vasp.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "vasp" / test_object.folder files = test_object.task_files[task_name] test_doc, objects = Calculation.from_vasp_files(dir_name, task_name, **files) valid_doc = test_object.task_doc["calcs_reversed"][0] assert_schemas_equal(test_doc, valid_doc) assert set(objects.keys()) == set(test_object.objects[task_name]) # check bader and ddec6 keys exist assert test_doc.bader is None assert test_doc.ddec6 is None # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) def test_calculation_run_type_metagga(test_dir): # Test to ensure that meta-GGA calculations are correctly identified # The VASP files were kindly provided by @Andrew-S-Rosen in issue #960 from emmet.core.vasp.calculation import Calculation calc_input, _ = Calculation.from_vasp_files( dir_name=test_dir / "vasp" / "r2scan_relax", task_name="relax", vasprun_file="vasprun.xml.gz", outcar_file="OUTCAR.gz", contcar_file="CONTCAR.gz", ) assert "r2SCAN" in repr(calc_input.run_type) assert "r2SCAN" in repr(calc_input.calc_type) def test_PotcarSpec(test_dir): from emmet.core.vasp.calculation import PotcarSpec from pymatgen.io.vasp import PotcarSingle, Potcar try: # First test, PotcarSingle object potcar = PotcarSingle.from_symbol_and_functional(symbol="Si", functional="PBE") ps_spec = PotcarSpec.from_potcar_single(potcar_single=potcar) assert ps_spec.titel == potcar.symbol assert ps_spec.hash == potcar.md5_header_hash assert ps_spec.summary_stats == potcar._summary_stats # Second test, Potcar object containing mulitple PotcarSingle obejcts potcars = Potcar(symbols=["Ga_d", "As"], functional="PBE") ps_spec = PotcarSpec.from_potcar(potcar=potcars) for ips, ps in enumerate(ps_spec): assert ps.titel == potcars[ips].symbol assert ps.hash == potcars[ips].md5_header_hash assert ps.summary_stats == potcars[ips]._summary_stats except (OSError, ValueError): # missing Pymatgen POTCARs, cannot perform test assert True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_chemenv.py0000644000175100001770000000216014673360562017462 0ustar00runnerdockerimport pytest from emmet.core.chemenv import ChemEnvDoc from pymatgen.core import Structure from . import test_structures @pytest.mark.parametrize("structure", test_structures.values()) def test_chemenv(structure: Structure): """Very simple test to make sure this actually works""" print(f"Should work : {structure.composition}") doc = ChemEnvDoc.from_structure( structure=structure, material_id=33, deprecated=False ) valences = [getattr(site.specie, "oxi_state", None) for site in structure] valences = [v for v in valences if v is not None] if len(valences) == len(structure): assert doc.model_dump()["warnings"] is None # elif structure.composition.almost_equals(Composition("CsCl")): # # We do not have reference polyhedra above a certain number of neighbors. # # ChemEnv cannot deliver an answer without oxidation states. # assert doc.model_dump()["warnings"] == "ChemEnv algorithm failed." else: assert ( doc.model_dump()["warnings"] == "No oxidation states available. Cation-anion bonds cannot be identified." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_defects.py0000644000175100001770000000053214673360562017453 0ustar00runnerdockerfrom emmet.core.defect import DefectTaskDoc def test_parsing_defect_directory(test_dir): from pymatgen.analysis.defects.core import Defect defect_run = test_dir / "vasp/defect_run" defect_task = DefectTaskDoc.from_directory(defect_run) assert isinstance(defect_task.defect, Defect) assert defect_task.defect_name == "O_Te" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_elasticity.py0000644000175100001770000000507414673360562020216 0ustar00runnerdockerfrom typing import List import numpy as np import pytest from monty.serialization import loadfn from pymatgen.analysis.elasticity import Deformation, Strain, Stress from pymatgen.core.tensors import Tensor, TensorMapping from emmet.core.elasticity import ( ElasticityDoc, generate_derived_fitting_data, generate_primary_fitting_data, ) @pytest.fixture(scope="session") def fitting_data(test_dir): """Primary fitting data""" data = loadfn(test_dir / "elasticity/SiC_fitting_data.json") structure = data["structure"] deformations = [Deformation(x) for x in data["deformations"]] stresses = [Stress(x) for x in data["stresses"]] equilibrium_stress = Stress(data["equilibrium_stress"]) return structure, deformations, stresses, equilibrium_stress @pytest.fixture(scope="session") def reference_data(test_dir): """Reference data""" data = loadfn(test_dir / "elasticity/SiC_reference_data.json") derived_strains = [Strain(x) for x in data["derived_strains"]] derived_stresses = [Stress(x) for x in data["derived_stresses"]] elastic_tensor_raw = data["elastic_tensor_raw"] return derived_strains, derived_stresses, elastic_tensor_raw def test_generate_derived_fitting_data(fitting_data, reference_data): structure, deformations, stresses, equilibrium_stress = fitting_data ref_d_strains, ref_d_stresses, _ = reference_data strains, _, _, _ = generate_primary_fitting_data(deformations, stresses) _, d_strains, d_stresses, _ = generate_derived_fitting_data( structure, strains, stresses ) def sequence_of_tensors_equal(a: List[Tensor], b: List[Tensor]): mapping = TensorMapping( tensors=a, values=[None for _ in range(len(a))], tol=1e-5 ) for i, x in enumerate(b): if x not in mapping: raise AssertionError( f"Cannot find a corresponding tensor in `a` that matches tensor " f"{i} in `b`" ) sequence_of_tensors_equal(d_strains, ref_d_strains) sequence_of_tensors_equal(d_stresses, ref_d_stresses) def test_from_deformations_and_stresses(fitting_data, reference_data): structure, deformations, stresses, equilibrium_stress = fitting_data _, _, ref_elastic_tensor = reference_data doc = ElasticityDoc.from_deformations_and_stresses( structure=structure, deformations=deformations, stresses=stresses, equilibrium_stress=equilibrium_stress, material_id=1, ) assert np.allclose(doc.elastic_tensor.raw, ref_elastic_tensor, atol=1e-6) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_electrodes.py0000644000175100001770000001103614673360562020170 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from pymatgen.apps.battery.conversion_battery import ConversionElectrode from pymatgen.apps.battery.insertion_battery import InsertionElectrode from pymatgen.core import Composition, Element from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.entries.computed_entries import ComputedEntry from emmet.core.electrode import ( ConversionElectrodeDoc, ConversionVoltagePairDoc, InsertionElectrodeDoc, InsertionVoltagePairDoc, get_battery_formula, ) @pytest.fixture(scope="session") def insertion_elec(test_dir): """ Recycle the test cases from pymatgen """ entry_Li = ComputedEntry("Li", -1.90753119) # more cases can be added later if problems are found entries_LTO = loadfn(test_dir / "LiTiO2_batt.json") ie_LTO = InsertionElectrode.from_entries(entries_LTO, entry_Li) d = { "LTO": (ie_LTO, entries_LTO[0].structure, entry_Li), } return d @pytest.fixture(scope="session") def conversion_elec(test_dir): conversion_electrodes = {} entries_LCO = loadfn(test_dir / "LiCoO2_batt.json") c = ConversionElectrode.from_composition_and_entries( Composition("LiCoO2"), entries_LCO, working_ion_symbol="Li" ) conversion_electrodes["LiCoO2"] = { "working_ion": "Li", "CE": c, "entries": entries_LCO, } expected_properties = { "LiCoO2": { "average_voltage": 2.26940307125, "capacity_grav": 903.19752911225669, "capacity_vol": 2903.35804724, "energy_grav": 2049.7192465127678, "energy_vol": 6588.8896693479574, } } return { k: (conversion_electrodes[k], expected_properties[k]) for k in conversion_electrodes.keys() } def test_InsertionDocs(insertion_elec): for k, (elec, struct, wion_entry) in insertion_elec.items(): # Make sure that main document can be created using an InsertionElectrode object ie = InsertionElectrodeDoc.from_entries( grouped_entries=elec.stable_entries, working_ion_entry=wion_entry, battery_id="mp-1234", ) assert ie.average_voltage == elec.get_average_voltage() assert len(ie.material_ids) > 2 # Make sure that each adjacent pair can be converted into a sub electrode for sub_elec in elec.get_sub_electrodes(adjacent_only=True): vp = InsertionVoltagePairDoc.from_sub_electrode(sub_electrode=sub_elec) assert vp.average_voltage == sub_elec.get_average_voltage() assert "mp" in vp.id_charge # assert type(ie.model_dump()["host_structure"]) == dict # This might be a requirement in the future def test_ConversionDocs_from_entries(conversion_elec): for k, (elec, expected) in conversion_elec.items(): vp = ConversionElectrodeDoc.from_composition_and_entries( Composition(k), entries=elec["entries"], working_ion_symbol=elec["working_ion"], battery_id="mp-1234", thermo_type="GGA_GGA+U", ) res_d = vp.model_dump() for k, v in expected.items(): assert res_d[k] == pytest.approx(v, 0.01) def test_ConversionDocs_from_composition_and_pd(conversion_elec, test_dir): entries_LCO = loadfn(test_dir / "LiCoO2_batt.json") pd = PhaseDiagram(entries_LCO) for k, (elec, expected) in conversion_elec.items(): vp = ConversionElectrodeDoc.from_composition_and_pd( comp=Composition(k), pd=pd, working_ion_symbol=elec["working_ion"], battery_id="mp-1234", thermo_type="GGA_GGA+U", ) res_d = vp.model_dump() for k, v in expected.items(): assert res_d[k] == pytest.approx(v, 0.01) def test_ConversionDocs_from_sub_electrodes(conversion_elec): for k, (elec, expected) in conversion_elec.items(): for sub_elec in elec["CE"].get_sub_electrodes(adjacent_only=True): vp = ConversionVoltagePairDoc.from_sub_electrode(sub_electrode=sub_elec) assert vp.average_voltage == sub_elec.get_average_voltage() def test_get_battery_formula(): test_cases = [ (Composition("Li2CoO3"), Composition("Li7(CoO3)2"), Element("Li")), (Composition("Al4(CoO4)3"), Composition("Al2CoO4"), Element("Al")), (Composition("Li17(Co4O9)2"), Composition("Li21(Co4O9)2"), Element("Li")), ] results = [get_battery_formula(*case) for case in test_cases] assert results == ["Li2-3.5CoO3", "Al1.33-2CoO4", "Li8.5-10.5Co4O9"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_electronic_structure.py0000644000175100001770000000554214673360562022313 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from emmet.core.electronic_structure import ElectronicStructureDoc @pytest.fixture(scope="session") def structure(test_dir): """ Fe (mp-13) structure with correct magmoms """ structure = loadfn(test_dir / "electronic_structure/Fe_structure.json") return structure @pytest.fixture(scope="session") def bandstructure(test_dir): """ Fe (mp-13) line-mode band structure """ bs = loadfn(test_dir / "electronic_structure/Fe_bs.json") return bs @pytest.fixture(scope="session") def dos(test_dir): """ Fe (mp-13) dos """ dos = loadfn(test_dir / "electronic_structure/Fe_dos.json") return dos def test_from_bsdos_1(bandstructure, dos, structure): es_doc = ElectronicStructureDoc.from_bsdos( material_id="mp-13", dos={"mp-1671247": dos}, is_gap_direct=False, is_metal=True, deprecated=False, setyawan_curtarolo={"mp-1056141": bandstructure}, structures={"mp-1671247": structure, "mp-1056141": structure}, ) assert str(es_doc.material_id) == "mp-13" assert es_doc.band_gap == 0.0 assert es_doc.cbm is None assert es_doc.vbm is None assert es_doc.efermi == 5.18804178 assert es_doc.is_gap_direct is False assert es_doc.is_metal is True assert str(es_doc.magnetic_ordering) == "Ordering.FM" assert str(es_doc.bandstructure.setyawan_curtarolo.task_id) == "mp-1056141" assert es_doc.bandstructure.setyawan_curtarolo.band_gap == 0.0 assert es_doc.bandstructure.setyawan_curtarolo.efermi == 5.18804178 assert es_doc.bandstructure.setyawan_curtarolo.nbands == 96.0 @pytest.fixture def bandstructure_fs(test_dir): bs = loadfn(test_dir / "electronic_structure/es_bs_objs.json.gz") return bs @pytest.fixture def dos_fs(test_dir): dos = loadfn(test_dir / "electronic_structure/es_dos_objs.json.gz") return dos def test_from_bsdos_2(bandstructure_fs, dos_fs): dos = dos_fs[0]["data"] bs = bandstructure_fs[0]["data"] es_doc = ElectronicStructureDoc.from_bsdos( material_id="mp-25375", dos={"mp-823888": dos}, is_gap_direct=False, is_metal=True, deprecated=False, setyawan_curtarolo={"mp-1612487": bs}, ) assert str(es_doc.material_id) == "mp-25375" assert es_doc.band_gap == 0.0 assert es_doc.cbm == 2.7102 assert es_doc.vbm == 2.9396 assert es_doc.efermi == 2.75448867 assert es_doc.is_gap_direct is False assert es_doc.is_metal is True assert str(es_doc.magnetic_ordering) == "Ordering.NM" assert str(es_doc.bandstructure.setyawan_curtarolo.task_id) == "mp-1612487" assert es_doc.bandstructure.setyawan_curtarolo.band_gap == 1.9916 assert es_doc.bandstructure.setyawan_curtarolo.efermi == 2.49084067 assert es_doc.bandstructure.setyawan_curtarolo.nbands == 64.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_magnetism.py0000644000175100001770000000171014673360562020021 0ustar00runnerdockerimport pytest from emmet.core.magnetism import MagnetismDoc from emmet.core.utils import jsanitize from monty.serialization import loadfn from pymatgen.core import Structure def test_magnetism_doc(test_dir): test_orderings = {"mp-1034331": "FM", "mp-753472": "NM"} for material in loadfn(test_dir / "magnetism/magnetism_mats_sample.json"): structure = Structure.from_dict(jsanitize(material["structure"])) total_magnetization = material["magnetism"]["total_magnetization"] material_id = material["task_id"] doc = MagnetismDoc.from_structure( structure=structure, material_id=material_id, total_magnetization=total_magnetization, deprecated=False, ) assert doc is not None assert doc.total_magnetization == pytest.approx(abs(total_magnetization)) if material_id in test_orderings: assert doc.ordering == test_orderings[material_id] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_ml.py0000644000175100001770000000403614673360562016451 0ustar00runnerdockerimport pytest # from matcalc.utils import get_universal_calculator from pymatgen.core import Structure from pymatgen.util.testing import PymatgenTest from emmet.core.elasticity import BulkModulus, ElasticTensorDoc, ShearModulus from emmet.core.ml import MLDoc # if TYPE_CHECKING: # from ase.calculators.calculator import Calculator struct = PymatgenTest.get_structure("Si") expected_keys = { # -- metadata -- "material_id": str, "structure": Structure, "deprecated": bool, "matcalc_version": type(None), # str, "model_name": type(None), # str, "model_version": type(None), # str, # -- relaxation -- "final_structure": Structure, "energy": float, "volume": float, "a": float, "b": float, "c": float, "alpha": float, "beta": float, "gamma": float, # -- eos -- "eos": dict, "bulk_modulus_bm": float, # -- phonon -- "temperatures": list, "free_energy": list, "entropy": list, "heat_capacity": list, # -- elasticity -- "elastic_tensor": ElasticTensorDoc, "shear_modulus": ShearModulus, "bulk_modulus": BulkModulus, "young_modulus": float, } # @pytest.mark.parametrize( # ("calculator", "prop_kwargs"), # [ # (get_universal_calculator("chgnet"), None), # ("M3GNet-MP-2021.2.8-PES", {"ElasticityCalc": {"relax_structure": False}}), # ], # ) @pytest.mark.skip(reason="Temporary skip. Needs attention.") def test_ml_doc(calculator, prop_kwargs: dict) -> None: doc = MLDoc( structure=struct, calculator=calculator, material_id="mp-33", deprecated=False, prop_kwargs=prop_kwargs, ) # check that all expected keys are present missing = sorted({*expected_keys} - {*doc.__dict__}) assert not missing, f"keys {missing=}" # check that all keys have expected type for key, typ in expected_keys.items(): actual = getattr(doc, key) assert isinstance( actual, typ ), f"{key=} expected type={typ.__name__}, got {type(actual).__name__}" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_molecule_metadata.py0000644000175100001770000000326514673360562021511 0ustar00runnerdockerimport pytest from pymatgen.core import Molecule from pymatgen.core.composition import Composition from pymatgen.core.periodic_table import Element from emmet.core.structure import MoleculeMetadata @pytest.fixture() def molecule(): return Molecule(species=["O", "O"], coords=[[0, 0, 0], [0.0, 0.0, 1.16]]) def test_from_molecule(molecule): metadata = MoleculeMetadata.from_molecule(molecule, extra_field="extra_value") assert metadata.natoms == 2 assert metadata.elements == [Element("O")] assert metadata.nelements == 1 assert metadata.composition == Composition("O2") assert metadata.composition_reduced == Composition("O2").reduced_composition assert metadata.formula_alphabetical == "O2" assert metadata.formula_pretty == "O2" assert metadata.formula_anonymous == "A" assert metadata.chemsys == "O" assert metadata.symmetry.point_group == "D*h" assert metadata.charge == 0 assert metadata.spin_multiplicity == 1 assert metadata.nelectrons == 16 assert metadata.model_config.get("extra") is None, ( "Should not allow extra field to keep validation strict, if " "extra fields are needed, set extra='allow' on a subclass" ) assert metadata.model_dump().get("extra_field") is None def test_from_comp(molecule): metadata = MoleculeMetadata.from_composition(molecule.composition) assert metadata.elements == [Element("O")] assert metadata.nelements == 1 assert metadata.composition == Composition("O2") assert metadata.composition_reduced == Composition("O2").reduced_composition assert metadata.formula_pretty == "O2" assert metadata.formula_anonymous == "A" assert metadata.chemsys == "O" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_mpid.py0000644000175100001770000000357614673360562017002 0ustar00runnerdockerfrom emmet.core.mpid import MPID, MPculeID import pytest def test_mpid(): assert MPID("mp-3") == MPID("mp-3") assert MPID("mp-3") < 3 assert MPID("mp-3") < MPID("np-3") assert MPID("mp-3") > MPID("mp-2") assert 3 > MPID("mp-3") assert MPID(MPID("mp-1234")) < MPID(1234) assert "mp-1234" < MPID(1234) assert MPID("1234") > MPID("mp-1234") assert MPID("1234") == MPID(1234) assert MPID("1234") == "1234" assert MPID("mp-12345") > MPID("mp-1234") assert min( [MPID("mp-44545"), MPID("mp-33"), MPID("mp-2134234"), MPID(33), MPID("33")] ) == MPID("mp-33") assert ( len(set([MPID("mp-33"), MPID("mp-44545"), MPID("mp-33"), MPID("mp-2134234")])) == 3 ) MPID(3) ulid_mpid = MPID("01HMVV88CCQ6JQ2Y1N8F3ZTVWP-Li") assert ulid_mpid.parts == ("01HMVV88CCQ6JQ2Y1N8F3ZTVWP", 0) with pytest.raises(ValueError, match="MPID string representation must follow"): MPID("GGIRADF") def test_mpculeid(): assert MPculeID("b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2") == MPculeID( "b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2" ) assert ( MPculeID("b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2") == "b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2" ) assert MPculeID("b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2") < MPculeID( "b9ba54febc77d2a9177accf4605767db-F6Li1P1-2-1" ) assert MPculeID("b9ba54febc77d2a9177accf4605767db-F6Li1P1-2-1") > MPculeID( "b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2" ) assert MPculeID("mpcule-98bab8f3795eae3fd8e28f5ff2d476e8-C3H8-0-1") < MPculeID( "b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2" ) def test_to_str(): assert str(MPID("mp-149")) == "mp-149" assert ( str(MPculeID("b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2")) == "b9ba54febc77d2a9177accf4605767db-F6Li1P1-1-2" ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_optimade.py0000644000175100001770000000130014673360562017632 0ustar00runnerdockerfrom datetime import datetime import pytest from pymatgen.core.structure import Structure from . import test_structures try: from emmet.core.optimade import OptimadeMaterialsDoc except Exception: pytest.skip("could not import 'optimade' ", allow_module_level=True) @pytest.mark.xfail(reason="Optimade + fastapi issues.") @pytest.mark.parametrize("structure", test_structures.values()) def test_oxidation_state(structure: Structure): """Very simple test to make sure this actually works""" print(f"Should work : {structure.composition}") doc = OptimadeMaterialsDoc.from_structure( structure, material_id=33, last_updated=datetime.utcnow() ) assert doc is not None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_oxidation_states.py0000644000175100001770000000100514673360562021413 0ustar00runnerdockerimport pytest from emmet.core.oxidation_states import OxidationStateDoc from pymatgen.core import Structure from . import test_structures @pytest.mark.parametrize("structure", test_structures.values()) def test_oxidation_state(structure: Structure): """Very simple test to make sure this actually works""" print(f"Should work : {structure.composition}") doc = OxidationStateDoc.from_structure(structure, material_id=33, deprecated=False) assert doc is not None assert doc.structure is not None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_polar.py0000644000175100001770000002267514673360562017167 0ustar00runnerdockerimport pytest from pymatgen.core import Lattice, Structure from emmet.core.polar import DielectricDoc, PiezoelectricDoc @pytest.fixture def dielectric_structure(): test_latt = Lattice.cubic(3.0) test_struc = Structure(lattice=test_latt, species=["Fe"], coords=[[0, 0, 0]]) return test_struc def test_dielectric(dielectric_structure): epsilon_static = [ [10.81747665, -0.00378371, 0.0049036], [-0.00373185, 10.82629335, -0.00432847], [0.0036548, -0.00479139, 8.68204827], ] epsilon_ionic = [ [30.98960925, -0.09107371, 0.00226948], [-0.09107371, 31.44264572, -0.00427919], [0.00226948, -0.00427919, 29.21747234], ] doc = DielectricDoc.from_ionic_and_electronic( material_id="mp-149", structure=dielectric_structure, electronic=epsilon_static, ionic=epsilon_ionic, deprecated=False, ) assert isinstance(doc, DielectricDoc) assert doc.property_name == "dielectric" assert doc.material_id == "mp-149" assert doc.n == pytest.approx(3.17940376590938) assert doc.e_total == pytest.approx(40.6585061611482) assert doc.e_ionic == pytest.approx(30.5498978544694) @pytest.fixture def piezoelectric_structure(): d = { "@module": "pymatgen.core.structure", "@class": "Structure", "charge": None, "lattice": { "matrix": [ [0.0, 5.077586, 0.0], [8.769167, 0.0, 0.0], [0.0, -1.7206, -4.819114], ], "a": 5.077586, "b": 8.769167, "c": 5.11706205795826, "alpha": 90.0, "beta": 109.648423669999, "gamma": 90.0, "volume": 214.576831815117, }, "sites": [ { "species": [{"element": "Li", "occu": 1}], "abc": [0.5, 0.997223, 0.0], "xyz": [8.744815023241, 2.538793, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.0, 0.007335, 0.5], "xyz": [0.064321839945, -0.8603, -2.409557], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.5, 0.673599, 0.0], "xyz": [5.906902122033, 2.538793, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.0, 0.848636, 0.0], "xyz": [7.441830806212, 0.0, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.0, 0.497223, 0.0], "xyz": [4.360231523241, 0.0, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.5, 0.507335, 0.5], "xyz": [4.448905339945, 1.678493, -2.409557], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.0, 0.173599, 0.0], "xyz": [1.522318622033, 0.0, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Li", "occu": 1}], "abc": [0.5, 0.348636, 0.0], "xyz": [3.057247306212, 2.538793, 0.0], "label": "Li", "properties": {}, }, { "species": [{"element": "Fe", "occu": 1}], "abc": [0.5, 0.840139, 0.5], "xyz": [7.367319194213, 1.678493, -2.409557], "label": "Fe", "properties": {}, }, { "species": [{"element": "Fe", "occu": 1}], "abc": [0.0, 0.674037, 0.5], "xyz": [5.910743017179, -0.8603, -2.409557], "label": "Fe", "properties": {}, }, { "species": [{"element": "Fe", "occu": 1}], "abc": [0.0, 0.340139, 0.5], "xyz": [2.982735694213, -0.8603, -2.409557], "label": "Fe", "properties": {}, }, { "species": [{"element": "Fe", "occu": 1}], "abc": [0.5, 0.174037, 0.5], "xyz": [1.526159517179, 1.678493, -2.409557], "label": "Fe", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.779705, 0.500278, 0.268671], "xyz": [4.387021328426, 3.49674386953, -1.294756177494], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.720295, 0.000278, 0.731329], "xyz": [0.002437828426, 2.39903513047, -3.524357822506], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.755993, 0.189934, 0.270851], "xyz": [1.665562964978, 3.372593242298, -1.305261846014], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.744007, 0.689934, 0.729149], "xyz": [6.050146464978, 2.523185757702, -3.513852153986], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.766434, 0.333483, 0.723505], "xyz": [2.924368118661, 2.646771845324, -3.48665307457], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.733566, 0.833483, 0.276495], "xyz": [7.308951618661, 3.249007154676, -1.33246092543], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.279705, 0.000278, 0.268671], "xyz": [0.002437828426, 0.95795086953, -1.294756177494], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.220295, 0.500278, 0.731329], "xyz": [4.387021328426, -0.13975786953, -3.524357822506], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.255993, 0.689934, 0.270851], "xyz": [6.050146464978, 0.833800242298, -1.305261846014], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.244007, 0.189934, 0.729149], "xyz": [1.665562964978, -0.015607242298, -3.513852153986], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.266434, 0.833483, 0.723505], "xyz": [7.308951618661, 0.107978845324, -3.48665307457], "label": "O", "properties": {}, }, { "species": [{"element": "O", "occu": 1}], "abc": [0.233566, 0.333483, 0.276495], "xyz": [2.924368118661, 0.710214154676, -1.33246092543], "label": "O", "properties": {}, }, ], } test_struc = Structure.from_dict(d) return test_struc def test_piezoelectric(piezoelectric_structure): piezo_static = [ [0.07886, -0.07647, -0.01902, 0.0, -0.18077, 0.0], [0.0, 0.0, 0.0, -0.10377, 0.0, 0.18109], [0.0, 0.0, 0.0, -0.07831, 0.0, 0.04849], ] piezo_ionic = [ [-0.53096, 0.12789, -0.01236, 0.0, 0.09352, 0.0], [-0.00013, 9e-05, 3e-05, 0.2681, 0.00042, -0.09373], [-0.00018, -9e-05, -0.00029, 0.15863, 0.0001, -0.22751], ] doc = PiezoelectricDoc.from_ionic_and_electronic( material_id="mp-149", structure=piezoelectric_structure, electronic=piezo_static, ionic=piezo_ionic, deprecated=False, ) assert isinstance(doc, PiezoelectricDoc) assert doc.property_name == "piezoelectric" assert doc.material_id == "mp-149" assert doc.e_ij_max == pytest.approx(0.464365904540805) assert [abs(n) for n in doc.strain_for_max] == pytest.approx( [ 0.0675760207481869, 0.97358569089405, 0.110731643941102, 0.0, 0.187890624929232, 0.0, ] ) total = [ [0.0, 0.0, 0.0, 0.08032, 0.0, -0.17902], [-0.03138, -0.4521, 0.05142, 0.0, -0.08725, 0.0], [0.0, 0.0, 0.0, 0.16433, 0.0, 0.08736], ] for i in range(3): assert doc.total[i] == pytest.approx(total[i]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_provenance.py0000644000175100001770000000317614673360562020205 0ustar00runnerdockerfrom datetime import datetime import pytest from pymatgen.core import Lattice, Structure from pymatgen.util.provenance import Author, HistoryNode, StructureNL from emmet.core.provenance import Database, ProvenanceDoc, SNLDict @pytest.fixture def structure(): test_latt = Lattice.cubic(3.0) test_struc = Structure(lattice=test_latt, species=["Fe"], coords=[[0, 0, 0]]) return test_struc @pytest.fixture def snls(structure): docs = [ StructureNL( structure, authors=[Author("test{i}", "test@test.com").as_dict()], history=[HistoryNode("nothing", "url.com", {})], created_at=datetime.utcnow(), references="", ).as_dict() for i in range(3) ] docs[0]["snl_id"] = "icsd-2" docs[1]["snl_id"] = "user-1" docs[2]["snl_id"] = "pf-3" return [SNLDict(**d) for d in docs] def test_from_snls(snls, structure): doc = ProvenanceDoc.from_SNLs( material_id="mp-3", structure=structure, snls=snls, deprecated=False ) assert isinstance(doc, ProvenanceDoc) assert doc.property_name == "provenance" assert doc.material_id == "mp-3" assert doc.theoretical is True assert doc.database_IDs == { Database.ICSD: ["icsd-2"], Database.Pauling_Files: ["pf-3"], } # Test experimental detection snls[0].about.history[0].description["experimental"] = True assert ( ProvenanceDoc.from_SNLs( material_id="mp-3", snls=snls, structure=structure, deprecated=False ).theoretical is False ) assert doc.dict(exclude_none=True)["property_name"] == "provenance" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_qc_task.py0000644000175100001770000000777114673360562017477 0ustar00runnerdockerimport pytest from tests.conftest_qchem import assert_schemas_equal, get_test_object @pytest.mark.parametrize( "object_name, task_name", [ pytest.param("SinglePointTest", "standard", id="SinglePointTest"), pytest.param("OptimizationTest", "standard", id="OptimizationTest"), ], ) # Can add more later, something like freq, pesscan, ts, # FFOptTest, once we get flows working for qchem in atomate2 def test_input_summary(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from emmet.core.qc_tasks import InputDoc from emmet.core.qchem.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "qchem" / test_object.folder files = test_object.task_files[task_name] calc_doc = Calculation.from_qchem_files(dir_name, task_name, **files) test_doc = InputDoc.from_qchem_calc_doc(calc_doc) valid_doc = test_object.task_doc["input"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( "object_name, task_name", [ pytest.param("SinglePointTest", "standard", id="SinglePointTest"), pytest.param("OptimizationTest", "standard", id="OptimizationTest"), ], ) def test_output_summary(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from emmet.core.qc_tasks import OutputDoc from emmet.core.qchem.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "qchem" / test_object.folder files = test_object.task_files[task_name] calc_doc = Calculation.from_qchem_files(dir_name, task_name, **files) test_doc = OutputDoc.from_qchem_calc_doc(calc_doc) valid_doc = test_object.task_doc["output"] assert_schemas_equal(test_doc, valid_doc) # test document can be janitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( "object_name", [ pytest.param("SinglePointTest", id="SinglePointTest"), pytest.param("OptimizationTest", id="OptimizationTest"), ], ) def test_task_doc(test_dir, object_name): from monty.json import MontyDecoder, jsanitize from emmet.core.qc_tasks import TaskDoc test_object = get_test_object(object_name) dir_name = test_dir / "qchem" / test_object.folder test_doc = TaskDoc.from_directory(dir_name) assert_schemas_equal(test_doc, test_object.task_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) # Test that additional_fields works test_doc = TaskDoc.from_directory(dir_name, additional_fields={"foo": "bar"}) assert test_doc.model_dump()["additional_fields"] == {"foo": "bar"} @pytest.mark.parametrize( "object_name", [ pytest.param("SinglePointTest", id="SinglePointTest"), pytest.param("OptimizationTest", id="OptimizationTest"), ], ) def test_task_doc_val_flag(test_dir, object_name): from monty.json import MontyDecoder, jsanitize from emmet.core.qc_tasks import TaskDoc test_object = get_test_object(object_name) dir_name = test_dir / "qchem" / test_object.folder print(f"The test object is {test_object.task_doc}") test_doc = TaskDoc.from_directory(dir_name, validate_lot=False) assert_schemas_equal(test_doc, test_object.task_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) # Test that additional_fields works test_doc = TaskDoc.from_directory( dir_name, validate_lot=False, additional_fields={"foo": "bar"} ) assert test_doc.model_dump()["additional_fields"] == {"foo": "bar"} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_robocrys.py0000644000175100001770000000105714673360562017703 0ustar00runnerdockerimport pytest from emmet.core.robocrys import RobocrystallogapherDoc from pymatgen.core import Structure from . import test_structures @pytest.mark.skip(reason="Skip until matminer is released") @pytest.mark.parametrize("structure", test_structures.values()) def test_robocrys(structure: Structure): """Very simple test to make sure this actually works""" print(f"Should work : {structure.composition}") doc = RobocrystallogapherDoc.from_structure( structure=structure, material_id=33, deprecated=False ) assert doc is not None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_settings.py0000644000175100001770000000270314673360562017700 0ustar00runnerdockerimport json import os from pathlib import PosixPath from random import random from monty.serialization import dumpfn, loadfn from monty.tempfile import ScratchDir from emmet.core.settings import EmmetSettings def test_default_config_path(tmp_path: PosixPath): """Make sure the default config path works""" rand_symprec = random() with open(tmp_path / "temp_config.json", "w") as f: json.dump({"SYMPREC": rand_symprec}, f) os.environ["EMMET_CONFIG_FILE"] = str(tmp_path.resolve() / "temp_config.json") test_config = EmmetSettings() assert test_config.SYMPREC == rand_symprec def test_allow_extra_fields(tmp_path: PosixPath): """Makes sure emmet config can be subclassed without loading issues""" with open(tmp_path / "temp_config.json", "w") as f: json.dump({"sub_class_prop": True}, f) os.environ["EMMET_CONFIG_FILE"] = str(tmp_path.resolve() / "temp_config.json") EmmetSettings() def test_from_url(): """Makes sure loading from a URL Works""" os.environ[ "EMMET_CONFIG_FILE" ] = "https://raw.githubusercontent.com/materialsproject/emmet/master/test_files/test_settings.json" test_config = EmmetSettings() assert test_config.ANGLE_TOL == 1.0 def test_seriallization(): test_config = EmmetSettings() with ScratchDir("."): dumpfn(test_config, "test.json") reload_config = loadfn("test.json") assert isinstance(reload_config, EmmetSettings) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_structure_group.py0000644000175100001770000000415014673360562021312 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from pymatgen.core import Composition from emmet.core.structure_group import StructureGroupDoc, _get_id_lexi @pytest.fixture(scope="session") def entries_lto(test_dir): """ Recycle the test cases from pymatgen """ entries = loadfn(test_dir / "LiTiO2_batt.json") for itr, ient in enumerate(entries): ient.entry_id = f"mp-{itr}" return entries @pytest.fixture(scope="session") def entries_lfeo(test_dir): """ Recycle the test cases from pymatgen """ entries = loadfn(test_dir / "Li-Fe-O.json") return entries def test_StructureGroupDoc_from_grouped_entries(entries_lto): sgroup_doc = StructureGroupDoc.from_grouped_entries( entries_lto, ignored_specie="Li", ) assert sgroup_doc.group_id == "mp-0_Li" assert sgroup_doc.material_ids == ["mp-0", "mp-1", "mp-2", "mp-3", "mp-4", "mp-5"] assert sgroup_doc.framework_formula == "TiO2" assert sgroup_doc.ignored_specie == "Li" assert sgroup_doc.chemsys == "Li-O-Ti" assert sgroup_doc.has_distinct_compositions is True @pytest.mark.skip(reason="Temp skip for spglib seg fault") def test_StructureGroupDoc_from_ungrouped_entries(entries_lfeo): entry_dict = {ient.entry_id: ient for ient in entries_lfeo} sgroup_docs = StructureGroupDoc.from_ungrouped_structure_entries( entries_lfeo, ignored_specie="Li" ) # Make sure that all the structure in each group has the same framework for sgroup_doc in sgroup_docs: framework_ref = sgroup_doc.framework_formula ignored = sgroup_doc.ignored_specie for entry_id in sgroup_doc.material_ids: dd_ = entry_dict[entry_id].composition.as_dict() if ignored in dd_: dd_.pop(ignored) framework = Composition.from_dict(dd_).reduced_formula assert framework == framework_ref def test_lexi_id(): assert _get_id_lexi("01HMVV88CCQ6JQ2Y1N8F3ZTVWP") == ( "01HMVV88CCQ6JQ2Y1N8F3ZTVWP", 0, ) assert _get_id_lexi("mp-123") == ("mp", 123) assert _get_id_lexi("123") == ("", 123) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_structure_metadata.py0000644000175100001770000000375014673360562021743 0ustar00runnerdockerimport pytest from pymatgen.core import Element, Lattice, Structure from emmet.core.structure import StructureMetadata from emmet.core.symmetry import CrystalSystem, SymmetryData @pytest.fixture def structure(): test_latt = Lattice.cubic(3.0) test_struc = Structure(lattice=test_latt, species=["Fe"], coords=[[0, 0, 0]]) return test_struc def test_symmetry(structure): symm_doc = SymmetryData.from_structure(structure) assert symm_doc.number == 221 assert symm_doc.point_group == "m-3m" assert symm_doc.symbol == "Pm-3m" assert symm_doc.crystal_system == CrystalSystem.cubic assert symm_doc.model_dump()["crystal_system"] == CrystalSystem.cubic assert str(symm_doc.model_dump()["crystal_system"]) == "Cubic" def test_structure_metadata(structure): meta_doc = StructureMetadata.from_structure(structure) assert meta_doc.nsites == 1 assert meta_doc.elements == [Element.Fe] assert meta_doc.nelements == 1 assert meta_doc.formula_pretty == "Fe" assert meta_doc.formula_anonymous == "A" assert meta_doc.chemsys == "Fe" assert meta_doc.volume == 27.0 assert meta_doc.density == 3.4345483027509993 assert meta_doc.density_atomic == 27.0 def test_structure_metadata_fewer_fields(structure): meta_doc = StructureMetadata.from_structure( structure, fields=["nsites", "nelements", "volume"] ) assert meta_doc.nsites == 1 assert meta_doc.nelements == 1 assert meta_doc.volume == 27.0 def test_composition(structure): meta_doc = StructureMetadata.from_structure(structure) comp_meta_doc = StructureMetadata.from_composition(structure.composition) assert meta_doc.elements == comp_meta_doc.elements assert meta_doc.nelements == comp_meta_doc.nelements assert meta_doc.formula_pretty == comp_meta_doc.formula_pretty assert meta_doc.formula_anonymous == comp_meta_doc.formula_anonymous assert meta_doc.chemsys == comp_meta_doc.chemsys def test_schema(): StructureMetadata.schema() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_task.py0000644000175100001770000001472414673360562017010 0ustar00runnerdockerimport pytest from tests.conftest import assert_schemas_equal, get_test_object @pytest.mark.parametrize( "object_name", [ pytest.param("SiOptimizeDouble", id="SiOptimizeDouble"), pytest.param("SiStatic", id="SiStatic"), pytest.param("SiNonSCFUniform", id="SiNonSCFUniform"), ], ) def test_analysis_summary(test_dir, object_name): from monty.json import MontyDecoder, jsanitize from emmet.core.tasks import AnalysisDoc from emmet.core.vasp.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "vasp" / test_object.folder calcs_reversed = [] for task_name, files in test_object.task_files.items(): doc, _ = Calculation.from_vasp_files(dir_name, task_name, **files) calcs_reversed.append(doc) # The 2 tasks of double-relaxation have been reversed in # "/atomate2/tests/vasp/schemas/conftest.py" for "SiOptimizeDouble" # task_files are in the order of {"relax2","relax1"} test_doc = AnalysisDoc.from_vasp_calc_docs(calcs_reversed) valid_doc = test_object.task_doc["analysis"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( ("object_name", "task_name"), [ pytest.param("SiOptimizeDouble", "relax1", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_input_summary(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from emmet.core.tasks import InputDoc from emmet.core.vasp.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "vasp" / test_object.folder files = test_object.task_files[task_name] calc_doc, _ = Calculation.from_vasp_files(dir_name, task_name, **files) test_doc = InputDoc.from_vasp_calc_doc(calc_doc) valid_doc = test_object.task_doc["input"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( ("object_name", "task_name"), [ pytest.param("SiOptimizeDouble", "relax2", id="SiOptimizeDouble"), pytest.param("SiStatic", "standard", id="SiStatic"), pytest.param("SiNonSCFUniform", "standard", id="SiNonSCFUniform"), ], ) def test_output_summary(test_dir, object_name, task_name): from monty.json import MontyDecoder, jsanitize from emmet.core.tasks import OutputDoc from emmet.core.vasp.calculation import Calculation test_object = get_test_object(object_name) dir_name = test_dir / "vasp" / test_object.folder files = test_object.task_files[task_name] calc_doc, _ = Calculation.from_vasp_files(dir_name, task_name, **files) test_doc = OutputDoc.from_vasp_calc_doc(calc_doc) valid_doc = test_object.task_doc["output"] assert_schemas_equal(test_doc, valid_doc) # test document can be jsanitized d = jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # and decoded MontyDecoder().process_decoded(d) @pytest.mark.parametrize( "object_name", [ pytest.param("SiOptimizeDouble", id="SiOptimizeDouble"), pytest.param("SiStatic", id="SiStatic"), pytest.param("SiNonSCFUniform", id="SiNonSCFUniform"), ], ) def test_task_doc(test_dir, object_name, tmpdir): from monty.json import jsanitize from monty.serialization import dumpfn import os from pymatgen.alchemy.materials import TransformedStructure from pymatgen.entries.computed_entries import ComputedEntry from pymatgen.transformations.standard_transformations import ( DeformStructureTransformation, ) import shutil from emmet.core.tasks import TaskDoc test_object = get_test_object(object_name) dir_name = test_dir / "vasp" / test_object.folder test_doc = TaskDoc.from_directory(dir_name) assert_schemas_equal(test_doc, test_object.task_doc) # test document can be jsanitized jsanitize(test_doc, strict=True, enum_values=True, allow_bson=True) # This is currently an issue as older versions of dumped custodian VaspJob objects are in the # test files. This needs to be updated to properly test decoding. # MontyDecoder().process_decoded(dct) # Test that additional_fields works test_doc = TaskDoc.from_directory(dir_name, additional_fields={"foo": "bar"}) assert test_doc.model_dump()["foo"] == "bar" assert len(test_doc.calcs_reversed) == len(test_object.task_files) # Check that entry is populated when calcs_reversed is not None if test_doc.calcs_reversed: assert isinstance( test_doc.entry, ComputedEntry ), f"Unexpected entry {test_doc.entry} for {object_name}" # Test that transformations field works, using hydrostatic compression as example ts = TransformedStructure( test_doc.output.structure, transformations=[ DeformStructureTransformation( deformation=[ [0.9 if i == j else 0.0 for j in range(3)] for i in range(3) ] ) ], ) ts_json = jsanitize(ts.as_dict()) dumpfn(ts, f"{tmpdir}/transformations.json") for f in os.listdir(dir_name): if os.path.isfile(os.path.join(dir_name, f)): shutil.copy(os.path.join(dir_name, f), tmpdir) test_doc = TaskDoc.from_directory(tmpdir) # if other_parameters == {}, this is popped from the TaskDoc.transformations field # seems like @version is added by monty serialization # jsanitize needed because pymatgen.core.Structure.pbc is a tuple assert all( test_doc.transformations[k] == v for k, v in ts_json.items() if k not in ( "other_parameters", "@version", "last_modified", ) ) assert isinstance(test_doc.transformations, dict) # now test case when transformations are serialized, relevant for atomate2 test_doc = TaskDoc( **{ "transformations": ts, **{ k: v for k, v in test_doc.model_dump().items() if k != "transformations" }, } ) assert test_doc.transformations == ts ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_thermo.py0000644000175100001770000001110414673360562017331 0ustar00runnerdockerimport pytest from monty.serialization import MontyDecoder from monty.serialization import loadfn from emmet.core.thermo import ThermoDoc @pytest.fixture(scope="session") def Fe3O4_structure(test_dir): structure = loadfn(test_dir / "thermo/Fe3O4_structure.json") return structure @pytest.fixture(scope="session") def Fe2O3a_structure(test_dir): structure = loadfn(test_dir / "thermo/Fe2O3a_structure.json") return structure @pytest.fixture(scope="session") def Fe2O3b_structure(test_dir): structure = loadfn(test_dir / "thermo/Fe2O3b_structure.json") return structure @pytest.fixture(scope="session") def Fe_structure(test_dir): structure = loadfn(test_dir / "thermo/Fe_structure.json") return structure @pytest.fixture(scope="session") def O_structure(test_dir): structure = loadfn(test_dir / "thermo/O_structure.json") return structure @pytest.fixture def entries( Fe3O4_structure, Fe2O3a_structure, Fe2O3b_structure, Fe_structure, O_structure ): return MontyDecoder().process_decoded( [ { "@module": "pymatgen.entries.computed_entries", "@class": "ComputedStructureEntry", "correction": 0.0, "structure": Fe3O4_structure.as_dict(), "entry_id": "mp-1", "energy": -382.146593528, "composition": {"Fe": 24.0, "O": 32.0}, "name": "Fe3O4", "data": { "material_id": "mp-1", "run_type": "Unknown", "task_id": "mp-10", }, "attribute": None, "@version": "2020.4.29", }, { "@module": "pymatgen.entries.computed_entries", "@class": "ComputedStructureEntry", "correction": 0.0, "structure": Fe2O3a_structure.as_dict(), "entry_id": "mp-2", "energy": -270.38765404, "composition": {"Fe": 16.0, "O": 24.0}, "name": "Fe2O3", "data": { "material_id": "mp-2", "run_type": "Unknown", "task_id": "mp-20", }, "attribute": None, "@version": "2020.4.29", }, { "@module": "pymatgen.entries.computed_entries", "@class": "ComputedStructureEntry", "correction": 0.0, "structure": O_structure.as_dict(), "entry_id": "mp-3", "energy": -92.274692568, "composition": {"O": 24.0}, "name": "O", "data": { "material_id": "mp-3", "run_type": "Unknown", "task_id": "mp-30", }, "attribute": None, "@version": "2020.4.29", }, { "@module": "pymatgen.entries.computed_entries", "@class": "ComputedStructureEntry", "correction": 0.0, "structure": Fe_structure.as_dict(), "entry_id": "mp-4", "energy": -13.00419661, "composition": {"Fe": 2.0}, "name": "Fe", "data": { "material_id": "mp-4", "run_type": "Unknown", "task_id": "mp-40", }, "attribute": None, "@version": "2020.4.29", }, { "@module": "pymatgen.entries.computed_entries", "@class": "ComputedStructureEntry", "correction": 0.0, "structure": Fe2O3b_structure.as_dict(), "entry_id": "mp-5", "energy": -1080.82678592, "composition": {"Fe": 64.0, "O": 96.0}, "name": "Fe2O3", "attribute": None, "data": { "material_id": "mp-5", "run_type": "Unknown", "task_id": "mp-50", }, "@version": "2020.4.29", }, ] ) def test_from_entries(entries): docs = ThermoDoc.from_entries(entries, thermo_type="UNKNOWN", deprecated=False) assert len(docs) == len(entries) assert all([d.energy_type == "Unknown" for d in docs]) unstable_doc = next(d for d in docs if d.material_id == "mp-5") assert unstable_doc.is_stable is False assert all([d.is_stable for d in docs if d != unstable_doc]) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_utils.py0000644000175100001770000000454714673360562017210 0ustar00runnerdockerimport datetime import json from pathlib import Path import numpy as np import pytest from bson.objectid import ObjectId from emmet.core.utils import DocEnum, ValueEnum, jsanitize from monty.json import MSONable from monty.serialization import dumpfn def test_jsanitize(): """ Tests emmet Jsanitize which converts MSONable classes into dicts """ # clean_json should have no effect on None types. d = {"hello": 1, "world": None} clean = jsanitize(d) assert clean["world"] is None assert json.loads(json.dumps(d)) == json.loads(json.dumps(clean)) d = {"hello": GoodMSONClass(1, 2, 3)} with pytest.raises(TypeError): json.dumps(d) clean = jsanitize(d) assert isinstance(clean["hello"], dict) clean_strict = jsanitize(d, strict=True) assert clean_strict["hello"]["a"] == 1 assert clean_strict["hello"]["b"] == 2 d = {"dt": datetime.datetime.now()} clean = jsanitize(d) assert isinstance(clean["dt"], str) clean = jsanitize(d, allow_bson=True) assert isinstance(clean["dt"], datetime.datetime) d = { "a": ["b", np.array([1, 2, 3])], "b": ObjectId.from_datetime(datetime.datetime.now()), } clean = jsanitize(d) assert clean["a"] == ["b", [1, 2, 3]] assert isinstance(clean["b"], str) rnd_bin = bytes(np.random.rand(10)) d = {"a": bytes(rnd_bin)} clean = jsanitize(d, allow_bson=True) assert clean["a"] == bytes(rnd_bin) assert isinstance(clean["a"], bytes) class GoodMSONClass(MSONable): def __init__(self, a, b, c, d=1, **kwargs): self.a = a self.b = b self._c = c self._d = d self.kwargs = kwargs def __eq__(self, other): return ( self.a == other.a and self.b == other.b and self._c == other._c and self._d == other._d and self.kwargs == other.kwargs ) def test_value_enum(monkeypatch, tmp_path): class TempEnum(ValueEnum): A = "A" B = "B" assert str(TempEnum.A) == "A" assert str(TempEnum.B) == "B" dumpfn(TempEnum, tmp_path / "temp.json") assert Path(tmp_path, "temp.json").is_file() def test_doc_enum(): class TestEnum(DocEnum): A = "A", "Describes A" B = "B", "Might describe B" assert str(TestEnum.A) == "A" assert TestEnum.B.__doc__ == "Might describe B" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/test_xrd.py0000644000175100001770000000230214673360562016630 0ustar00runnerdockerimport pytest from pymatgen.analysis.diffraction.xrd import WAVELENGTHS from pymatgen.core import Element, Lattice, Structure from emmet.core.xrd import Edge, XRDDoc @pytest.fixture def structure(): test_latt = Lattice.cubic(3.0) test_struc = Structure(lattice=test_latt, species=["Fe"], coords=[[0, 0, 0]]) return test_struc @pytest.mark.parametrize("target", list(WAVELENGTHS.keys())) def test_target_detection(structure, target): doc = XRDDoc.from_structure( structure=structure, spectrum_id="test-1", material_id="test-1", wavelength=WAVELENGTHS[target], ) target_element = Element(target[:2]) target_edge = Edge(target[2:]) assert doc.target == target_element assert doc.edge == target_edge @pytest.mark.parametrize("target", list(WAVELENGTHS.keys())) def test_from_target(structure, target): target_element = Element(target[:2]) target_edge = Edge(target[2:]) doc = XRDDoc.from_target( structure=structure, material_id="test-1", target=target_element, edge=target_edge, ) assert doc.target == target_element assert doc.edge == target_edge def test_schema(): XRDDoc.schema() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1726865782.0612903 emmet-core-0.84.2/tests/vasp/0000755000175100001770000000000014673360566015402 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/vasp/test_calc_types.py0000644000175100001770000000200114673360562021126 0ustar00runnerdockerfrom importlib.resources import files as import_resource_file from ruamel.yaml import YAML with open( import_resource_file("emmet.core.vasp.calc_types") / "calc_types.yaml", "r" ) as f: config = YAML().load(f) _REFERENCE_MEMBER_COUNT = { "RunType": 2 * sum(len(rtypes) for rtypes in config["RUN_TYPES"].values()), "TaskType": len(config["TASK_TYPES"]), } _REFERENCE_MEMBER_COUNT["CalcType"] = ( _REFERENCE_MEMBER_COUNT["RunType"] * _REFERENCE_MEMBER_COUNT["TaskType"] ) def test_enums(): from emmet.core.vasp.calc_types import enums as vasp_enums for k, count in _REFERENCE_MEMBER_COUNT.items(): # Test that we have expected number of enum members curr_enum = getattr(vasp_enums, k, None) assert len(curr_enum) == count if k == "RunType": # Test that RunType enum is not case sensitive assert all( curr_enum(member.value.upper()) == curr_enum(member.value.lower()) for member in curr_enum ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/vasp/test_materials.py0000644000175100001770000000241214673360562020767 0ustar00runnerdockerimport json import pytest from monty.io import zopen from emmet.core.vasp.calc_types import TaskType from emmet.core.vasp.material import MaterialsDoc from emmet.core.vasp.task_valid import TaskDocument @pytest.fixture def test_tasks(test_dir): with zopen(test_dir / "test_si_tasks.json.gz") as f: tasks = json.load(f) tasks = [TaskDocument(**t) for t in tasks] return tasks def test_make_mat(test_tasks): material = MaterialsDoc.from_tasks(test_tasks) assert material.formula_pretty == "Si" assert len(material.task_ids) == 4 assert len(material.entries.model_dump(exclude_none=True)) == 1 bad_task_group = [ task for task in test_tasks if task.task_type != TaskType.Structure_Optimization ] with pytest.raises(Exception): MaterialsDoc.from_tasks(bad_task_group, use_statics=False) def test_make_deprecated_mat(test_tasks): bad_task_group = [ task for task in test_tasks if task.task_type != TaskType.Structure_Optimization ] material = MaterialsDoc.construct_deprecated_material(bad_task_group) assert material.deprecated assert material.formula_pretty == "Si" assert len(material.task_ids) == 3 assert material.entries is None def test_schema(): MaterialsDoc.schema() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1726865778.0 emmet-core-0.84.2/tests/vasp/test_vasp.py0000644000175100001770000001741114673360562017764 0ustar00runnerdockerimport json import pytest from monty.io import zopen from emmet.core.vasp.calc_types import RunType, TaskType, run_type, task_type from emmet.core.tasks import TaskDoc from emmet.core.vasp.task_valid import TaskDocument from emmet.core.vasp.validation import ValidationDoc, _potcar_stats_check def test_task_type(): # TODO: Switch this to actual inputs? input_types = [ ("NSCF Line", {"incar": {"ICHARG": 11}, "kpoints": {"labels": ["A"]}}), ("NSCF Uniform", {"incar": {"ICHARG": 11}}), ("Dielectric", {"incar": {"LEPSILON": True}}), ("DFPT Dielectric", {"incar": {"LEPSILON": True, "IBRION": 7}}), ("DFPT Dielectric", {"incar": {"LEPSILON": True, "IBRION": 8}}), ("DFPT", {"incar": {"IBRION": 7}}), ("DFPT", {"incar": {"IBRION": 8}}), ("Static", {"incar": {"NSW": 0}}), ] for _type, inputs in input_types: assert task_type(inputs) == TaskType(_type) def test_run_type(): params_sets = [ ("GGA", {"GGA": "--"}), ("GGA+U", {"GGA": "--", "LDAU": True}), ("SCAN", {"METAGGA": "Scan"}), ("SCAN+U", {"METAGGA": "Scan", "LDAU": True}), ("R2SCAN", {"METAGGA": "R2SCAN"}), ("R2SCAN+U", {"METAGGA": "R2SCAN", "LDAU": True}), ("HFCus", {"LHFCALC": True}), ] for _type, params in params_sets: assert run_type(params) == RunType(_type) @pytest.fixture(scope="session") def tasks(test_dir): with zopen(test_dir / "test_si_tasks.json.gz") as f: data = json.load(f) return [TaskDoc(**d) for d in data] def test_validator(tasks): validation_docs = [ValidationDoc.from_task_doc(task) for task in tasks] assert len(validation_docs) == len(tasks) assert all([doc.valid for doc in validation_docs]) def test_validator_magmom(test_dir): # Task with Cr in structure - this is only element with MAGMOM check with zopen(test_dir / "task_doc_mp-2766060.json.gz") as f: cr_task_dict = json.load(f) taskdoc = TaskDoc(**cr_task_dict) assert ValidationDoc.from_task_doc(taskdoc).valid # test backwards compatibility taskdocument = TaskDocument( **{k: v for k, v in cr_task_dict.items() if k != "last_updated"} ) assert ValidationDoc.from_task_doc(taskdocument).valid # Change MAGMOM on Cr to fail magmom test td_bad_mag = TaskDoc(**cr_task_dict) td_bad_mag.calcs_reversed[0].output.outcar["magnetization"] = [ {"tot": 6.0} if td_bad_mag.structure[ientry].species_string == "Cr" else entry for ientry, entry in enumerate( td_bad_mag.calcs_reversed[0].output.outcar["magnetization"] ) ] assert not (valid_doc := ValidationDoc.from_task_doc(td_bad_mag)).valid assert any("MAG" in repr(reason) for reason in valid_doc.reasons) # Remove magnetization tag to simulate spin-unpolarized (ISPIN = 1) calculation td_no_mag = TaskDoc(**cr_task_dict) del td_no_mag.calcs_reversed[0].output.outcar["magnetization"] assert ValidationDoc.from_task_doc(td_no_mag).valid def test_validator_failed_symmetry(test_dir): with zopen(test_dir / "failed_elastic_task.json.gz", "r") as f: failed_task = json.load(f) taskdoc = TaskDoc(**failed_task) validation = ValidationDoc.from_task_doc(taskdoc) assert any("SYMMETRY" in repr(reason) for reason in validation.reasons) def test_computed_entry(tasks): entries = [task.entry for task in tasks] ids = {e.entry_id for e in entries} assert ids == {"mp-1141021", "mp-149", "mp-1686587", "mp-1440634"} @pytest.fixture(scope="session") def task_ldau(test_dir): with zopen(test_dir / "test_task.json") as f: data = json.load(f) return TaskDoc(**data) def test_ldau(task_ldau): task_ldau.input.is_hubbard = True assert task_ldau.run_type == RunType.GGA_U assert not ValidationDoc.from_task_doc(task_ldau).valid def test_ldau_validation(test_dir): with open(test_dir / "old_aflow_ggau_task.json") as f: data = json.load(f) task = TaskDoc(**data) assert task.run_type == "GGA+U" valid = ValidationDoc.from_task_doc(task) assert valid.valid def test_potcar_stats_check(test_dir): from pymatgen.io.vasp import PotcarSingle with zopen(test_dir / "CoF_TaskDoc.json") as f: data = json.load(f) """ NB: seems like TaskDoc is not fully compatible with TaskDocument excluding all keys but `last_updated` ensures TaskDocument can be built Similarly, after a TaskDoc is dumped to a file, using json.dump( jsanitize( < Task Doc >.model_dump() ), < filename > ) I cannot rebuild the TaskDoc without excluding the `orig_inputs` key. """ # task_doc = TaskDocument(**{key: data[key] for key in data if key != "last_updated"}) task_doc = TaskDoc(**data) try: # First check: generate hashes from POTCARs in TaskDoc, check should pass calc_type = str(task_doc.calc_type) expected_hashes = {calc_type: {}} for spec in task_doc.calcs_reversed[0].input.potcar_spec: symbol = spec.titel.split(" ")[1] potcar = PotcarSingle.from_symbol_and_functional( symbol=symbol, functional="PBE" ) expected_hashes[calc_type][symbol] = [ { **potcar._summary_stats, "hash": potcar.md5_header_hash, "titel": potcar.TITEL, } ] assert not _potcar_stats_check(task_doc, expected_hashes) # Second check: remove POTCAR from expected_hashes, check should fail missing_hashes = {calc_type: expected_hashes[calc_type].copy()} first_element = list(missing_hashes[calc_type])[0] missing_hashes[calc_type].pop(first_element) assert _potcar_stats_check(task_doc, missing_hashes) # Third check: change data in expected hashes, check should fail wrong_hashes = {calc_type: {**expected_hashes[calc_type]}} for key in wrong_hashes[calc_type][first_element][0]["stats"]["data"]: wrong_hashes[calc_type][first_element][0]["stats"]["data"][key] *= 1.1 assert _potcar_stats_check(task_doc, wrong_hashes) # Fourth check: use legacy hash check if `summary_stats` # field not populated. This should pass legacy_data = data.copy() legacy_data["calcs_reversed"][0]["input"]["potcar_spec"] = [ { key: potcar[key] for key in ( "titel", "hash", ) } for potcar in legacy_data["calcs_reversed"][0]["input"]["potcar_spec"] ] legacy_task_doc = TaskDoc( **{key: legacy_data[key] for key in legacy_data if key != "last_updated"} ) assert not _potcar_stats_check(legacy_task_doc, expected_hashes) # Fifth check: use legacy hash check if `summary_stats` # field not populated, but one hash is wrong. This should fail legacy_data = data.copy() legacy_data["calcs_reversed"][0]["input"]["potcar_spec"] = [ { key: potcar[key] for key in ( "titel", "hash", ) } for potcar in legacy_data["calcs_reversed"][0]["input"]["potcar_spec"] ] legacy_data["calcs_reversed"][0]["input"]["potcar_spec"][0][ "hash" ] = legacy_data["calcs_reversed"][0]["input"]["potcar_spec"][0]["hash"][:-1] legacy_task_doc = TaskDoc( **{key: legacy_data[key] for key in legacy_data if key != "last_updated"} ) assert _potcar_stats_check(legacy_task_doc, expected_hashes) except (OSError, ValueError): # missing Pymatgen POTCARs, cannot perform test assert True