././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9112563 emmet-core-0.76.2/0000755000175100001770000000000014551165452013260 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9112563 emmet-core-0.76.2/PKG-INFO0000644000175100001770000000156514551165452014364 0ustar00runnerdockerMetadata-Version: 2.1 Name: emmet-core Version: 0.76.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=1705306921.8912563 emmet-core-0.76.2/emmet/0000755000175100001770000000000014551165452014367 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.8992565 emmet-core-0.76.2/emmet/core/0000755000175100001770000000000014551165452015317 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/__init__.py0000644000175100001770000000050714551165444017433 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=1705306916.0 emmet-core-0.76.2/emmet/core/_general_store.py0000644000175100001770000000135014551165444020661 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=1705306916.0 emmet-core-0.76.2/emmet/core/_messages.py0000644000175100001770000000177314551165444017650 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=1705306916.0 emmet-core-0.76.2/emmet/core/_user_settings.py0000644000175100001770000000067014551165444020732 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=1705306916.0 emmet-core-0.76.2/emmet/core/absorption.py0000644000175100001770000000517414551165444020061 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=1705306916.0 emmet-core-0.76.2/emmet/core/alloys.py0000644000175100001770000000162614551165444017202 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 return cls(alloy_system=alloy_system, alloy_id=alloy_system.alloy_id) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/base.py0000644000175100001770000000322014551165444016601 0ustar00runnerdocker# mypy: ignore-errors """Base emmet model to add default metadata.""" from datetime import datetime from typing import Literal, Optional, TypeVar from monty.json import MontyDecoder from pydantic import BaseModel, Field, field_validator from pymatgen.core import __version__ as pmg_version from emmet.core import __version__ T = TypeVar("T", bound="EmmetBaseModel") monty_decoder = MontyDecoder() 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." ) pull_request: Optional[int] = Field( None, description="The pull request number associated with this data build." ) database_version: Optional[str] = Field( None, description="The database version for the built data." ) build_date: Optional[datetime] = Field( default_factory=datetime.utcnow, description="The build date for this document.", ) license: Optional[Literal["BY-C", "BY-NC"]] = Field( None, description="License for the data entry." ) # Make sure that the datetime field is properly formatted @field_validator("build_date", mode="before") @classmethod def build_date_dict_ok(cls, v): return monty_decoder.process_decoded(v) class EmmetBaseModel(BaseModel): """Base Model for default emmet data.""" builder_meta: Optional[EmmetMeta] = Field( default_factory=EmmetMeta, description="Builder metadata." ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/bonds.py0000644000175100001770000000740514551165444017005 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=1705306916.0 emmet-core-0.76.2/emmet/core/charge_density.py0000644000175100001770000000134314551165444020663 0ustar00runnerdockerfrom pydantic import ConfigDict, BaseModel, Field from datetime import datetime from typing import Optional class ChgcarDataDoc(BaseModel): """ Electron charge density 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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/chemenv.py0000644000175100001770000004365114551165444017330 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 ] 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=1705306916.0 emmet-core-0.76.2/emmet/core/common.py0000644000175100001770000000025114551165444017160 0ustar00runnerdockerfrom emmet.core.utils import ValueEnum class Status(ValueEnum): """ State of a calculation/analysis. """ SUCCESS = "successful" FAILED = "failed" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/corrected_entries.py0000644000175100001770000000213114551165444021372 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=1705306916.0 emmet-core-0.76.2/emmet/core/dois.py0000644000175100001770000000103314551165444016625 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.", ) task_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/elasticity.py0000644000175100001770000006243214551165444020053 0ustar00runnerdockerfrom 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, tol: float = 0.002, ) -> 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. In such 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 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: 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, tol=tol) # Warnings: # Do not use deformations to replace strains in generating the derived fitting # data. More specifically, do not create TensorMapping using deformation. This is # because the Lagrangian strain is symmetric, but the deformation gradient is not. # Then, more derived data can be generated than enough/necessary, due to the # asymmetry of the deformation gradient. # generated derived deforms mapping = TensorMapping(tol=tol) 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 # sym op generates a non-independent deform if not d_strain.get_deformation_matrix().is_independent(tol=tol): 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) 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, 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(result[0]) elif fitting_method == "pseudoinverse": result = ElasticTensor.from_pseudoinverse(strains, stresses) elif fitting_method == "independent": result = ElasticTensor.from_independent_strains( strains, stresses, eq_stress=eq_stress ) else: raise ValueError(f"Unsupported elastic fitting method {fitting_method}") return result 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), reuss=np.round(prop_dict["k_reuss"], decimals), vrh=np.round(prop_dict["k_vrh"], decimals), ), "shear_modulus": ShearModulus( voigt=np.round(prop_dict["g_voigt"], decimals), reuss=np.round(prop_dict["g_reuss"], decimals), vrh=np.round(prop_dict["g_vrh"], decimals), ), "young_modulus": np.round(prop_dict["y_mod"], 0), "homogeneous_poisson": np.round(prop_dict["homogeneous_poisson"], decimals), "universal_anisotropy": np.round(prop_dict["universal_anisotropy"], decimals), } if structure_prop_computed: derived_prop.update( { "sound_velocity": SoundVelocity( transverse=prop_dict["trans_v"], longitudinal=prop_dict["long_v"], snyder_acoustic=prop_dict["snyder_ac"], snyder_optical=prop_dict["snyder_opt"], snyder_total=prop_dict["snyder_total"], ), "thermal_conductivity": ThermalConductivity( clarke=prop_dict["clarke_thermalcond"], cahill=prop_dict["cahill_thermalcond"], ), "debye_temperature": prop_dict["debye_temperature"], } ) 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=1705306916.0 emmet-core-0.76.2/emmet/core/elasticity_legacy.py0000644000175100001770000000403614551165444021373 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=1705306916.0 emmet-core-0.76.2/emmet/core/electrode.py0000644000175100001770000004736514551165444017657 0ustar00runnerdockerimport re from datetime import datetime from typing import List, Union, Dict, Optional from collections import defaultdict from emmet.core.utils import ValueEnum from monty.json import MontyDecoder from pydantic import field_validator, BaseModel, Field 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.analysis.phase_diagram import PhaseDiagram from pymatgen.core import Composition, Structure from pymatgen.core.periodic_table import Element from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.mpid import MPID 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[Element]] = 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 last_updated_dict_ok(cls, v): return MontyDecoder().process_decoded(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.as_dict(), 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) 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) 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=1705306916.0 emmet-core-0.76.2/emmet/core/electronic_structure.py0000644000175100001770000004274514551165444022155 0ustar00runnerdocker""" Core definition of an Electronic Structure """ from __future__ import annotations from collections import defaultdict from datetime import datetime from math import isnan from typing import Dict, Optional, Type, TypeVar, Union, List 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 enum import Enum from emmet.core.settings import EmmetSettings from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID 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( 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( 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()): 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( 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 ).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 vbm = None is_gap_direct = False else: band_gap = gap_dict["energy"] cbm = bs.get_cbm() vbm = bs.get_vbm() 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 ).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) # 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=1705306916.0 emmet-core-0.76.2/emmet/core/eos.py0000644000175100001770000000142614551165444016463 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.", ) task_id: Optional[str] = Field( None, description="The Materials Project ID of the material. This comes in the form: mp-******.", ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.8992565 emmet-core-0.76.2/emmet/core/feff/0000755000175100001770000000000014551165452016225 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/feff/__init__.py0000644000175100001770000000000014551165444020325 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/feff/task.py0000644000175100001770000000527214551165444017550 0ustar00runnerdocker""" Core definition of a VASP Task Document """ 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 from emmet.core.structure import StructureMetadata from emmet.core.vasp.task_valid import TaskDocument as BaseTaskDocument from emmet.core.utils import ValueEnum 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: 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=1705306916.0 emmet-core-0.76.2/emmet/core/fermi.py0000644000175100001770000000214314551165444016774 0ustar00runnerdockerfrom datetime import datetime from typing import List, Optional from monty.json import MontyDecoder from pydantic import BaseModel, Field, field_validator 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.", ) task_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 last_updated_dict_ok(cls, v): return MontyDecoder().process_decoded(v) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/find_structure.py0000644000175100001770000000216614551165444020737 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=1705306916.0 emmet-core-0.76.2/emmet/core/formula_autocomplete.py0000644000175100001770000000044614551165444022124 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=1705306916.0 emmet-core-0.76.2/emmet/core/grain_boundary.py0000644000175100001770000000435214551165444020701 0ustar00runnerdockerfrom typing import List, Optional from pydantic import field_validator, BaseModel, Field from enum import Enum from datetime import datetime from monty.json import MontyDecoder 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... """ task_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 last_updated_dict_ok(cls, v): return MontyDecoder().process_decoded(v) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/magnetism.py0000644000175100001770000000614414551165444017663 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=1705306916.0 emmet-core-0.76.2/emmet/core/material.py0000644000175100001770000001326414551165444017476 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 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 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( description="The timestamp when this calculation was last updated", default_factory=datetime.utcnow, ) 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=1705306916.0 emmet-core-0.76.2/emmet/core/material_property.py0000644000175100001770000000404714551165444021441 0ustar00runnerdocker""" Core definition of a Materials Document """ from __future__ import annotations from datetime import datetime from typing import Sequence, Type, TypeVar, Union, List, Optional from pydantic import Field from pymatgen.core import Structure 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 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." ) @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=1705306916.0 emmet-core-0.76.2/emmet/core/math.py0000644000175100001770000000161514551165444016626 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=1705306916.0 emmet-core-0.76.2/emmet/core/ml.py0000644000175100001770000001556714551165444016320 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_name: Optional[str] = Field( None, description="Name of model used as ML potential." ) model_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=1705306921.8992565 emmet-core-0.76.2/emmet/core/mobility/0000755000175100001770000000000014551165452017147 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/mobility/migrationgraph.py0000644000175100001770000003471414551165444022546 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() 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[Union[int, float]]] ): 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[Union[int, float]]], 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[Union[int, float]]], 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 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.8992565 emmet-core-0.76.2/emmet/core/molecules/0000755000175100001770000000000014551165452017307 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/__init__.py0000644000175100001770000000000014551165444021407 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/atomic.py0000644000175100001770000001355714551165444021151 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/bonds.py0000644000175100001770000003432714551165444021000 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/metal_binding.py0000644000175100001770000004113014551165444022455 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[Union[str, Species]]] = 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/molecule_property.py0000644000175100001770000000553414551165444023442 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/orbitals.py0000644000175100001770000004762714551165444021521 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/redox.py0000644000175100001770000002306014551165444021004 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/summary.py0000644000175100001770000005716314551165444021373 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/thermo.py0000644000175100001770000002335214551165444021165 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules/vibration.py0000644000175100001770000000736114551165444021666 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=1705306916.0 emmet-core-0.76.2/emmet/core/molecules_jcesr.py0000644000175100001770000000321514551165444021051 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=1705306916.0 emmet-core-0.76.2/emmet/core/mpcomplete.py0000644000175100001770000000146714551165444020047 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=1705306916.0 emmet-core-0.76.2/emmet/core/mpid.py0000644000175100001770000001600614551165444016626 0ustar00runnerdockerimport re from typing import Union, Any, Callable from pydantic_core import CoreSchema, core_schema from pydantic import GetJsonSchemaHandler from pydantic.json_schema import JsonSchemaValue 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]+)$" ) 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): parts = val.split("-") parts[1] = int(parts[1]) # type: ignore self.parts = tuple(parts) self.string = val else: raise ValueError( "Must provide an MPID, int, or string of the format prefix-number" ) 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, 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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/optimade.py0000644000175100001770000001110114551165444017466 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=1705306916.0 emmet-core-0.76.2/emmet/core/oxidation_states.py0000644000175100001770000000777514551165444021273 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=1705306916.0 emmet-core-0.76.2/emmet/core/phonon.py0000644000175100001770000003117214551165444017177 0ustar00runnerdockerfrom datetime import datetime from monty.json import MontyDecoder 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 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 last_updated_dict_ok(cls, v): return MontyDecoder().process_decoded(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=1705306916.0 emmet-core-0.76.2/emmet/core/polar.py0000644000175100001770000001262114551165444017011 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 = ionic_tensor + electronic_tensor # 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=1705306916.0 emmet-core-0.76.2/emmet/core/provenance.py0000644000175100001770000001514414551165444020037 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 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 convert_monty_date(cls, v): if isinstance(v, dict): if v.get("@module", "datetime") and v.get("@class", "datetime"): return datetime.fromisoformat(v["string"]) raise ValueError("Improper monty dict datetime") return 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("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=1705306916.0 emmet-core-0.76.2/emmet/core/qc_tasks.py0000644000175100001770000005073514551165444017514 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" ) frequency_modes: Optional[Union[List, str]] = Field( None, description="The list of calculated frequency mode vectors if job type is freq (units: cm^-1)", ) @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, ) 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 """ # 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=calc_doc.level_of_theory.value, 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=calc_doc.calc_type.value, ) 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], 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. 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 ) 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} 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, "qcoutput_file": out_file, } # This block will exist only if calcs were run through atomate else: try: task_files[in_task_name] = { "qcinput_file": file, "qcoutput_file": Path("mol.qout." + in_task_name + ".gz"), } except FileNotFoundError: task_files[in_task_name] = { "qcinput_file": file, "qcoutput_file": "No qout files exist for this in file", } return task_files ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9032564 emmet-core-0.76.2/emmet/core/qchem/0000755000175100001770000000000014551165452016414 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/__init__.py0000644000175100001770000000000014551165444020514 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9032564 emmet-core-0.76.2/emmet/core/qchem/calc_types/0000755000175100001770000000000014551165452020542 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/__init__.py0000644000175100001770000000055314551165444022657 0ustar00runnerdockerfrom pathlib import Path try: import emmet.core.qchem.calc_types.enums except ImportError: import emmet.core.qchem.calc_types.generate 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/calc_types.py0000644000175100001770000000361214551165444023245 0ustar00runnerdocker"""Task types and level of theory components for Q-Chem calculations""" __author__ = "Evan Spotte-Smith " 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" ], } FUNCTIONALS = [ rt for functional_class in FUNCTIONAL_CLASSES for rt in FUNCTIONAL_CLASSES[functional_class] ] 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/em_utils.py0000644000175100001770000001627214551165444022746 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 " ) 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() 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/enums.py0000644000175100001770000070401714551165444022255 0ustar00runnerdocker""" Autogenerated Enums for Q-Chem LevelOfTheory, TaskType, and CalcType Do not edit this by hand. Edit generate.py or types.py instead """ from emmet.core.utils import ValueEnum class LevelOfTheory(ValueEnum): """Levels of theory for calculations in Q-Chem""" PBE_6_31g_d_VACUUM = "PBE/6-31g*/VACUUM" PBE_6_31g_d_PCM = "PBE/6-31g*/PCM" PBE_6_31g_d_SMD = "PBE/6-31g*/SMD" PBE_def2_SVPD_VACUUM = "PBE/def2-SVPD/VACUUM" PBE_def2_SVPD_PCM = "PBE/def2-SVPD/PCM" PBE_def2_SVPD_SMD = "PBE/def2-SVPD/SMD" PBE_def2_TZVP_VACUUM = "PBE/def2-TZVP/VACUUM" PBE_def2_TZVP_PCM = "PBE/def2-TZVP/PCM" PBE_def2_TZVP_SMD = "PBE/def2-TZVP/SMD" PBE_def2_TZVPD_VACUUM = "PBE/def2-TZVPD/VACUUM" PBE_def2_TZVPD_PCM = "PBE/def2-TZVPD/PCM" PBE_def2_TZVPD_SMD = "PBE/def2-TZVPD/SMD" PBE_def2_TZVPP_VACUUM = "PBE/def2-TZVPP/VACUUM" PBE_def2_TZVPP_PCM = "PBE/def2-TZVPP/PCM" PBE_def2_TZVPP_SMD = "PBE/def2-TZVPP/SMD" PBE_def2_TZVPPD_VACUUM = "PBE/def2-TZVPPD/VACUUM" PBE_def2_TZVPPD_PCM = "PBE/def2-TZVPPD/PCM" PBE_def2_TZVPPD_SMD = "PBE/def2-TZVPPD/SMD" PBE_def2_QZVPD_VACUUM = "PBE/def2-QZVPD/VACUUM" PBE_def2_QZVPD_PCM = "PBE/def2-QZVPD/PCM" PBE_def2_QZVPD_SMD = "PBE/def2-QZVPD/SMD" PBE_def2_QZVPPD_VACUUM = "PBE/def2-QZVPPD/VACUUM" PBE_def2_QZVPPD_PCM = "PBE/def2-QZVPPD/PCM" PBE_def2_QZVPPD_SMD = "PBE/def2-QZVPPD/SMD" B97_D_6_31g_d_VACUUM = "B97-D/6-31g*/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_def2_SVPD_VACUUM = "B97-D/def2-SVPD/VACUUM" B97_D_def2_SVPD_PCM = "B97-D/def2-SVPD/PCM" B97_D_def2_SVPD_SMD = "B97-D/def2-SVPD/SMD" B97_D_def2_TZVP_VACUUM = "B97-D/def2-TZVP/VACUUM" B97_D_def2_TZVP_PCM = "B97-D/def2-TZVP/PCM" B97_D_def2_TZVP_SMD = "B97-D/def2-TZVP/SMD" B97_D_def2_TZVPD_VACUUM = "B97-D/def2-TZVPD/VACUUM" B97_D_def2_TZVPD_PCM = "B97-D/def2-TZVPD/PCM" B97_D_def2_TZVPD_SMD = "B97-D/def2-TZVPD/SMD" B97_D_def2_TZVPP_VACUUM = "B97-D/def2-TZVPP/VACUUM" B97_D_def2_TZVPP_PCM = "B97-D/def2-TZVPP/PCM" B97_D_def2_TZVPP_SMD = "B97-D/def2-TZVPP/SMD" B97_D_def2_TZVPPD_VACUUM = "B97-D/def2-TZVPPD/VACUUM" B97_D_def2_TZVPPD_PCM = "B97-D/def2-TZVPPD/PCM" B97_D_def2_TZVPPD_SMD = "B97-D/def2-TZVPPD/SMD" B97_D_def2_QZVPD_VACUUM = "B97-D/def2-QZVPD/VACUUM" B97_D_def2_QZVPD_PCM = "B97-D/def2-QZVPD/PCM" B97_D_def2_QZVPD_SMD = "B97-D/def2-QZVPD/SMD" B97_D_def2_QZVPPD_VACUUM = "B97-D/def2-QZVPPD/VACUUM" B97_D_def2_QZVPPD_PCM = "B97-D/def2-QZVPPD/PCM" B97_D_def2_QZVPPD_SMD = "B97-D/def2-QZVPPD/SMD" B97_D3_6_31g_d_VACUUM = "B97-D3/6-31g*/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_def2_SVPD_VACUUM = "B97-D3/def2-SVPD/VACUUM" B97_D3_def2_SVPD_PCM = "B97-D3/def2-SVPD/PCM" B97_D3_def2_SVPD_SMD = "B97-D3/def2-SVPD/SMD" B97_D3_def2_TZVP_VACUUM = "B97-D3/def2-TZVP/VACUUM" B97_D3_def2_TZVP_PCM = "B97-D3/def2-TZVP/PCM" B97_D3_def2_TZVP_SMD = "B97-D3/def2-TZVP/SMD" B97_D3_def2_TZVPD_VACUUM = "B97-D3/def2-TZVPD/VACUUM" B97_D3_def2_TZVPD_PCM = "B97-D3/def2-TZVPD/PCM" B97_D3_def2_TZVPD_SMD = "B97-D3/def2-TZVPD/SMD" B97_D3_def2_TZVPP_VACUUM = "B97-D3/def2-TZVPP/VACUUM" B97_D3_def2_TZVPP_PCM = "B97-D3/def2-TZVPP/PCM" B97_D3_def2_TZVPP_SMD = "B97-D3/def2-TZVPP/SMD" B97_D3_def2_TZVPPD_VACUUM = "B97-D3/def2-TZVPPD/VACUUM" B97_D3_def2_TZVPPD_PCM = "B97-D3/def2-TZVPPD/PCM" B97_D3_def2_TZVPPD_SMD = "B97-D3/def2-TZVPPD/SMD" B97_D3_def2_QZVPD_VACUUM = "B97-D3/def2-QZVPD/VACUUM" B97_D3_def2_QZVPD_PCM = "B97-D3/def2-QZVPD/PCM" B97_D3_def2_QZVPD_SMD = "B97-D3/def2-QZVPD/SMD" B97_D3_def2_QZVPPD_VACUUM = "B97-D3/def2-QZVPPD/VACUUM" B97_D3_def2_QZVPPD_PCM = "B97-D3/def2-QZVPPD/PCM" B97_D3_def2_QZVPPD_SMD = "B97-D3/def2-QZVPPD/SMD" B97M_V_6_31g_d_VACUUM = "B97M-V/6-31g*/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_def2_SVPD_VACUUM = "B97M-V/def2-SVPD/VACUUM" B97M_V_def2_SVPD_PCM = "B97M-V/def2-SVPD/PCM" B97M_V_def2_SVPD_SMD = "B97M-V/def2-SVPD/SMD" B97M_V_def2_TZVP_VACUUM = "B97M-V/def2-TZVP/VACUUM" B97M_V_def2_TZVP_PCM = "B97M-V/def2-TZVP/PCM" B97M_V_def2_TZVP_SMD = "B97M-V/def2-TZVP/SMD" B97M_V_def2_TZVPD_VACUUM = "B97M-V/def2-TZVPD/VACUUM" B97M_V_def2_TZVPD_PCM = "B97M-V/def2-TZVPD/PCM" B97M_V_def2_TZVPD_SMD = "B97M-V/def2-TZVPD/SMD" B97M_V_def2_TZVPP_VACUUM = "B97M-V/def2-TZVPP/VACUUM" B97M_V_def2_TZVPP_PCM = "B97M-V/def2-TZVPP/PCM" B97M_V_def2_TZVPP_SMD = "B97M-V/def2-TZVPP/SMD" B97M_V_def2_TZVPPD_VACUUM = "B97M-V/def2-TZVPPD/VACUUM" B97M_V_def2_TZVPPD_PCM = "B97M-V/def2-TZVPPD/PCM" B97M_V_def2_TZVPPD_SMD = "B97M-V/def2-TZVPPD/SMD" B97M_V_def2_QZVPD_VACUUM = "B97M-V/def2-QZVPD/VACUUM" B97M_V_def2_QZVPD_PCM = "B97M-V/def2-QZVPD/PCM" B97M_V_def2_QZVPD_SMD = "B97M-V/def2-QZVPD/SMD" B97M_V_def2_QZVPPD_VACUUM = "B97M-V/def2-QZVPPD/VACUUM" B97M_V_def2_QZVPPD_PCM = "B97M-V/def2-QZVPPD/PCM" B97M_V_def2_QZVPPD_SMD = "B97M-V/def2-QZVPPD/SMD" B97M_rV_6_31g_d_VACUUM = "B97M-rV/6-31g*/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_def2_SVPD_VACUUM = "B97M-rV/def2-SVPD/VACUUM" B97M_rV_def2_SVPD_PCM = "B97M-rV/def2-SVPD/PCM" B97M_rV_def2_SVPD_SMD = "B97M-rV/def2-SVPD/SMD" B97M_rV_def2_TZVP_VACUUM = "B97M-rV/def2-TZVP/VACUUM" B97M_rV_def2_TZVP_PCM = "B97M-rV/def2-TZVP/PCM" B97M_rV_def2_TZVP_SMD = "B97M-rV/def2-TZVP/SMD" B97M_rV_def2_TZVPD_VACUUM = "B97M-rV/def2-TZVPD/VACUUM" B97M_rV_def2_TZVPD_PCM = "B97M-rV/def2-TZVPD/PCM" B97M_rV_def2_TZVPD_SMD = "B97M-rV/def2-TZVPD/SMD" B97M_rV_def2_TZVPP_VACUUM = "B97M-rV/def2-TZVPP/VACUUM" B97M_rV_def2_TZVPP_PCM = "B97M-rV/def2-TZVPP/PCM" B97M_rV_def2_TZVPP_SMD = "B97M-rV/def2-TZVPP/SMD" B97M_rV_def2_TZVPPD_VACUUM = "B97M-rV/def2-TZVPPD/VACUUM" B97M_rV_def2_TZVPPD_PCM = "B97M-rV/def2-TZVPPD/PCM" B97M_rV_def2_TZVPPD_SMD = "B97M-rV/def2-TZVPPD/SMD" B97M_rV_def2_QZVPD_VACUUM = "B97M-rV/def2-QZVPD/VACUUM" B97M_rV_def2_QZVPD_PCM = "B97M-rV/def2-QZVPD/PCM" B97M_rV_def2_QZVPD_SMD = "B97M-rV/def2-QZVPD/SMD" B97M_rV_def2_QZVPPD_VACUUM = "B97M-rV/def2-QZVPPD/VACUUM" B97M_rV_def2_QZVPPD_PCM = "B97M-rV/def2-QZVPPD/PCM" B97M_rV_def2_QZVPPD_SMD = "B97M-rV/def2-QZVPPD/SMD" B3LYP_6_31g_d_VACUUM = "B3LYP/6-31g*/VACUUM" B3LYP_6_31g_d_PCM = "B3LYP/6-31g*/PCM" B3LYP_6_31g_d_SMD = "B3LYP/6-31g*/SMD" B3LYP_def2_SVPD_VACUUM = "B3LYP/def2-SVPD/VACUUM" B3LYP_def2_SVPD_PCM = "B3LYP/def2-SVPD/PCM" B3LYP_def2_SVPD_SMD = "B3LYP/def2-SVPD/SMD" B3LYP_def2_TZVP_VACUUM = "B3LYP/def2-TZVP/VACUUM" B3LYP_def2_TZVP_PCM = "B3LYP/def2-TZVP/PCM" B3LYP_def2_TZVP_SMD = "B3LYP/def2-TZVP/SMD" B3LYP_def2_TZVPD_VACUUM = "B3LYP/def2-TZVPD/VACUUM" B3LYP_def2_TZVPD_PCM = "B3LYP/def2-TZVPD/PCM" B3LYP_def2_TZVPD_SMD = "B3LYP/def2-TZVPD/SMD" B3LYP_def2_TZVPP_VACUUM = "B3LYP/def2-TZVPP/VACUUM" B3LYP_def2_TZVPP_PCM = "B3LYP/def2-TZVPP/PCM" B3LYP_def2_TZVPP_SMD = "B3LYP/def2-TZVPP/SMD" B3LYP_def2_TZVPPD_VACUUM = "B3LYP/def2-TZVPPD/VACUUM" B3LYP_def2_TZVPPD_PCM = "B3LYP/def2-TZVPPD/PCM" B3LYP_def2_TZVPPD_SMD = "B3LYP/def2-TZVPPD/SMD" B3LYP_def2_QZVPD_VACUUM = "B3LYP/def2-QZVPD/VACUUM" B3LYP_def2_QZVPD_PCM = "B3LYP/def2-QZVPD/PCM" B3LYP_def2_QZVPD_SMD = "B3LYP/def2-QZVPD/SMD" B3LYP_def2_QZVPPD_VACUUM = "B3LYP/def2-QZVPPD/VACUUM" B3LYP_def2_QZVPPD_PCM = "B3LYP/def2-QZVPPD/PCM" B3LYP_def2_QZVPPD_SMD = "B3LYP/def2-QZVPPD/SMD" wB97X_D_6_31g_d_VACUUM = "wB97X-D/6-31g*/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_def2_SVPD_VACUUM = "wB97X-D/def2-SVPD/VACUUM" wB97X_D_def2_SVPD_PCM = "wB97X-D/def2-SVPD/PCM" wB97X_D_def2_SVPD_SMD = "wB97X-D/def2-SVPD/SMD" wB97X_D_def2_TZVP_VACUUM = "wB97X-D/def2-TZVP/VACUUM" wB97X_D_def2_TZVP_PCM = "wB97X-D/def2-TZVP/PCM" wB97X_D_def2_TZVP_SMD = "wB97X-D/def2-TZVP/SMD" wB97X_D_def2_TZVPD_VACUUM = "wB97X-D/def2-TZVPD/VACUUM" wB97X_D_def2_TZVPD_PCM = "wB97X-D/def2-TZVPD/PCM" wB97X_D_def2_TZVPD_SMD = "wB97X-D/def2-TZVPD/SMD" wB97X_D_def2_TZVPP_VACUUM = "wB97X-D/def2-TZVPP/VACUUM" wB97X_D_def2_TZVPP_PCM = "wB97X-D/def2-TZVPP/PCM" wB97X_D_def2_TZVPP_SMD = "wB97X-D/def2-TZVPP/SMD" wB97X_D_def2_TZVPPD_VACUUM = "wB97X-D/def2-TZVPPD/VACUUM" wB97X_D_def2_TZVPPD_PCM = "wB97X-D/def2-TZVPPD/PCM" wB97X_D_def2_TZVPPD_SMD = "wB97X-D/def2-TZVPPD/SMD" wB97X_D_def2_QZVPD_VACUUM = "wB97X-D/def2-QZVPD/VACUUM" wB97X_D_def2_QZVPD_PCM = "wB97X-D/def2-QZVPD/PCM" wB97X_D_def2_QZVPD_SMD = "wB97X-D/def2-QZVPD/SMD" wB97X_D_def2_QZVPPD_VACUUM = "wB97X-D/def2-QZVPPD/VACUUM" wB97X_D_def2_QZVPPD_PCM = "wB97X-D/def2-QZVPPD/PCM" wB97X_D_def2_QZVPPD_SMD = "wB97X-D/def2-QZVPPD/SMD" wB97X_D3_6_31g_d_VACUUM = "wB97X-D3/6-31g*/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_def2_SVPD_VACUUM = "wB97X-D3/def2-SVPD/VACUUM" wB97X_D3_def2_SVPD_PCM = "wB97X-D3/def2-SVPD/PCM" wB97X_D3_def2_SVPD_SMD = "wB97X-D3/def2-SVPD/SMD" wB97X_D3_def2_TZVP_VACUUM = "wB97X-D3/def2-TZVP/VACUUM" wB97X_D3_def2_TZVP_PCM = "wB97X-D3/def2-TZVP/PCM" wB97X_D3_def2_TZVP_SMD = "wB97X-D3/def2-TZVP/SMD" wB97X_D3_def2_TZVPD_VACUUM = "wB97X-D3/def2-TZVPD/VACUUM" wB97X_D3_def2_TZVPD_PCM = "wB97X-D3/def2-TZVPD/PCM" wB97X_D3_def2_TZVPD_SMD = "wB97X-D3/def2-TZVPD/SMD" wB97X_D3_def2_TZVPP_VACUUM = "wB97X-D3/def2-TZVPP/VACUUM" wB97X_D3_def2_TZVPP_PCM = "wB97X-D3/def2-TZVPP/PCM" wB97X_D3_def2_TZVPP_SMD = "wB97X-D3/def2-TZVPP/SMD" wB97X_D3_def2_TZVPPD_VACUUM = "wB97X-D3/def2-TZVPPD/VACUUM" wB97X_D3_def2_TZVPPD_PCM = "wB97X-D3/def2-TZVPPD/PCM" wB97X_D3_def2_TZVPPD_SMD = "wB97X-D3/def2-TZVPPD/SMD" wB97X_D3_def2_QZVPD_VACUUM = "wB97X-D3/def2-QZVPD/VACUUM" wB97X_D3_def2_QZVPD_PCM = "wB97X-D3/def2-QZVPD/PCM" wB97X_D3_def2_QZVPD_SMD = "wB97X-D3/def2-QZVPD/SMD" wB97X_D3_def2_QZVPPD_VACUUM = "wB97X-D3/def2-QZVPPD/VACUUM" wB97X_D3_def2_QZVPPD_PCM = "wB97X-D3/def2-QZVPPD/PCM" wB97X_D3_def2_QZVPPD_SMD = "wB97X-D3/def2-QZVPPD/SMD" wB97X_V_6_31g_d_VACUUM = "wB97X-V/6-31g*/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_def2_SVPD_VACUUM = "wB97X-V/def2-SVPD/VACUUM" wB97X_V_def2_SVPD_PCM = "wB97X-V/def2-SVPD/PCM" wB97X_V_def2_SVPD_SMD = "wB97X-V/def2-SVPD/SMD" wB97X_V_def2_TZVP_VACUUM = "wB97X-V/def2-TZVP/VACUUM" wB97X_V_def2_TZVP_PCM = "wB97X-V/def2-TZVP/PCM" wB97X_V_def2_TZVP_SMD = "wB97X-V/def2-TZVP/SMD" wB97X_V_def2_TZVPD_VACUUM = "wB97X-V/def2-TZVPD/VACUUM" wB97X_V_def2_TZVPD_PCM = "wB97X-V/def2-TZVPD/PCM" wB97X_V_def2_TZVPD_SMD = "wB97X-V/def2-TZVPD/SMD" wB97X_V_def2_TZVPP_VACUUM = "wB97X-V/def2-TZVPP/VACUUM" wB97X_V_def2_TZVPP_PCM = "wB97X-V/def2-TZVPP/PCM" wB97X_V_def2_TZVPP_SMD = "wB97X-V/def2-TZVPP/SMD" wB97X_V_def2_TZVPPD_VACUUM = "wB97X-V/def2-TZVPPD/VACUUM" wB97X_V_def2_TZVPPD_PCM = "wB97X-V/def2-TZVPPD/PCM" wB97X_V_def2_TZVPPD_SMD = "wB97X-V/def2-TZVPPD/SMD" wB97X_V_def2_QZVPD_VACUUM = "wB97X-V/def2-QZVPD/VACUUM" wB97X_V_def2_QZVPD_PCM = "wB97X-V/def2-QZVPD/PCM" wB97X_V_def2_QZVPD_SMD = "wB97X-V/def2-QZVPD/SMD" wB97X_V_def2_QZVPPD_VACUUM = "wB97X-V/def2-QZVPPD/VACUUM" wB97X_V_def2_QZVPPD_PCM = "wB97X-V/def2-QZVPPD/PCM" wB97X_V_def2_QZVPPD_SMD = "wB97X-V/def2-QZVPPD/SMD" wB97M_V_6_31g_d_VACUUM = "wB97M-V/6-31g*/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_def2_SVPD_VACUUM = "wB97M-V/def2-SVPD/VACUUM" wB97M_V_def2_SVPD_PCM = "wB97M-V/def2-SVPD/PCM" wB97M_V_def2_SVPD_SMD = "wB97M-V/def2-SVPD/SMD" wB97M_V_def2_TZVP_VACUUM = "wB97M-V/def2-TZVP/VACUUM" wB97M_V_def2_TZVP_PCM = "wB97M-V/def2-TZVP/PCM" wB97M_V_def2_TZVP_SMD = "wB97M-V/def2-TZVP/SMD" wB97M_V_def2_TZVPD_VACUUM = "wB97M-V/def2-TZVPD/VACUUM" wB97M_V_def2_TZVPD_PCM = "wB97M-V/def2-TZVPD/PCM" wB97M_V_def2_TZVPD_SMD = "wB97M-V/def2-TZVPD/SMD" wB97M_V_def2_TZVPP_VACUUM = "wB97M-V/def2-TZVPP/VACUUM" wB97M_V_def2_TZVPP_PCM = "wB97M-V/def2-TZVPP/PCM" wB97M_V_def2_TZVPP_SMD = "wB97M-V/def2-TZVPP/SMD" wB97M_V_def2_TZVPPD_VACUUM = "wB97M-V/def2-TZVPPD/VACUUM" wB97M_V_def2_TZVPPD_PCM = "wB97M-V/def2-TZVPPD/PCM" wB97M_V_def2_TZVPPD_SMD = "wB97M-V/def2-TZVPPD/SMD" wB97M_V_def2_QZVPD_VACUUM = "wB97M-V/def2-QZVPD/VACUUM" wB97M_V_def2_QZVPD_PCM = "wB97M-V/def2-QZVPD/PCM" wB97M_V_def2_QZVPD_SMD = "wB97M-V/def2-QZVPD/SMD" wB97M_V_def2_QZVPPD_VACUUM = "wB97M-V/def2-QZVPPD/VACUUM" wB97M_V_def2_QZVPPD_PCM = "wB97M-V/def2-QZVPPD/PCM" wB97M_V_def2_QZVPPD_SMD = "wB97M-V/def2-QZVPPD/SMD" class TaskType(ValueEnum): """Calculation task types for Q-Chem""" Single_Point = "Single Point" Force = "Force" Geometry_Optimization = "Geometry Optimization" Frequency_Analysis = "Frequency Analysis" Frequency_Flattening_Geometry_Optimization = ( "Frequency Flattening Geometry Optimization" ) Transition_State_Geometry_Optimization = "Transition State Geometry Optimization" Frequency_Flattening_Transition_State_Geometry_Optimization = ( "Frequency Flattening Transition State Geometry Optimization" ) Unknown = "Unknown" class CalcType(ValueEnum): """Calculation types (LOT + task type) for Q-Chem""" PBE_6_31g_d_VACUUM_Single_Point = "PBE/6-31g*/VACUUM Single Point" PBE_6_31g_d_VACUUM_Force = "PBE/6-31g*/VACUUM Force" PBE_6_31g_d_VACUUM_Geometry_Optimization = "PBE/6-31g*/VACUUM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/VACUUM Transition State 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_Unknown = "PBE/6-31g*/VACUUM Unknown" PBE_6_31g_d_PCM_Single_Point = "PBE/6-31g*/PCM Single Point" PBE_6_31g_d_PCM_Force = "PBE/6-31g*/PCM Force" PBE_6_31g_d_PCM_Geometry_Optimization = "PBE/6-31g*/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/PCM Transition State 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_Unknown = "PBE/6-31g*/PCM Unknown" PBE_6_31g_d_SMD_Single_Point = "PBE/6-31g*/SMD Single Point" PBE_6_31g_d_SMD_Force = "PBE/6-31g*/SMD Force" PBE_6_31g_d_SMD_Geometry_Optimization = "PBE/6-31g*/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/6-31g*/SMD Transition State 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_Unknown = "PBE/6-31g*/SMD Unknown" PBE_def2_SVPD_VACUUM_Single_Point = "PBE/def2-SVPD/VACUUM Single Point" PBE_def2_SVPD_VACUUM_Force = "PBE/def2-SVPD/VACUUM Force" PBE_def2_SVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/VACUUM Transition State 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_Unknown = "PBE/def2-SVPD/VACUUM Unknown" PBE_def2_SVPD_PCM_Single_Point = "PBE/def2-SVPD/PCM Single Point" PBE_def2_SVPD_PCM_Force = "PBE/def2-SVPD/PCM Force" PBE_def2_SVPD_PCM_Geometry_Optimization = "PBE/def2-SVPD/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/PCM Transition State 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_Unknown = "PBE/def2-SVPD/PCM Unknown" PBE_def2_SVPD_SMD_Single_Point = "PBE/def2-SVPD/SMD Single Point" PBE_def2_SVPD_SMD_Force = "PBE/def2-SVPD/SMD Force" PBE_def2_SVPD_SMD_Geometry_Optimization = "PBE/def2-SVPD/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/def2-SVPD/SMD Transition State 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_Unknown = "PBE/def2-SVPD/SMD Unknown" PBE_def2_TZVP_VACUUM_Single_Point = "PBE/def2-TZVP/VACUUM Single Point" PBE_def2_TZVP_VACUUM_Force = "PBE/def2-TZVP/VACUUM Force" PBE_def2_TZVP_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/VACUUM Transition State 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_Unknown = "PBE/def2-TZVP/VACUUM Unknown" PBE_def2_TZVP_PCM_Single_Point = "PBE/def2-TZVP/PCM Single Point" PBE_def2_TZVP_PCM_Force = "PBE/def2-TZVP/PCM Force" PBE_def2_TZVP_PCM_Geometry_Optimization = "PBE/def2-TZVP/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/PCM Transition State 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_Unknown = "PBE/def2-TZVP/PCM Unknown" PBE_def2_TZVP_SMD_Single_Point = "PBE/def2-TZVP/SMD Single Point" PBE_def2_TZVP_SMD_Force = "PBE/def2-TZVP/SMD Force" PBE_def2_TZVP_SMD_Geometry_Optimization = "PBE/def2-TZVP/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVP/SMD Transition State 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_Unknown = "PBE/def2-TZVP/SMD Unknown" PBE_def2_TZVPD_VACUUM_Single_Point = "PBE/def2-TZVPD/VACUUM Single Point" PBE_def2_TZVPD_VACUUM_Force = "PBE/def2-TZVPD/VACUUM Force" PBE_def2_TZVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/VACUUM Transition State 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_Unknown = "PBE/def2-TZVPD/VACUUM Unknown" PBE_def2_TZVPD_PCM_Single_Point = "PBE/def2-TZVPD/PCM Single Point" PBE_def2_TZVPD_PCM_Force = "PBE/def2-TZVPD/PCM Force" PBE_def2_TZVPD_PCM_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/PCM Transition State 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_Unknown = "PBE/def2-TZVPD/PCM Unknown" PBE_def2_TZVPD_SMD_Single_Point = "PBE/def2-TZVPD/SMD Single Point" PBE_def2_TZVPD_SMD_Force = "PBE/def2-TZVPD/SMD Force" PBE_def2_TZVPD_SMD_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPD/SMD Transition State 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_Unknown = "PBE/def2-TZVPD/SMD Unknown" PBE_def2_TZVPP_VACUUM_Single_Point = "PBE/def2-TZVPP/VACUUM Single Point" PBE_def2_TZVPP_VACUUM_Force = "PBE/def2-TZVPP/VACUUM Force" PBE_def2_TZVPP_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/VACUUM Transition State 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_Unknown = "PBE/def2-TZVPP/VACUUM Unknown" PBE_def2_TZVPP_PCM_Single_Point = "PBE/def2-TZVPP/PCM Single Point" PBE_def2_TZVPP_PCM_Force = "PBE/def2-TZVPP/PCM Force" PBE_def2_TZVPP_PCM_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/PCM Transition State 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_Unknown = "PBE/def2-TZVPP/PCM Unknown" PBE_def2_TZVPP_SMD_Single_Point = "PBE/def2-TZVPP/SMD Single Point" PBE_def2_TZVPP_SMD_Force = "PBE/def2-TZVPP/SMD Force" PBE_def2_TZVPP_SMD_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPP/SMD Transition State 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_Unknown = "PBE/def2-TZVPP/SMD Unknown" PBE_def2_TZVPPD_VACUUM_Single_Point = "PBE/def2-TZVPPD/VACUUM Single Point" PBE_def2_TZVPPD_VACUUM_Force = "PBE/def2-TZVPPD/VACUUM Force" PBE_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "PBE/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/VACUUM Transition State 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_Unknown = "PBE/def2-TZVPPD/VACUUM Unknown" PBE_def2_TZVPPD_PCM_Single_Point = "PBE/def2-TZVPPD/PCM Single Point" PBE_def2_TZVPPD_PCM_Force = "PBE/def2-TZVPPD/PCM Force" PBE_def2_TZVPPD_PCM_Geometry_Optimization = ( "PBE/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/PCM Transition State 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_Unknown = "PBE/def2-TZVPPD/PCM Unknown" PBE_def2_TZVPPD_SMD_Single_Point = "PBE/def2-TZVPPD/SMD Single Point" PBE_def2_TZVPPD_SMD_Force = "PBE/def2-TZVPPD/SMD Force" PBE_def2_TZVPPD_SMD_Geometry_Optimization = ( "PBE/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-TZVPPD/SMD Transition State 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_Unknown = "PBE/def2-TZVPPD/SMD Unknown" PBE_def2_QZVPD_VACUUM_Single_Point = "PBE/def2-QZVPD/VACUUM Single Point" PBE_def2_QZVPD_VACUUM_Force = "PBE/def2-QZVPD/VACUUM Force" PBE_def2_QZVPD_VACUUM_Geometry_Optimization = ( "PBE/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/VACUUM Transition State 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_Unknown = "PBE/def2-QZVPD/VACUUM Unknown" PBE_def2_QZVPD_PCM_Single_Point = "PBE/def2-QZVPD/PCM Single Point" PBE_def2_QZVPD_PCM_Force = "PBE/def2-QZVPD/PCM Force" PBE_def2_QZVPD_PCM_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/PCM Transition State 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_Unknown = "PBE/def2-QZVPD/PCM Unknown" PBE_def2_QZVPD_SMD_Single_Point = "PBE/def2-QZVPD/SMD Single Point" PBE_def2_QZVPD_SMD_Force = "PBE/def2-QZVPD/SMD Force" PBE_def2_QZVPD_SMD_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPD/SMD Transition State 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_Unknown = "PBE/def2-QZVPD/SMD Unknown" PBE_def2_QZVPPD_VACUUM_Single_Point = "PBE/def2-QZVPPD/VACUUM Single Point" PBE_def2_QZVPPD_VACUUM_Force = "PBE/def2-QZVPPD/VACUUM Force" PBE_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "PBE/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/VACUUM Transition State 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_Unknown = "PBE/def2-QZVPPD/VACUUM Unknown" PBE_def2_QZVPPD_PCM_Single_Point = "PBE/def2-QZVPPD/PCM Single Point" PBE_def2_QZVPPD_PCM_Force = "PBE/def2-QZVPPD/PCM Force" PBE_def2_QZVPPD_PCM_Geometry_Optimization = ( "PBE/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/PCM Transition State 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_Unknown = "PBE/def2-QZVPPD/PCM Unknown" PBE_def2_QZVPPD_SMD_Single_Point = "PBE/def2-QZVPPD/SMD Single Point" PBE_def2_QZVPPD_SMD_Force = "PBE/def2-QZVPPD/SMD Force" PBE_def2_QZVPPD_SMD_Geometry_Optimization = ( "PBE/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "PBE/def2-QZVPPD/SMD Transition State 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_Unknown = "PBE/def2-QZVPPD/SMD Unknown" B97_D_6_31g_d_VACUUM_Single_Point = "B97-D/6-31g*/VACUUM Single Point" B97_D_6_31g_d_VACUUM_Force = "B97-D/6-31g*/VACUUM Force" B97_D_6_31g_d_VACUUM_Geometry_Optimization = ( "B97-D/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/VACUUM Transition State 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_Unknown = "B97-D/6-31g*/VACUUM Unknown" B97_D_6_31g_d_PCM_Single_Point = "B97-D/6-31g*/PCM Single Point" B97_D_6_31g_d_PCM_Force = "B97-D/6-31g*/PCM Force" B97_D_6_31g_d_PCM_Geometry_Optimization = "B97-D/6-31g*/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/PCM Transition State 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_Unknown = "B97-D/6-31g*/PCM Unknown" B97_D_6_31g_d_SMD_Single_Point = "B97-D/6-31g*/SMD Single Point" B97_D_6_31g_d_SMD_Force = "B97-D/6-31g*/SMD Force" B97_D_6_31g_d_SMD_Geometry_Optimization = "B97-D/6-31g*/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97-D/6-31g*/SMD Transition State 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_Unknown = "B97-D/6-31g*/SMD Unknown" B97_D_def2_SVPD_VACUUM_Single_Point = "B97-D/def2-SVPD/VACUUM Single Point" B97_D_def2_SVPD_VACUUM_Force = "B97-D/def2-SVPD/VACUUM Force" B97_D_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/VACUUM Transition State 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_Unknown = "B97-D/def2-SVPD/VACUUM Unknown" B97_D_def2_SVPD_PCM_Single_Point = "B97-D/def2-SVPD/PCM Single Point" B97_D_def2_SVPD_PCM_Force = "B97-D/def2-SVPD/PCM Force" B97_D_def2_SVPD_PCM_Geometry_Optimization = ( "B97-D/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/PCM Transition State 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_Unknown = "B97-D/def2-SVPD/PCM Unknown" B97_D_def2_SVPD_SMD_Single_Point = "B97-D/def2-SVPD/SMD Single Point" B97_D_def2_SVPD_SMD_Force = "B97-D/def2-SVPD/SMD Force" B97_D_def2_SVPD_SMD_Geometry_Optimization = ( "B97-D/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-SVPD/SMD Transition State 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_Unknown = "B97-D/def2-SVPD/SMD Unknown" B97_D_def2_TZVP_VACUUM_Single_Point = "B97-D/def2-TZVP/VACUUM Single Point" B97_D_def2_TZVP_VACUUM_Force = "B97-D/def2-TZVP/VACUUM Force" B97_D_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/VACUUM Transition State 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_Unknown = "B97-D/def2-TZVP/VACUUM Unknown" B97_D_def2_TZVP_PCM_Single_Point = "B97-D/def2-TZVP/PCM Single Point" B97_D_def2_TZVP_PCM_Force = "B97-D/def2-TZVP/PCM Force" B97_D_def2_TZVP_PCM_Geometry_Optimization = ( "B97-D/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/PCM Transition State 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_Unknown = "B97-D/def2-TZVP/PCM Unknown" B97_D_def2_TZVP_SMD_Single_Point = "B97-D/def2-TZVP/SMD Single Point" B97_D_def2_TZVP_SMD_Force = "B97-D/def2-TZVP/SMD Force" B97_D_def2_TZVP_SMD_Geometry_Optimization = ( "B97-D/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVP/SMD Transition State 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_Unknown = "B97-D/def2-TZVP/SMD Unknown" B97_D_def2_TZVPD_VACUUM_Single_Point = "B97-D/def2-TZVPD/VACUUM Single Point" B97_D_def2_TZVPD_VACUUM_Force = "B97-D/def2-TZVPD/VACUUM Force" B97_D_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/VACUUM Transition State 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_Unknown = "B97-D/def2-TZVPD/VACUUM Unknown" B97_D_def2_TZVPD_PCM_Single_Point = "B97-D/def2-TZVPD/PCM Single Point" B97_D_def2_TZVPD_PCM_Force = "B97-D/def2-TZVPD/PCM Force" B97_D_def2_TZVPD_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/PCM Transition State 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_Unknown = "B97-D/def2-TZVPD/PCM Unknown" B97_D_def2_TZVPD_SMD_Single_Point = "B97-D/def2-TZVPD/SMD Single Point" B97_D_def2_TZVPD_SMD_Force = "B97-D/def2-TZVPD/SMD Force" B97_D_def2_TZVPD_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPD/SMD Transition State 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_Unknown = "B97-D/def2-TZVPD/SMD Unknown" B97_D_def2_TZVPP_VACUUM_Single_Point = "B97-D/def2-TZVPP/VACUUM Single Point" B97_D_def2_TZVPP_VACUUM_Force = "B97-D/def2-TZVPP/VACUUM Force" B97_D_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/VACUUM Transition State 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_Unknown = "B97-D/def2-TZVPP/VACUUM Unknown" B97_D_def2_TZVPP_PCM_Single_Point = "B97-D/def2-TZVPP/PCM Single Point" B97_D_def2_TZVPP_PCM_Force = "B97-D/def2-TZVPP/PCM Force" B97_D_def2_TZVPP_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/PCM Transition State 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_Unknown = "B97-D/def2-TZVPP/PCM Unknown" B97_D_def2_TZVPP_SMD_Single_Point = "B97-D/def2-TZVPP/SMD Single Point" B97_D_def2_TZVPP_SMD_Force = "B97-D/def2-TZVPP/SMD Force" B97_D_def2_TZVPP_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPP/SMD Transition State 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_Unknown = "B97-D/def2-TZVPP/SMD Unknown" B97_D_def2_TZVPPD_VACUUM_Single_Point = "B97-D/def2-TZVPPD/VACUUM Single Point" B97_D_def2_TZVPPD_VACUUM_Force = "B97-D/def2-TZVPPD/VACUUM Force" B97_D_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/VACUUM Transition State 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_Unknown = "B97-D/def2-TZVPPD/VACUUM Unknown" B97_D_def2_TZVPPD_PCM_Single_Point = "B97-D/def2-TZVPPD/PCM Single Point" B97_D_def2_TZVPPD_PCM_Force = "B97-D/def2-TZVPPD/PCM Force" B97_D_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97-D/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/PCM Transition State 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_Unknown = "B97-D/def2-TZVPPD/PCM Unknown" B97_D_def2_TZVPPD_SMD_Single_Point = "B97-D/def2-TZVPPD/SMD Single Point" B97_D_def2_TZVPPD_SMD_Force = "B97-D/def2-TZVPPD/SMD Force" B97_D_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97-D/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-TZVPPD/SMD Transition State 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_Unknown = "B97-D/def2-TZVPPD/SMD Unknown" B97_D_def2_QZVPD_VACUUM_Single_Point = "B97-D/def2-QZVPD/VACUUM Single Point" B97_D_def2_QZVPD_VACUUM_Force = "B97-D/def2-QZVPD/VACUUM Force" B97_D_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/VACUUM Transition State 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_Unknown = "B97-D/def2-QZVPD/VACUUM Unknown" B97_D_def2_QZVPD_PCM_Single_Point = "B97-D/def2-QZVPD/PCM Single Point" B97_D_def2_QZVPD_PCM_Force = "B97-D/def2-QZVPD/PCM Force" B97_D_def2_QZVPD_PCM_Geometry_Optimization = ( "B97-D/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/PCM Transition State 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_Unknown = "B97-D/def2-QZVPD/PCM Unknown" B97_D_def2_QZVPD_SMD_Single_Point = "B97-D/def2-QZVPD/SMD Single Point" B97_D_def2_QZVPD_SMD_Force = "B97-D/def2-QZVPD/SMD Force" B97_D_def2_QZVPD_SMD_Geometry_Optimization = ( "B97-D/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPD/SMD Transition State 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_Unknown = "B97-D/def2-QZVPD/SMD Unknown" B97_D_def2_QZVPPD_VACUUM_Single_Point = "B97-D/def2-QZVPPD/VACUUM Single Point" B97_D_def2_QZVPPD_VACUUM_Force = "B97-D/def2-QZVPPD/VACUUM Force" B97_D_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97-D/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/VACUUM Transition State 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_Unknown = "B97-D/def2-QZVPPD/VACUUM Unknown" B97_D_def2_QZVPPD_PCM_Single_Point = "B97-D/def2-QZVPPD/PCM Single Point" B97_D_def2_QZVPPD_PCM_Force = "B97-D/def2-QZVPPD/PCM Force" B97_D_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97-D/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/PCM Transition State 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_Unknown = "B97-D/def2-QZVPPD/PCM Unknown" B97_D_def2_QZVPPD_SMD_Single_Point = "B97-D/def2-QZVPPD/SMD Single Point" B97_D_def2_QZVPPD_SMD_Force = "B97-D/def2-QZVPPD/SMD Force" B97_D_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97-D/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D/def2-QZVPPD/SMD Transition State 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_Unknown = "B97-D/def2-QZVPPD/SMD Unknown" B97_D3_6_31g_d_VACUUM_Single_Point = "B97-D3/6-31g*/VACUUM Single Point" B97_D3_6_31g_d_VACUUM_Force = "B97-D3/6-31g*/VACUUM Force" B97_D3_6_31g_d_VACUUM_Geometry_Optimization = ( "B97-D3/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/VACUUM Transition State 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_Unknown = "B97-D3/6-31g*/VACUUM Unknown" B97_D3_6_31g_d_PCM_Single_Point = "B97-D3/6-31g*/PCM Single Point" B97_D3_6_31g_d_PCM_Force = "B97-D3/6-31g*/PCM Force" B97_D3_6_31g_d_PCM_Geometry_Optimization = "B97-D3/6-31g*/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/PCM Transition State 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_Unknown = "B97-D3/6-31g*/PCM Unknown" B97_D3_6_31g_d_SMD_Single_Point = "B97-D3/6-31g*/SMD Single Point" B97_D3_6_31g_d_SMD_Force = "B97-D3/6-31g*/SMD Force" B97_D3_6_31g_d_SMD_Geometry_Optimization = "B97-D3/6-31g*/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97-D3/6-31g*/SMD Transition State 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_Unknown = "B97-D3/6-31g*/SMD Unknown" B97_D3_def2_SVPD_VACUUM_Single_Point = "B97-D3/def2-SVPD/VACUUM Single Point" B97_D3_def2_SVPD_VACUUM_Force = "B97-D3/def2-SVPD/VACUUM Force" B97_D3_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/VACUUM Transition State 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_Unknown = "B97-D3/def2-SVPD/VACUUM Unknown" B97_D3_def2_SVPD_PCM_Single_Point = "B97-D3/def2-SVPD/PCM Single Point" B97_D3_def2_SVPD_PCM_Force = "B97-D3/def2-SVPD/PCM Force" B97_D3_def2_SVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/PCM Transition State 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_Unknown = "B97-D3/def2-SVPD/PCM Unknown" B97_D3_def2_SVPD_SMD_Single_Point = "B97-D3/def2-SVPD/SMD Single Point" B97_D3_def2_SVPD_SMD_Force = "B97-D3/def2-SVPD/SMD Force" B97_D3_def2_SVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-SVPD/SMD Transition State 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_Unknown = "B97-D3/def2-SVPD/SMD Unknown" B97_D3_def2_TZVP_VACUUM_Single_Point = "B97-D3/def2-TZVP/VACUUM Single Point" B97_D3_def2_TZVP_VACUUM_Force = "B97-D3/def2-TZVP/VACUUM Force" B97_D3_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/VACUUM Transition State 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_Unknown = "B97-D3/def2-TZVP/VACUUM Unknown" B97_D3_def2_TZVP_PCM_Single_Point = "B97-D3/def2-TZVP/PCM Single Point" B97_D3_def2_TZVP_PCM_Force = "B97-D3/def2-TZVP/PCM Force" B97_D3_def2_TZVP_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/PCM Transition State 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_Unknown = "B97-D3/def2-TZVP/PCM Unknown" B97_D3_def2_TZVP_SMD_Single_Point = "B97-D3/def2-TZVP/SMD Single Point" B97_D3_def2_TZVP_SMD_Force = "B97-D3/def2-TZVP/SMD Force" B97_D3_def2_TZVP_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVP/SMD Transition State 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_Unknown = "B97-D3/def2-TZVP/SMD Unknown" B97_D3_def2_TZVPD_VACUUM_Single_Point = "B97-D3/def2-TZVPD/VACUUM Single Point" B97_D3_def2_TZVPD_VACUUM_Force = "B97-D3/def2-TZVPD/VACUUM Force" B97_D3_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/VACUUM Transition State 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_Unknown = "B97-D3/def2-TZVPD/VACUUM Unknown" B97_D3_def2_TZVPD_PCM_Single_Point = "B97-D3/def2-TZVPD/PCM Single Point" B97_D3_def2_TZVPD_PCM_Force = "B97-D3/def2-TZVPD/PCM Force" B97_D3_def2_TZVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/PCM Transition State 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_Unknown = "B97-D3/def2-TZVPD/PCM Unknown" B97_D3_def2_TZVPD_SMD_Single_Point = "B97-D3/def2-TZVPD/SMD Single Point" B97_D3_def2_TZVPD_SMD_Force = "B97-D3/def2-TZVPD/SMD Force" B97_D3_def2_TZVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPD/SMD Transition State 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_Unknown = "B97-D3/def2-TZVPD/SMD Unknown" B97_D3_def2_TZVPP_VACUUM_Single_Point = "B97-D3/def2-TZVPP/VACUUM Single Point" B97_D3_def2_TZVPP_VACUUM_Force = "B97-D3/def2-TZVPP/VACUUM Force" B97_D3_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/VACUUM Transition State 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_Unknown = "B97-D3/def2-TZVPP/VACUUM Unknown" B97_D3_def2_TZVPP_PCM_Single_Point = "B97-D3/def2-TZVPP/PCM Single Point" B97_D3_def2_TZVPP_PCM_Force = "B97-D3/def2-TZVPP/PCM Force" B97_D3_def2_TZVPP_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/PCM Transition State 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_Unknown = "B97-D3/def2-TZVPP/PCM Unknown" B97_D3_def2_TZVPP_SMD_Single_Point = "B97-D3/def2-TZVPP/SMD Single Point" B97_D3_def2_TZVPP_SMD_Force = "B97-D3/def2-TZVPP/SMD Force" B97_D3_def2_TZVPP_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPP/SMD Transition State 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_Unknown = "B97-D3/def2-TZVPP/SMD Unknown" B97_D3_def2_TZVPPD_VACUUM_Single_Point = "B97-D3/def2-TZVPPD/VACUUM Single Point" B97_D3_def2_TZVPPD_VACUUM_Force = "B97-D3/def2-TZVPPD/VACUUM Force" B97_D3_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/VACUUM Transition State 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_Unknown = "B97-D3/def2-TZVPPD/VACUUM Unknown" B97_D3_def2_TZVPPD_PCM_Single_Point = "B97-D3/def2-TZVPPD/PCM Single Point" B97_D3_def2_TZVPPD_PCM_Force = "B97-D3/def2-TZVPPD/PCM Force" B97_D3_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/PCM Transition State 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_Unknown = "B97-D3/def2-TZVPPD/PCM Unknown" B97_D3_def2_TZVPPD_SMD_Single_Point = "B97-D3/def2-TZVPPD/SMD Single Point" B97_D3_def2_TZVPPD_SMD_Force = "B97-D3/def2-TZVPPD/SMD Force" B97_D3_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-TZVPPD/SMD Transition State 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_Unknown = "B97-D3/def2-TZVPPD/SMD Unknown" B97_D3_def2_QZVPD_VACUUM_Single_Point = "B97-D3/def2-QZVPD/VACUUM Single Point" B97_D3_def2_QZVPD_VACUUM_Force = "B97-D3/def2-QZVPD/VACUUM Force" B97_D3_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/VACUUM Transition State 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_Unknown = "B97-D3/def2-QZVPD/VACUUM Unknown" B97_D3_def2_QZVPD_PCM_Single_Point = "B97-D3/def2-QZVPD/PCM Single Point" B97_D3_def2_QZVPD_PCM_Force = "B97-D3/def2-QZVPD/PCM Force" B97_D3_def2_QZVPD_PCM_Geometry_Optimization = ( "B97-D3/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/PCM Transition State 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_Unknown = "B97-D3/def2-QZVPD/PCM Unknown" B97_D3_def2_QZVPD_SMD_Single_Point = "B97-D3/def2-QZVPD/SMD Single Point" B97_D3_def2_QZVPD_SMD_Force = "B97-D3/def2-QZVPD/SMD Force" B97_D3_def2_QZVPD_SMD_Geometry_Optimization = ( "B97-D3/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPD/SMD Transition State 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_Unknown = "B97-D3/def2-QZVPD/SMD Unknown" B97_D3_def2_QZVPPD_VACUUM_Single_Point = "B97-D3/def2-QZVPPD/VACUUM Single Point" B97_D3_def2_QZVPPD_VACUUM_Force = "B97-D3/def2-QZVPPD/VACUUM Force" B97_D3_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/VACUUM Transition State 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_Unknown = "B97-D3/def2-QZVPPD/VACUUM Unknown" B97_D3_def2_QZVPPD_PCM_Single_Point = "B97-D3/def2-QZVPPD/PCM Single Point" B97_D3_def2_QZVPPD_PCM_Force = "B97-D3/def2-QZVPPD/PCM Force" B97_D3_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/PCM Transition State 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_Unknown = "B97-D3/def2-QZVPPD/PCM Unknown" B97_D3_def2_QZVPPD_SMD_Single_Point = "B97-D3/def2-QZVPPD/SMD Single Point" B97_D3_def2_QZVPPD_SMD_Force = "B97-D3/def2-QZVPPD/SMD Force" B97_D3_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97-D3/def2-QZVPPD/SMD Transition State 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_Unknown = "B97-D3/def2-QZVPPD/SMD Unknown" B97M_V_6_31g_d_VACUUM_Single_Point = "B97M-V/6-31g*/VACUUM Single Point" B97M_V_6_31g_d_VACUUM_Force = "B97M-V/6-31g*/VACUUM Force" B97M_V_6_31g_d_VACUUM_Geometry_Optimization = ( "B97M-V/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/VACUUM Transition State 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_Unknown = "B97M-V/6-31g*/VACUUM Unknown" B97M_V_6_31g_d_PCM_Single_Point = "B97M-V/6-31g*/PCM Single Point" B97M_V_6_31g_d_PCM_Force = "B97M-V/6-31g*/PCM Force" B97M_V_6_31g_d_PCM_Geometry_Optimization = "B97M-V/6-31g*/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/PCM Transition State 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_Unknown = "B97M-V/6-31g*/PCM Unknown" B97M_V_6_31g_d_SMD_Single_Point = "B97M-V/6-31g*/SMD Single Point" B97M_V_6_31g_d_SMD_Force = "B97M-V/6-31g*/SMD Force" B97M_V_6_31g_d_SMD_Geometry_Optimization = "B97M-V/6-31g*/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B97M-V/6-31g*/SMD Transition State 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_Unknown = "B97M-V/6-31g*/SMD Unknown" B97M_V_def2_SVPD_VACUUM_Single_Point = "B97M-V/def2-SVPD/VACUUM Single Point" B97M_V_def2_SVPD_VACUUM_Force = "B97M-V/def2-SVPD/VACUUM Force" B97M_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/VACUUM Transition State 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_Unknown = "B97M-V/def2-SVPD/VACUUM Unknown" B97M_V_def2_SVPD_PCM_Single_Point = "B97M-V/def2-SVPD/PCM Single Point" B97M_V_def2_SVPD_PCM_Force = "B97M-V/def2-SVPD/PCM Force" B97M_V_def2_SVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/PCM Transition State 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_Unknown = "B97M-V/def2-SVPD/PCM Unknown" B97M_V_def2_SVPD_SMD_Single_Point = "B97M-V/def2-SVPD/SMD Single Point" B97M_V_def2_SVPD_SMD_Force = "B97M-V/def2-SVPD/SMD Force" B97M_V_def2_SVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-SVPD/SMD Transition State 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_Unknown = "B97M-V/def2-SVPD/SMD Unknown" B97M_V_def2_TZVP_VACUUM_Single_Point = "B97M-V/def2-TZVP/VACUUM Single Point" B97M_V_def2_TZVP_VACUUM_Force = "B97M-V/def2-TZVP/VACUUM Force" B97M_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/VACUUM Transition State 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_Unknown = "B97M-V/def2-TZVP/VACUUM Unknown" B97M_V_def2_TZVP_PCM_Single_Point = "B97M-V/def2-TZVP/PCM Single Point" B97M_V_def2_TZVP_PCM_Force = "B97M-V/def2-TZVP/PCM Force" B97M_V_def2_TZVP_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/PCM Transition State 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_Unknown = "B97M-V/def2-TZVP/PCM Unknown" B97M_V_def2_TZVP_SMD_Single_Point = "B97M-V/def2-TZVP/SMD Single Point" B97M_V_def2_TZVP_SMD_Force = "B97M-V/def2-TZVP/SMD Force" B97M_V_def2_TZVP_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVP/SMD Transition State 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_Unknown = "B97M-V/def2-TZVP/SMD Unknown" B97M_V_def2_TZVPD_VACUUM_Single_Point = "B97M-V/def2-TZVPD/VACUUM Single Point" B97M_V_def2_TZVPD_VACUUM_Force = "B97M-V/def2-TZVPD/VACUUM Force" B97M_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/VACUUM Transition State 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_Unknown = "B97M-V/def2-TZVPD/VACUUM Unknown" B97M_V_def2_TZVPD_PCM_Single_Point = "B97M-V/def2-TZVPD/PCM Single Point" B97M_V_def2_TZVPD_PCM_Force = "B97M-V/def2-TZVPD/PCM Force" B97M_V_def2_TZVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/PCM Transition State 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_Unknown = "B97M-V/def2-TZVPD/PCM Unknown" B97M_V_def2_TZVPD_SMD_Single_Point = "B97M-V/def2-TZVPD/SMD Single Point" B97M_V_def2_TZVPD_SMD_Force = "B97M-V/def2-TZVPD/SMD Force" B97M_V_def2_TZVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPD/SMD Transition State 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_Unknown = "B97M-V/def2-TZVPD/SMD Unknown" B97M_V_def2_TZVPP_VACUUM_Single_Point = "B97M-V/def2-TZVPP/VACUUM Single Point" B97M_V_def2_TZVPP_VACUUM_Force = "B97M-V/def2-TZVPP/VACUUM Force" B97M_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/VACUUM Transition State 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_Unknown = "B97M-V/def2-TZVPP/VACUUM Unknown" B97M_V_def2_TZVPP_PCM_Single_Point = "B97M-V/def2-TZVPP/PCM Single Point" B97M_V_def2_TZVPP_PCM_Force = "B97M-V/def2-TZVPP/PCM Force" B97M_V_def2_TZVPP_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/PCM Transition State 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_Unknown = "B97M-V/def2-TZVPP/PCM Unknown" B97M_V_def2_TZVPP_SMD_Single_Point = "B97M-V/def2-TZVPP/SMD Single Point" B97M_V_def2_TZVPP_SMD_Force = "B97M-V/def2-TZVPP/SMD Force" B97M_V_def2_TZVPP_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPP/SMD Transition State 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_Unknown = "B97M-V/def2-TZVPP/SMD Unknown" B97M_V_def2_TZVPPD_VACUUM_Single_Point = "B97M-V/def2-TZVPPD/VACUUM Single Point" B97M_V_def2_TZVPPD_VACUUM_Force = "B97M-V/def2-TZVPPD/VACUUM Force" B97M_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/VACUUM Transition State 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_Unknown = "B97M-V/def2-TZVPPD/VACUUM Unknown" B97M_V_def2_TZVPPD_PCM_Single_Point = "B97M-V/def2-TZVPPD/PCM Single Point" B97M_V_def2_TZVPPD_PCM_Force = "B97M-V/def2-TZVPPD/PCM Force" B97M_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/PCM Transition State 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_Unknown = "B97M-V/def2-TZVPPD/PCM Unknown" B97M_V_def2_TZVPPD_SMD_Single_Point = "B97M-V/def2-TZVPPD/SMD Single Point" B97M_V_def2_TZVPPD_SMD_Force = "B97M-V/def2-TZVPPD/SMD Force" B97M_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-TZVPPD/SMD Transition State 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_Unknown = "B97M-V/def2-TZVPPD/SMD Unknown" B97M_V_def2_QZVPD_VACUUM_Single_Point = "B97M-V/def2-QZVPD/VACUUM Single Point" B97M_V_def2_QZVPD_VACUUM_Force = "B97M-V/def2-QZVPD/VACUUM Force" B97M_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/VACUUM Transition State 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_Unknown = "B97M-V/def2-QZVPD/VACUUM Unknown" B97M_V_def2_QZVPD_PCM_Single_Point = "B97M-V/def2-QZVPD/PCM Single Point" B97M_V_def2_QZVPD_PCM_Force = "B97M-V/def2-QZVPD/PCM Force" B97M_V_def2_QZVPD_PCM_Geometry_Optimization = ( "B97M-V/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/PCM Transition State 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_Unknown = "B97M-V/def2-QZVPD/PCM Unknown" B97M_V_def2_QZVPD_SMD_Single_Point = "B97M-V/def2-QZVPD/SMD Single Point" B97M_V_def2_QZVPD_SMD_Force = "B97M-V/def2-QZVPD/SMD Force" B97M_V_def2_QZVPD_SMD_Geometry_Optimization = ( "B97M-V/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPD/SMD Transition State 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_Unknown = "B97M-V/def2-QZVPD/SMD Unknown" B97M_V_def2_QZVPPD_VACUUM_Single_Point = "B97M-V/def2-QZVPPD/VACUUM Single Point" B97M_V_def2_QZVPPD_VACUUM_Force = "B97M-V/def2-QZVPPD/VACUUM Force" B97M_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/VACUUM Transition State 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_Unknown = "B97M-V/def2-QZVPPD/VACUUM Unknown" B97M_V_def2_QZVPPD_PCM_Single_Point = "B97M-V/def2-QZVPPD/PCM Single Point" B97M_V_def2_QZVPPD_PCM_Force = "B97M-V/def2-QZVPPD/PCM Force" B97M_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/PCM Transition State 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_Unknown = "B97M-V/def2-QZVPPD/PCM Unknown" B97M_V_def2_QZVPPD_SMD_Single_Point = "B97M-V/def2-QZVPPD/SMD Single Point" B97M_V_def2_QZVPPD_SMD_Force = "B97M-V/def2-QZVPPD/SMD Force" B97M_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-V/def2-QZVPPD/SMD Transition State 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_Unknown = "B97M-V/def2-QZVPPD/SMD Unknown" B97M_rV_6_31g_d_VACUUM_Single_Point = "B97M-rV/6-31g*/VACUUM Single Point" B97M_rV_6_31g_d_VACUUM_Force = "B97M-rV/6-31g*/VACUUM Force" B97M_rV_6_31g_d_VACUUM_Geometry_Optimization = ( "B97M-rV/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/VACUUM Transition State 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_Unknown = "B97M-rV/6-31g*/VACUUM Unknown" B97M_rV_6_31g_d_PCM_Single_Point = "B97M-rV/6-31g*/PCM Single Point" B97M_rV_6_31g_d_PCM_Force = "B97M-rV/6-31g*/PCM Force" B97M_rV_6_31g_d_PCM_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/PCM Transition State 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_Unknown = "B97M-rV/6-31g*/PCM Unknown" B97M_rV_6_31g_d_SMD_Single_Point = "B97M-rV/6-31g*/SMD Single Point" B97M_rV_6_31g_d_SMD_Force = "B97M-rV/6-31g*/SMD Force" B97M_rV_6_31g_d_SMD_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/6-31g*/SMD Transition State 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_Unknown = "B97M-rV/6-31g*/SMD Unknown" B97M_rV_def2_SVPD_VACUUM_Single_Point = "B97M-rV/def2-SVPD/VACUUM Single Point" B97M_rV_def2_SVPD_VACUUM_Force = "B97M-rV/def2-SVPD/VACUUM Force" B97M_rV_def2_SVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/VACUUM Transition State 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_Unknown = "B97M-rV/def2-SVPD/VACUUM Unknown" B97M_rV_def2_SVPD_PCM_Single_Point = "B97M-rV/def2-SVPD/PCM Single Point" B97M_rV_def2_SVPD_PCM_Force = "B97M-rV/def2-SVPD/PCM Force" B97M_rV_def2_SVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/PCM Transition State 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_Unknown = "B97M-rV/def2-SVPD/PCM Unknown" B97M_rV_def2_SVPD_SMD_Single_Point = "B97M-rV/def2-SVPD/SMD Single Point" B97M_rV_def2_SVPD_SMD_Force = "B97M-rV/def2-SVPD/SMD Force" B97M_rV_def2_SVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-SVPD/SMD Transition State 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_Unknown = "B97M-rV/def2-SVPD/SMD Unknown" B97M_rV_def2_TZVP_VACUUM_Single_Point = "B97M-rV/def2-TZVP/VACUUM Single Point" B97M_rV_def2_TZVP_VACUUM_Force = "B97M-rV/def2-TZVP/VACUUM Force" B97M_rV_def2_TZVP_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/VACUUM Transition State 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_Unknown = "B97M-rV/def2-TZVP/VACUUM Unknown" B97M_rV_def2_TZVP_PCM_Single_Point = "B97M-rV/def2-TZVP/PCM Single Point" B97M_rV_def2_TZVP_PCM_Force = "B97M-rV/def2-TZVP/PCM Force" B97M_rV_def2_TZVP_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/PCM Transition State 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_Unknown = "B97M-rV/def2-TZVP/PCM Unknown" B97M_rV_def2_TZVP_SMD_Single_Point = "B97M-rV/def2-TZVP/SMD Single Point" B97M_rV_def2_TZVP_SMD_Force = "B97M-rV/def2-TZVP/SMD Force" B97M_rV_def2_TZVP_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVP/SMD Transition State 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_Unknown = "B97M-rV/def2-TZVP/SMD Unknown" B97M_rV_def2_TZVPD_VACUUM_Single_Point = "B97M-rV/def2-TZVPD/VACUUM Single Point" B97M_rV_def2_TZVPD_VACUUM_Force = "B97M-rV/def2-TZVPD/VACUUM Force" B97M_rV_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/VACUUM Transition State 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_Unknown = "B97M-rV/def2-TZVPD/VACUUM Unknown" B97M_rV_def2_TZVPD_PCM_Single_Point = "B97M-rV/def2-TZVPD/PCM Single Point" B97M_rV_def2_TZVPD_PCM_Force = "B97M-rV/def2-TZVPD/PCM Force" B97M_rV_def2_TZVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/PCM Transition State 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_Unknown = "B97M-rV/def2-TZVPD/PCM Unknown" B97M_rV_def2_TZVPD_SMD_Single_Point = "B97M-rV/def2-TZVPD/SMD Single Point" B97M_rV_def2_TZVPD_SMD_Force = "B97M-rV/def2-TZVPD/SMD Force" B97M_rV_def2_TZVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPD/SMD Transition State 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_Unknown = "B97M-rV/def2-TZVPD/SMD Unknown" B97M_rV_def2_TZVPP_VACUUM_Single_Point = "B97M-rV/def2-TZVPP/VACUUM Single Point" B97M_rV_def2_TZVPP_VACUUM_Force = "B97M-rV/def2-TZVPP/VACUUM Force" B97M_rV_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/VACUUM Transition State 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_Unknown = "B97M-rV/def2-TZVPP/VACUUM Unknown" B97M_rV_def2_TZVPP_PCM_Single_Point = "B97M-rV/def2-TZVPP/PCM Single Point" B97M_rV_def2_TZVPP_PCM_Force = "B97M-rV/def2-TZVPP/PCM Force" B97M_rV_def2_TZVPP_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/PCM Transition State 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_Unknown = "B97M-rV/def2-TZVPP/PCM Unknown" B97M_rV_def2_TZVPP_SMD_Single_Point = "B97M-rV/def2-TZVPP/SMD Single Point" B97M_rV_def2_TZVPP_SMD_Force = "B97M-rV/def2-TZVPP/SMD Force" B97M_rV_def2_TZVPP_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPP/SMD Transition State 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_Unknown = "B97M-rV/def2-TZVPP/SMD Unknown" B97M_rV_def2_TZVPPD_VACUUM_Single_Point = "B97M-rV/def2-TZVPPD/VACUUM Single Point" B97M_rV_def2_TZVPPD_VACUUM_Force = "B97M-rV/def2-TZVPPD/VACUUM Force" B97M_rV_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/VACUUM Transition State 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_Unknown = "B97M-rV/def2-TZVPPD/VACUUM Unknown" B97M_rV_def2_TZVPPD_PCM_Single_Point = "B97M-rV/def2-TZVPPD/PCM Single Point" B97M_rV_def2_TZVPPD_PCM_Force = "B97M-rV/def2-TZVPPD/PCM Force" B97M_rV_def2_TZVPPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/PCM Transition State 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_Unknown = "B97M-rV/def2-TZVPPD/PCM Unknown" B97M_rV_def2_TZVPPD_SMD_Single_Point = "B97M-rV/def2-TZVPPD/SMD Single Point" B97M_rV_def2_TZVPPD_SMD_Force = "B97M-rV/def2-TZVPPD/SMD Force" B97M_rV_def2_TZVPPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-TZVPPD/SMD Transition State 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_Unknown = "B97M-rV/def2-TZVPPD/SMD Unknown" B97M_rV_def2_QZVPD_VACUUM_Single_Point = "B97M-rV/def2-QZVPD/VACUUM Single Point" B97M_rV_def2_QZVPD_VACUUM_Force = "B97M-rV/def2-QZVPD/VACUUM Force" B97M_rV_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/VACUUM Transition State 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_Unknown = "B97M-rV/def2-QZVPD/VACUUM Unknown" B97M_rV_def2_QZVPD_PCM_Single_Point = "B97M-rV/def2-QZVPD/PCM Single Point" B97M_rV_def2_QZVPD_PCM_Force = "B97M-rV/def2-QZVPD/PCM Force" B97M_rV_def2_QZVPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/PCM Transition State 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_Unknown = "B97M-rV/def2-QZVPD/PCM Unknown" B97M_rV_def2_QZVPD_SMD_Single_Point = "B97M-rV/def2-QZVPD/SMD Single Point" B97M_rV_def2_QZVPD_SMD_Force = "B97M-rV/def2-QZVPD/SMD Force" B97M_rV_def2_QZVPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPD/SMD Transition State 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_Unknown = "B97M-rV/def2-QZVPD/SMD Unknown" B97M_rV_def2_QZVPPD_VACUUM_Single_Point = "B97M-rV/def2-QZVPPD/VACUUM Single Point" B97M_rV_def2_QZVPPD_VACUUM_Force = "B97M-rV/def2-QZVPPD/VACUUM Force" B97M_rV_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/VACUUM Transition State 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_Unknown = "B97M-rV/def2-QZVPPD/VACUUM Unknown" B97M_rV_def2_QZVPPD_PCM_Single_Point = "B97M-rV/def2-QZVPPD/PCM Single Point" B97M_rV_def2_QZVPPD_PCM_Force = "B97M-rV/def2-QZVPPD/PCM Force" B97M_rV_def2_QZVPPD_PCM_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/PCM Transition State 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_Unknown = "B97M-rV/def2-QZVPPD/PCM Unknown" B97M_rV_def2_QZVPPD_SMD_Single_Point = "B97M-rV/def2-QZVPPD/SMD Single Point" B97M_rV_def2_QZVPPD_SMD_Force = "B97M-rV/def2-QZVPPD/SMD Force" B97M_rV_def2_QZVPPD_SMD_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B97M-rV/def2-QZVPPD/SMD Transition State 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_Unknown = "B97M-rV/def2-QZVPPD/SMD Unknown" B3LYP_6_31g_d_VACUUM_Single_Point = "B3LYP/6-31g*/VACUUM Single Point" B3LYP_6_31g_d_VACUUM_Force = "B3LYP/6-31g*/VACUUM Force" B3LYP_6_31g_d_VACUUM_Geometry_Optimization = ( "B3LYP/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/VACUUM Transition State 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_Unknown = "B3LYP/6-31g*/VACUUM Unknown" B3LYP_6_31g_d_PCM_Single_Point = "B3LYP/6-31g*/PCM Single Point" B3LYP_6_31g_d_PCM_Force = "B3LYP/6-31g*/PCM Force" B3LYP_6_31g_d_PCM_Geometry_Optimization = "B3LYP/6-31g*/PCM Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/PCM Transition State 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_Unknown = "B3LYP/6-31g*/PCM Unknown" B3LYP_6_31g_d_SMD_Single_Point = "B3LYP/6-31g*/SMD Single Point" B3LYP_6_31g_d_SMD_Force = "B3LYP/6-31g*/SMD Force" B3LYP_6_31g_d_SMD_Geometry_Optimization = "B3LYP/6-31g*/SMD Geometry Optimization" 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_Transition_State_Geometry_Optimization = ( "B3LYP/6-31g*/SMD Transition State 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_Unknown = "B3LYP/6-31g*/SMD Unknown" B3LYP_def2_SVPD_VACUUM_Single_Point = "B3LYP/def2-SVPD/VACUUM Single Point" B3LYP_def2_SVPD_VACUUM_Force = "B3LYP/def2-SVPD/VACUUM Force" B3LYP_def2_SVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/VACUUM Transition State 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_Unknown = "B3LYP/def2-SVPD/VACUUM Unknown" B3LYP_def2_SVPD_PCM_Single_Point = "B3LYP/def2-SVPD/PCM Single Point" B3LYP_def2_SVPD_PCM_Force = "B3LYP/def2-SVPD/PCM Force" B3LYP_def2_SVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/PCM Transition State 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_Unknown = "B3LYP/def2-SVPD/PCM Unknown" B3LYP_def2_SVPD_SMD_Single_Point = "B3LYP/def2-SVPD/SMD Single Point" B3LYP_def2_SVPD_SMD_Force = "B3LYP/def2-SVPD/SMD Force" B3LYP_def2_SVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-SVPD/SMD Transition State 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_Unknown = "B3LYP/def2-SVPD/SMD Unknown" B3LYP_def2_TZVP_VACUUM_Single_Point = "B3LYP/def2-TZVP/VACUUM Single Point" B3LYP_def2_TZVP_VACUUM_Force = "B3LYP/def2-TZVP/VACUUM Force" B3LYP_def2_TZVP_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/VACUUM Transition State 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_Unknown = "B3LYP/def2-TZVP/VACUUM Unknown" B3LYP_def2_TZVP_PCM_Single_Point = "B3LYP/def2-TZVP/PCM Single Point" B3LYP_def2_TZVP_PCM_Force = "B3LYP/def2-TZVP/PCM Force" B3LYP_def2_TZVP_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/PCM Transition State 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_Unknown = "B3LYP/def2-TZVP/PCM Unknown" B3LYP_def2_TZVP_SMD_Single_Point = "B3LYP/def2-TZVP/SMD Single Point" B3LYP_def2_TZVP_SMD_Force = "B3LYP/def2-TZVP/SMD Force" B3LYP_def2_TZVP_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVP/SMD Transition State 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_Unknown = "B3LYP/def2-TZVP/SMD Unknown" B3LYP_def2_TZVPD_VACUUM_Single_Point = "B3LYP/def2-TZVPD/VACUUM Single Point" B3LYP_def2_TZVPD_VACUUM_Force = "B3LYP/def2-TZVPD/VACUUM Force" B3LYP_def2_TZVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/VACUUM Transition State 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_Unknown = "B3LYP/def2-TZVPD/VACUUM Unknown" B3LYP_def2_TZVPD_PCM_Single_Point = "B3LYP/def2-TZVPD/PCM Single Point" B3LYP_def2_TZVPD_PCM_Force = "B3LYP/def2-TZVPD/PCM Force" B3LYP_def2_TZVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/PCM Transition State 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_Unknown = "B3LYP/def2-TZVPD/PCM Unknown" B3LYP_def2_TZVPD_SMD_Single_Point = "B3LYP/def2-TZVPD/SMD Single Point" B3LYP_def2_TZVPD_SMD_Force = "B3LYP/def2-TZVPD/SMD Force" B3LYP_def2_TZVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPD/SMD Transition State 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_Unknown = "B3LYP/def2-TZVPD/SMD Unknown" B3LYP_def2_TZVPP_VACUUM_Single_Point = "B3LYP/def2-TZVPP/VACUUM Single Point" B3LYP_def2_TZVPP_VACUUM_Force = "B3LYP/def2-TZVPP/VACUUM Force" B3LYP_def2_TZVPP_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/VACUUM Transition State 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_Unknown = "B3LYP/def2-TZVPP/VACUUM Unknown" B3LYP_def2_TZVPP_PCM_Single_Point = "B3LYP/def2-TZVPP/PCM Single Point" B3LYP_def2_TZVPP_PCM_Force = "B3LYP/def2-TZVPP/PCM Force" B3LYP_def2_TZVPP_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/PCM Transition State 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_Unknown = "B3LYP/def2-TZVPP/PCM Unknown" B3LYP_def2_TZVPP_SMD_Single_Point = "B3LYP/def2-TZVPP/SMD Single Point" B3LYP_def2_TZVPP_SMD_Force = "B3LYP/def2-TZVPP/SMD Force" B3LYP_def2_TZVPP_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPP/SMD Transition State 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_Unknown = "B3LYP/def2-TZVPP/SMD Unknown" B3LYP_def2_TZVPPD_VACUUM_Single_Point = "B3LYP/def2-TZVPPD/VACUUM Single Point" B3LYP_def2_TZVPPD_VACUUM_Force = "B3LYP/def2-TZVPPD/VACUUM Force" B3LYP_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/VACUUM Transition State 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_Unknown = "B3LYP/def2-TZVPPD/VACUUM Unknown" B3LYP_def2_TZVPPD_PCM_Single_Point = "B3LYP/def2-TZVPPD/PCM Single Point" B3LYP_def2_TZVPPD_PCM_Force = "B3LYP/def2-TZVPPD/PCM Force" B3LYP_def2_TZVPPD_PCM_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/PCM Transition State 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_Unknown = "B3LYP/def2-TZVPPD/PCM Unknown" B3LYP_def2_TZVPPD_SMD_Single_Point = "B3LYP/def2-TZVPPD/SMD Single Point" B3LYP_def2_TZVPPD_SMD_Force = "B3LYP/def2-TZVPPD/SMD Force" B3LYP_def2_TZVPPD_SMD_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-TZVPPD/SMD Transition State 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_Unknown = "B3LYP/def2-TZVPPD/SMD Unknown" B3LYP_def2_QZVPD_VACUUM_Single_Point = "B3LYP/def2-QZVPD/VACUUM Single Point" B3LYP_def2_QZVPD_VACUUM_Force = "B3LYP/def2-QZVPD/VACUUM Force" B3LYP_def2_QZVPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/VACUUM Transition State 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_Unknown = "B3LYP/def2-QZVPD/VACUUM Unknown" B3LYP_def2_QZVPD_PCM_Single_Point = "B3LYP/def2-QZVPD/PCM Single Point" B3LYP_def2_QZVPD_PCM_Force = "B3LYP/def2-QZVPD/PCM Force" B3LYP_def2_QZVPD_PCM_Geometry_Optimization = ( "B3LYP/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/PCM Transition State 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_Unknown = "B3LYP/def2-QZVPD/PCM Unknown" B3LYP_def2_QZVPD_SMD_Single_Point = "B3LYP/def2-QZVPD/SMD Single Point" B3LYP_def2_QZVPD_SMD_Force = "B3LYP/def2-QZVPD/SMD Force" B3LYP_def2_QZVPD_SMD_Geometry_Optimization = ( "B3LYP/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPD/SMD Transition State 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_Unknown = "B3LYP/def2-QZVPD/SMD Unknown" B3LYP_def2_QZVPPD_VACUUM_Single_Point = "B3LYP/def2-QZVPPD/VACUUM Single Point" B3LYP_def2_QZVPPD_VACUUM_Force = "B3LYP/def2-QZVPPD/VACUUM Force" B3LYP_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/VACUUM Transition State 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_Unknown = "B3LYP/def2-QZVPPD/VACUUM Unknown" B3LYP_def2_QZVPPD_PCM_Single_Point = "B3LYP/def2-QZVPPD/PCM Single Point" B3LYP_def2_QZVPPD_PCM_Force = "B3LYP/def2-QZVPPD/PCM Force" B3LYP_def2_QZVPPD_PCM_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/PCM Transition State 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_Unknown = "B3LYP/def2-QZVPPD/PCM Unknown" B3LYP_def2_QZVPPD_SMD_Single_Point = "B3LYP/def2-QZVPPD/SMD Single Point" B3LYP_def2_QZVPPD_SMD_Force = "B3LYP/def2-QZVPPD/SMD Force" B3LYP_def2_QZVPPD_SMD_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "B3LYP/def2-QZVPPD/SMD Transition State 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_Unknown = "B3LYP/def2-QZVPPD/SMD Unknown" wB97X_D_6_31g_d_VACUUM_Single_Point = "wB97X-D/6-31g*/VACUUM Single Point" wB97X_D_6_31g_d_VACUUM_Force = "wB97X-D/6-31g*/VACUUM Force" wB97X_D_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-D/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/VACUUM Transition State 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_Unknown = "wB97X-D/6-31g*/VACUUM Unknown" wB97X_D_6_31g_d_PCM_Single_Point = "wB97X-D/6-31g*/PCM Single Point" wB97X_D_6_31g_d_PCM_Force = "wB97X-D/6-31g*/PCM Force" wB97X_D_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/PCM Transition State 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_Unknown = "wB97X-D/6-31g*/PCM Unknown" wB97X_D_6_31g_d_SMD_Single_Point = "wB97X-D/6-31g*/SMD Single Point" wB97X_D_6_31g_d_SMD_Force = "wB97X-D/6-31g*/SMD Force" wB97X_D_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/6-31g*/SMD Transition State 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_Unknown = "wB97X-D/6-31g*/SMD Unknown" wB97X_D_def2_SVPD_VACUUM_Single_Point = "wB97X-D/def2-SVPD/VACUUM Single Point" wB97X_D_def2_SVPD_VACUUM_Force = "wB97X-D/def2-SVPD/VACUUM Force" wB97X_D_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/VACUUM Transition State 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_Unknown = "wB97X-D/def2-SVPD/VACUUM Unknown" wB97X_D_def2_SVPD_PCM_Single_Point = "wB97X-D/def2-SVPD/PCM Single Point" wB97X_D_def2_SVPD_PCM_Force = "wB97X-D/def2-SVPD/PCM Force" wB97X_D_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/PCM Transition State 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_Unknown = "wB97X-D/def2-SVPD/PCM Unknown" wB97X_D_def2_SVPD_SMD_Single_Point = "wB97X-D/def2-SVPD/SMD Single Point" wB97X_D_def2_SVPD_SMD_Force = "wB97X-D/def2-SVPD/SMD Force" wB97X_D_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-SVPD/SMD Transition State 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_Unknown = "wB97X-D/def2-SVPD/SMD Unknown" wB97X_D_def2_TZVP_VACUUM_Single_Point = "wB97X-D/def2-TZVP/VACUUM Single Point" wB97X_D_def2_TZVP_VACUUM_Force = "wB97X-D/def2-TZVP/VACUUM Force" wB97X_D_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/VACUUM Transition State 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_Unknown = "wB97X-D/def2-TZVP/VACUUM Unknown" wB97X_D_def2_TZVP_PCM_Single_Point = "wB97X-D/def2-TZVP/PCM Single Point" wB97X_D_def2_TZVP_PCM_Force = "wB97X-D/def2-TZVP/PCM Force" wB97X_D_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/PCM Transition State 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_Unknown = "wB97X-D/def2-TZVP/PCM Unknown" wB97X_D_def2_TZVP_SMD_Single_Point = "wB97X-D/def2-TZVP/SMD Single Point" wB97X_D_def2_TZVP_SMD_Force = "wB97X-D/def2-TZVP/SMD Force" wB97X_D_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVP/SMD Transition State 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_Unknown = "wB97X-D/def2-TZVP/SMD Unknown" wB97X_D_def2_TZVPD_VACUUM_Single_Point = "wB97X-D/def2-TZVPD/VACUUM Single Point" wB97X_D_def2_TZVPD_VACUUM_Force = "wB97X-D/def2-TZVPD/VACUUM Force" wB97X_D_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/VACUUM Transition State 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_Unknown = "wB97X-D/def2-TZVPD/VACUUM Unknown" wB97X_D_def2_TZVPD_PCM_Single_Point = "wB97X-D/def2-TZVPD/PCM Single Point" wB97X_D_def2_TZVPD_PCM_Force = "wB97X-D/def2-TZVPD/PCM Force" wB97X_D_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/PCM Transition State 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_Unknown = "wB97X-D/def2-TZVPD/PCM Unknown" wB97X_D_def2_TZVPD_SMD_Single_Point = "wB97X-D/def2-TZVPD/SMD Single Point" wB97X_D_def2_TZVPD_SMD_Force = "wB97X-D/def2-TZVPD/SMD Force" wB97X_D_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPD/SMD Transition State 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_Unknown = "wB97X-D/def2-TZVPD/SMD Unknown" wB97X_D_def2_TZVPP_VACUUM_Single_Point = "wB97X-D/def2-TZVPP/VACUUM Single Point" wB97X_D_def2_TZVPP_VACUUM_Force = "wB97X-D/def2-TZVPP/VACUUM Force" wB97X_D_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/VACUUM Transition State 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_Unknown = "wB97X-D/def2-TZVPP/VACUUM Unknown" wB97X_D_def2_TZVPP_PCM_Single_Point = "wB97X-D/def2-TZVPP/PCM Single Point" wB97X_D_def2_TZVPP_PCM_Force = "wB97X-D/def2-TZVPP/PCM Force" wB97X_D_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/PCM Transition State 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_Unknown = "wB97X-D/def2-TZVPP/PCM Unknown" wB97X_D_def2_TZVPP_SMD_Single_Point = "wB97X-D/def2-TZVPP/SMD Single Point" wB97X_D_def2_TZVPP_SMD_Force = "wB97X-D/def2-TZVPP/SMD Force" wB97X_D_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPP/SMD Transition State 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_Unknown = "wB97X-D/def2-TZVPP/SMD Unknown" wB97X_D_def2_TZVPPD_VACUUM_Single_Point = "wB97X-D/def2-TZVPPD/VACUUM Single Point" wB97X_D_def2_TZVPPD_VACUUM_Force = "wB97X-D/def2-TZVPPD/VACUUM Force" wB97X_D_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/VACUUM Transition State 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_Unknown = "wB97X-D/def2-TZVPPD/VACUUM Unknown" wB97X_D_def2_TZVPPD_PCM_Single_Point = "wB97X-D/def2-TZVPPD/PCM Single Point" wB97X_D_def2_TZVPPD_PCM_Force = "wB97X-D/def2-TZVPPD/PCM Force" wB97X_D_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/PCM Transition State 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_Unknown = "wB97X-D/def2-TZVPPD/PCM Unknown" wB97X_D_def2_TZVPPD_SMD_Single_Point = "wB97X-D/def2-TZVPPD/SMD Single Point" wB97X_D_def2_TZVPPD_SMD_Force = "wB97X-D/def2-TZVPPD/SMD Force" wB97X_D_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-TZVPPD/SMD Transition State 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_Unknown = "wB97X-D/def2-TZVPPD/SMD Unknown" wB97X_D_def2_QZVPD_VACUUM_Single_Point = "wB97X-D/def2-QZVPD/VACUUM Single Point" wB97X_D_def2_QZVPD_VACUUM_Force = "wB97X-D/def2-QZVPD/VACUUM Force" wB97X_D_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/VACUUM Transition State 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_Unknown = "wB97X-D/def2-QZVPD/VACUUM Unknown" wB97X_D_def2_QZVPD_PCM_Single_Point = "wB97X-D/def2-QZVPD/PCM Single Point" wB97X_D_def2_QZVPD_PCM_Force = "wB97X-D/def2-QZVPD/PCM Force" wB97X_D_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/PCM Transition State 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_Unknown = "wB97X-D/def2-QZVPD/PCM Unknown" wB97X_D_def2_QZVPD_SMD_Single_Point = "wB97X-D/def2-QZVPD/SMD Single Point" wB97X_D_def2_QZVPD_SMD_Force = "wB97X-D/def2-QZVPD/SMD Force" wB97X_D_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPD/SMD Transition State 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_Unknown = "wB97X-D/def2-QZVPD/SMD Unknown" wB97X_D_def2_QZVPPD_VACUUM_Single_Point = "wB97X-D/def2-QZVPPD/VACUUM Single Point" wB97X_D_def2_QZVPPD_VACUUM_Force = "wB97X-D/def2-QZVPPD/VACUUM Force" wB97X_D_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/VACUUM Transition State 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_Unknown = "wB97X-D/def2-QZVPPD/VACUUM Unknown" wB97X_D_def2_QZVPPD_PCM_Single_Point = "wB97X-D/def2-QZVPPD/PCM Single Point" wB97X_D_def2_QZVPPD_PCM_Force = "wB97X-D/def2-QZVPPD/PCM Force" wB97X_D_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/PCM Transition State 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_Unknown = "wB97X-D/def2-QZVPPD/PCM Unknown" wB97X_D_def2_QZVPPD_SMD_Single_Point = "wB97X-D/def2-QZVPPD/SMD Single Point" wB97X_D_def2_QZVPPD_SMD_Force = "wB97X-D/def2-QZVPPD/SMD Force" wB97X_D_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D/def2-QZVPPD/SMD Transition State 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_Unknown = "wB97X-D/def2-QZVPPD/SMD Unknown" wB97X_D3_6_31g_d_VACUUM_Single_Point = "wB97X-D3/6-31g*/VACUUM Single Point" wB97X_D3_6_31g_d_VACUUM_Force = "wB97X-D3/6-31g*/VACUUM Force" wB97X_D3_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-D3/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/VACUUM Transition State 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_Unknown = "wB97X-D3/6-31g*/VACUUM Unknown" wB97X_D3_6_31g_d_PCM_Single_Point = "wB97X-D3/6-31g*/PCM Single Point" wB97X_D3_6_31g_d_PCM_Force = "wB97X-D3/6-31g*/PCM Force" wB97X_D3_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-D3/6-31g*/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/PCM Transition State 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_Unknown = "wB97X-D3/6-31g*/PCM Unknown" wB97X_D3_6_31g_d_SMD_Single_Point = "wB97X-D3/6-31g*/SMD Single Point" wB97X_D3_6_31g_d_SMD_Force = "wB97X-D3/6-31g*/SMD Force" wB97X_D3_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-D3/6-31g*/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/6-31g*/SMD Transition State 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_Unknown = "wB97X-D3/6-31g*/SMD Unknown" wB97X_D3_def2_SVPD_VACUUM_Single_Point = "wB97X-D3/def2-SVPD/VACUUM Single Point" wB97X_D3_def2_SVPD_VACUUM_Force = "wB97X-D3/def2-SVPD/VACUUM Force" wB97X_D3_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-SVPD/VACUUM Unknown" wB97X_D3_def2_SVPD_PCM_Single_Point = "wB97X-D3/def2-SVPD/PCM Single Point" wB97X_D3_def2_SVPD_PCM_Force = "wB97X-D3/def2-SVPD/PCM Force" wB97X_D3_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/PCM Transition State 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_Unknown = "wB97X-D3/def2-SVPD/PCM Unknown" wB97X_D3_def2_SVPD_SMD_Single_Point = "wB97X-D3/def2-SVPD/SMD Single Point" wB97X_D3_def2_SVPD_SMD_Force = "wB97X-D3/def2-SVPD/SMD Force" wB97X_D3_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-SVPD/SMD Transition State 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_Unknown = "wB97X-D3/def2-SVPD/SMD Unknown" wB97X_D3_def2_TZVP_VACUUM_Single_Point = "wB97X-D3/def2-TZVP/VACUUM Single Point" wB97X_D3_def2_TZVP_VACUUM_Force = "wB97X-D3/def2-TZVP/VACUUM Force" wB97X_D3_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-TZVP/VACUUM Unknown" wB97X_D3_def2_TZVP_PCM_Single_Point = "wB97X-D3/def2-TZVP/PCM Single Point" wB97X_D3_def2_TZVP_PCM_Force = "wB97X-D3/def2-TZVP/PCM Force" wB97X_D3_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/PCM Transition State 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_Unknown = "wB97X-D3/def2-TZVP/PCM Unknown" wB97X_D3_def2_TZVP_SMD_Single_Point = "wB97X-D3/def2-TZVP/SMD Single Point" wB97X_D3_def2_TZVP_SMD_Force = "wB97X-D3/def2-TZVP/SMD Force" wB97X_D3_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVP/SMD Transition State 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_Unknown = "wB97X-D3/def2-TZVP/SMD Unknown" wB97X_D3_def2_TZVPD_VACUUM_Single_Point = "wB97X-D3/def2-TZVPD/VACUUM Single Point" wB97X_D3_def2_TZVPD_VACUUM_Force = "wB97X-D3/def2-TZVPD/VACUUM Force" wB97X_D3_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-TZVPD/VACUUM Unknown" wB97X_D3_def2_TZVPD_PCM_Single_Point = "wB97X-D3/def2-TZVPD/PCM Single Point" wB97X_D3_def2_TZVPD_PCM_Force = "wB97X-D3/def2-TZVPD/PCM Force" wB97X_D3_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/PCM Transition State 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_Unknown = "wB97X-D3/def2-TZVPD/PCM Unknown" wB97X_D3_def2_TZVPD_SMD_Single_Point = "wB97X-D3/def2-TZVPD/SMD Single Point" wB97X_D3_def2_TZVPD_SMD_Force = "wB97X-D3/def2-TZVPD/SMD Force" wB97X_D3_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPD/SMD Transition State 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_Unknown = "wB97X-D3/def2-TZVPD/SMD Unknown" wB97X_D3_def2_TZVPP_VACUUM_Single_Point = "wB97X-D3/def2-TZVPP/VACUUM Single Point" wB97X_D3_def2_TZVPP_VACUUM_Force = "wB97X-D3/def2-TZVPP/VACUUM Force" wB97X_D3_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-TZVPP/VACUUM Unknown" wB97X_D3_def2_TZVPP_PCM_Single_Point = "wB97X-D3/def2-TZVPP/PCM Single Point" wB97X_D3_def2_TZVPP_PCM_Force = "wB97X-D3/def2-TZVPP/PCM Force" wB97X_D3_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/PCM Transition State 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_Unknown = "wB97X-D3/def2-TZVPP/PCM Unknown" wB97X_D3_def2_TZVPP_SMD_Single_Point = "wB97X-D3/def2-TZVPP/SMD Single Point" wB97X_D3_def2_TZVPP_SMD_Force = "wB97X-D3/def2-TZVPP/SMD Force" wB97X_D3_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPP/SMD Transition State 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_Unknown = "wB97X-D3/def2-TZVPP/SMD Unknown" wB97X_D3_def2_TZVPPD_VACUUM_Single_Point = ( "wB97X-D3/def2-TZVPPD/VACUUM Single Point" ) wB97X_D3_def2_TZVPPD_VACUUM_Force = "wB97X-D3/def2-TZVPPD/VACUUM Force" wB97X_D3_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-TZVPPD/VACUUM Unknown" wB97X_D3_def2_TZVPPD_PCM_Single_Point = "wB97X-D3/def2-TZVPPD/PCM Single Point" wB97X_D3_def2_TZVPPD_PCM_Force = "wB97X-D3/def2-TZVPPD/PCM Force" wB97X_D3_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/PCM Transition State 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_Unknown = "wB97X-D3/def2-TZVPPD/PCM Unknown" wB97X_D3_def2_TZVPPD_SMD_Single_Point = "wB97X-D3/def2-TZVPPD/SMD Single Point" wB97X_D3_def2_TZVPPD_SMD_Force = "wB97X-D3/def2-TZVPPD/SMD Force" wB97X_D3_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-TZVPPD/SMD Transition State 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_Unknown = "wB97X-D3/def2-TZVPPD/SMD Unknown" wB97X_D3_def2_QZVPD_VACUUM_Single_Point = "wB97X-D3/def2-QZVPD/VACUUM Single Point" wB97X_D3_def2_QZVPD_VACUUM_Force = "wB97X-D3/def2-QZVPD/VACUUM Force" wB97X_D3_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-QZVPD/VACUUM Unknown" wB97X_D3_def2_QZVPD_PCM_Single_Point = "wB97X-D3/def2-QZVPD/PCM Single Point" wB97X_D3_def2_QZVPD_PCM_Force = "wB97X-D3/def2-QZVPD/PCM Force" wB97X_D3_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/PCM Transition State 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_Unknown = "wB97X-D3/def2-QZVPD/PCM Unknown" wB97X_D3_def2_QZVPD_SMD_Single_Point = "wB97X-D3/def2-QZVPD/SMD Single Point" wB97X_D3_def2_QZVPD_SMD_Force = "wB97X-D3/def2-QZVPD/SMD Force" wB97X_D3_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPD/SMD Transition State 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_Unknown = "wB97X-D3/def2-QZVPD/SMD Unknown" wB97X_D3_def2_QZVPPD_VACUUM_Single_Point = ( "wB97X-D3/def2-QZVPPD/VACUUM Single Point" ) wB97X_D3_def2_QZVPPD_VACUUM_Force = "wB97X-D3/def2-QZVPPD/VACUUM Force" wB97X_D3_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/VACUUM Transition State 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_Unknown = "wB97X-D3/def2-QZVPPD/VACUUM Unknown" wB97X_D3_def2_QZVPPD_PCM_Single_Point = "wB97X-D3/def2-QZVPPD/PCM Single Point" wB97X_D3_def2_QZVPPD_PCM_Force = "wB97X-D3/def2-QZVPPD/PCM Force" wB97X_D3_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/PCM Transition State 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_Unknown = "wB97X-D3/def2-QZVPPD/PCM Unknown" wB97X_D3_def2_QZVPPD_SMD_Single_Point = "wB97X-D3/def2-QZVPPD/SMD Single Point" wB97X_D3_def2_QZVPPD_SMD_Force = "wB97X-D3/def2-QZVPPD/SMD Force" wB97X_D3_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-D3/def2-QZVPPD/SMD Transition State 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_Unknown = "wB97X-D3/def2-QZVPPD/SMD Unknown" wB97X_V_6_31g_d_VACUUM_Single_Point = "wB97X-V/6-31g*/VACUUM Single Point" wB97X_V_6_31g_d_VACUUM_Force = "wB97X-V/6-31g*/VACUUM Force" wB97X_V_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97X-V/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/VACUUM Transition State 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_Unknown = "wB97X-V/6-31g*/VACUUM Unknown" wB97X_V_6_31g_d_PCM_Single_Point = "wB97X-V/6-31g*/PCM Single Point" wB97X_V_6_31g_d_PCM_Force = "wB97X-V/6-31g*/PCM Force" wB97X_V_6_31g_d_PCM_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/PCM Transition State 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_Unknown = "wB97X-V/6-31g*/PCM Unknown" wB97X_V_6_31g_d_SMD_Single_Point = "wB97X-V/6-31g*/SMD Single Point" wB97X_V_6_31g_d_SMD_Force = "wB97X-V/6-31g*/SMD Force" wB97X_V_6_31g_d_SMD_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/6-31g*/SMD Transition State 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_Unknown = "wB97X-V/6-31g*/SMD Unknown" wB97X_V_def2_SVPD_VACUUM_Single_Point = "wB97X-V/def2-SVPD/VACUUM Single Point" wB97X_V_def2_SVPD_VACUUM_Force = "wB97X-V/def2-SVPD/VACUUM Force" wB97X_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/VACUUM Transition State 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_Unknown = "wB97X-V/def2-SVPD/VACUUM Unknown" wB97X_V_def2_SVPD_PCM_Single_Point = "wB97X-V/def2-SVPD/PCM Single Point" wB97X_V_def2_SVPD_PCM_Force = "wB97X-V/def2-SVPD/PCM Force" wB97X_V_def2_SVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/PCM Transition State 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_Unknown = "wB97X-V/def2-SVPD/PCM Unknown" wB97X_V_def2_SVPD_SMD_Single_Point = "wB97X-V/def2-SVPD/SMD Single Point" wB97X_V_def2_SVPD_SMD_Force = "wB97X-V/def2-SVPD/SMD Force" wB97X_V_def2_SVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-SVPD/SMD Transition State 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_Unknown = "wB97X-V/def2-SVPD/SMD Unknown" wB97X_V_def2_TZVP_VACUUM_Single_Point = "wB97X-V/def2-TZVP/VACUUM Single Point" wB97X_V_def2_TZVP_VACUUM_Force = "wB97X-V/def2-TZVP/VACUUM Force" wB97X_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/VACUUM Transition State 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_Unknown = "wB97X-V/def2-TZVP/VACUUM Unknown" wB97X_V_def2_TZVP_PCM_Single_Point = "wB97X-V/def2-TZVP/PCM Single Point" wB97X_V_def2_TZVP_PCM_Force = "wB97X-V/def2-TZVP/PCM Force" wB97X_V_def2_TZVP_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/PCM Transition State 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_Unknown = "wB97X-V/def2-TZVP/PCM Unknown" wB97X_V_def2_TZVP_SMD_Single_Point = "wB97X-V/def2-TZVP/SMD Single Point" wB97X_V_def2_TZVP_SMD_Force = "wB97X-V/def2-TZVP/SMD Force" wB97X_V_def2_TZVP_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVP/SMD Transition State 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_Unknown = "wB97X-V/def2-TZVP/SMD Unknown" wB97X_V_def2_TZVPD_VACUUM_Single_Point = "wB97X-V/def2-TZVPD/VACUUM Single Point" wB97X_V_def2_TZVPD_VACUUM_Force = "wB97X-V/def2-TZVPD/VACUUM Force" wB97X_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/VACUUM Transition State 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_Unknown = "wB97X-V/def2-TZVPD/VACUUM Unknown" wB97X_V_def2_TZVPD_PCM_Single_Point = "wB97X-V/def2-TZVPD/PCM Single Point" wB97X_V_def2_TZVPD_PCM_Force = "wB97X-V/def2-TZVPD/PCM Force" wB97X_V_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/PCM Transition State 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_Unknown = "wB97X-V/def2-TZVPD/PCM Unknown" wB97X_V_def2_TZVPD_SMD_Single_Point = "wB97X-V/def2-TZVPD/SMD Single Point" wB97X_V_def2_TZVPD_SMD_Force = "wB97X-V/def2-TZVPD/SMD Force" wB97X_V_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPD/SMD Transition State 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_Unknown = "wB97X-V/def2-TZVPD/SMD Unknown" wB97X_V_def2_TZVPP_VACUUM_Single_Point = "wB97X-V/def2-TZVPP/VACUUM Single Point" wB97X_V_def2_TZVPP_VACUUM_Force = "wB97X-V/def2-TZVPP/VACUUM Force" wB97X_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/VACUUM Transition State 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_Unknown = "wB97X-V/def2-TZVPP/VACUUM Unknown" wB97X_V_def2_TZVPP_PCM_Single_Point = "wB97X-V/def2-TZVPP/PCM Single Point" wB97X_V_def2_TZVPP_PCM_Force = "wB97X-V/def2-TZVPP/PCM Force" wB97X_V_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/PCM Transition State 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_Unknown = "wB97X-V/def2-TZVPP/PCM Unknown" wB97X_V_def2_TZVPP_SMD_Single_Point = "wB97X-V/def2-TZVPP/SMD Single Point" wB97X_V_def2_TZVPP_SMD_Force = "wB97X-V/def2-TZVPP/SMD Force" wB97X_V_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPP/SMD Transition State 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_Unknown = "wB97X-V/def2-TZVPP/SMD Unknown" wB97X_V_def2_TZVPPD_VACUUM_Single_Point = "wB97X-V/def2-TZVPPD/VACUUM Single Point" wB97X_V_def2_TZVPPD_VACUUM_Force = "wB97X-V/def2-TZVPPD/VACUUM Force" wB97X_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/VACUUM Transition State 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_Unknown = "wB97X-V/def2-TZVPPD/VACUUM Unknown" wB97X_V_def2_TZVPPD_PCM_Single_Point = "wB97X-V/def2-TZVPPD/PCM Single Point" wB97X_V_def2_TZVPPD_PCM_Force = "wB97X-V/def2-TZVPPD/PCM Force" wB97X_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/PCM Transition State 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_Unknown = "wB97X-V/def2-TZVPPD/PCM Unknown" wB97X_V_def2_TZVPPD_SMD_Single_Point = "wB97X-V/def2-TZVPPD/SMD Single Point" wB97X_V_def2_TZVPPD_SMD_Force = "wB97X-V/def2-TZVPPD/SMD Force" wB97X_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-TZVPPD/SMD Transition State 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_Unknown = "wB97X-V/def2-TZVPPD/SMD Unknown" wB97X_V_def2_QZVPD_VACUUM_Single_Point = "wB97X-V/def2-QZVPD/VACUUM Single Point" wB97X_V_def2_QZVPD_VACUUM_Force = "wB97X-V/def2-QZVPD/VACUUM Force" wB97X_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/VACUUM Transition State 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_Unknown = "wB97X-V/def2-QZVPD/VACUUM Unknown" wB97X_V_def2_QZVPD_PCM_Single_Point = "wB97X-V/def2-QZVPD/PCM Single Point" wB97X_V_def2_QZVPD_PCM_Force = "wB97X-V/def2-QZVPD/PCM Force" wB97X_V_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/PCM Transition State 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_Unknown = "wB97X-V/def2-QZVPD/PCM Unknown" wB97X_V_def2_QZVPD_SMD_Single_Point = "wB97X-V/def2-QZVPD/SMD Single Point" wB97X_V_def2_QZVPD_SMD_Force = "wB97X-V/def2-QZVPD/SMD Force" wB97X_V_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPD/SMD Transition State 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_Unknown = "wB97X-V/def2-QZVPD/SMD Unknown" wB97X_V_def2_QZVPPD_VACUUM_Single_Point = "wB97X-V/def2-QZVPPD/VACUUM Single Point" wB97X_V_def2_QZVPPD_VACUUM_Force = "wB97X-V/def2-QZVPPD/VACUUM Force" wB97X_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/VACUUM Transition State 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_Unknown = "wB97X-V/def2-QZVPPD/VACUUM Unknown" wB97X_V_def2_QZVPPD_PCM_Single_Point = "wB97X-V/def2-QZVPPD/PCM Single Point" wB97X_V_def2_QZVPPD_PCM_Force = "wB97X-V/def2-QZVPPD/PCM Force" wB97X_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/PCM Transition State 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_Unknown = "wB97X-V/def2-QZVPPD/PCM Unknown" wB97X_V_def2_QZVPPD_SMD_Single_Point = "wB97X-V/def2-QZVPPD/SMD Single Point" wB97X_V_def2_QZVPPD_SMD_Force = "wB97X-V/def2-QZVPPD/SMD Force" wB97X_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97X-V/def2-QZVPPD/SMD Transition State 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_Unknown = "wB97X-V/def2-QZVPPD/SMD Unknown" wB97M_V_6_31g_d_VACUUM_Single_Point = "wB97M-V/6-31g*/VACUUM Single Point" wB97M_V_6_31g_d_VACUUM_Force = "wB97M-V/6-31g*/VACUUM Force" wB97M_V_6_31g_d_VACUUM_Geometry_Optimization = ( "wB97M-V/6-31g*/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/VACUUM Transition State 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_Unknown = "wB97M-V/6-31g*/VACUUM Unknown" wB97M_V_6_31g_d_PCM_Single_Point = "wB97M-V/6-31g*/PCM Single Point" wB97M_V_6_31g_d_PCM_Force = "wB97M-V/6-31g*/PCM Force" wB97M_V_6_31g_d_PCM_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/PCM Transition State 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_Unknown = "wB97M-V/6-31g*/PCM Unknown" wB97M_V_6_31g_d_SMD_Single_Point = "wB97M-V/6-31g*/SMD Single Point" wB97M_V_6_31g_d_SMD_Force = "wB97M-V/6-31g*/SMD Force" wB97M_V_6_31g_d_SMD_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/6-31g*/SMD Transition State 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_Unknown = "wB97M-V/6-31g*/SMD Unknown" wB97M_V_def2_SVPD_VACUUM_Single_Point = "wB97M-V/def2-SVPD/VACUUM Single Point" wB97M_V_def2_SVPD_VACUUM_Force = "wB97M-V/def2-SVPD/VACUUM Force" wB97M_V_def2_SVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-SVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/VACUUM Transition State 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_Unknown = "wB97M-V/def2-SVPD/VACUUM Unknown" wB97M_V_def2_SVPD_PCM_Single_Point = "wB97M-V/def2-SVPD/PCM Single Point" wB97M_V_def2_SVPD_PCM_Force = "wB97M-V/def2-SVPD/PCM Force" wB97M_V_def2_SVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-SVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/PCM Transition State 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_Unknown = "wB97M-V/def2-SVPD/PCM Unknown" wB97M_V_def2_SVPD_SMD_Single_Point = "wB97M-V/def2-SVPD/SMD Single Point" wB97M_V_def2_SVPD_SMD_Force = "wB97M-V/def2-SVPD/SMD Force" wB97M_V_def2_SVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-SVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-SVPD/SMD Transition State 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_Unknown = "wB97M-V/def2-SVPD/SMD Unknown" wB97M_V_def2_TZVP_VACUUM_Single_Point = "wB97M-V/def2-TZVP/VACUUM Single Point" wB97M_V_def2_TZVP_VACUUM_Force = "wB97M-V/def2-TZVP/VACUUM Force" wB97M_V_def2_TZVP_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/VACUUM Transition State 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_Unknown = "wB97M-V/def2-TZVP/VACUUM Unknown" wB97M_V_def2_TZVP_PCM_Single_Point = "wB97M-V/def2-TZVP/PCM Single Point" wB97M_V_def2_TZVP_PCM_Force = "wB97M-V/def2-TZVP/PCM Force" wB97M_V_def2_TZVP_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/PCM Transition State 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_Unknown = "wB97M-V/def2-TZVP/PCM Unknown" wB97M_V_def2_TZVP_SMD_Single_Point = "wB97M-V/def2-TZVP/SMD Single Point" wB97M_V_def2_TZVP_SMD_Force = "wB97M-V/def2-TZVP/SMD Force" wB97M_V_def2_TZVP_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVP/SMD Transition State 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_Unknown = "wB97M-V/def2-TZVP/SMD Unknown" wB97M_V_def2_TZVPD_VACUUM_Single_Point = "wB97M-V/def2-TZVPD/VACUUM Single Point" wB97M_V_def2_TZVPD_VACUUM_Force = "wB97M-V/def2-TZVPD/VACUUM Force" wB97M_V_def2_TZVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/VACUUM Transition State 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_Unknown = "wB97M-V/def2-TZVPD/VACUUM Unknown" wB97M_V_def2_TZVPD_PCM_Single_Point = "wB97M-V/def2-TZVPD/PCM Single Point" wB97M_V_def2_TZVPD_PCM_Force = "wB97M-V/def2-TZVPD/PCM Force" wB97M_V_def2_TZVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/PCM Transition State 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_Unknown = "wB97M-V/def2-TZVPD/PCM Unknown" wB97M_V_def2_TZVPD_SMD_Single_Point = "wB97M-V/def2-TZVPD/SMD Single Point" wB97M_V_def2_TZVPD_SMD_Force = "wB97M-V/def2-TZVPD/SMD Force" wB97M_V_def2_TZVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPD/SMD Transition State 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_Unknown = "wB97M-V/def2-TZVPD/SMD Unknown" wB97M_V_def2_TZVPP_VACUUM_Single_Point = "wB97M-V/def2-TZVPP/VACUUM Single Point" wB97M_V_def2_TZVPP_VACUUM_Force = "wB97M-V/def2-TZVPP/VACUUM Force" wB97M_V_def2_TZVPP_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/VACUUM Transition State 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_Unknown = "wB97M-V/def2-TZVPP/VACUUM Unknown" wB97M_V_def2_TZVPP_PCM_Single_Point = "wB97M-V/def2-TZVPP/PCM Single Point" wB97M_V_def2_TZVPP_PCM_Force = "wB97M-V/def2-TZVPP/PCM Force" wB97M_V_def2_TZVPP_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/PCM Transition State 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_Unknown = "wB97M-V/def2-TZVPP/PCM Unknown" wB97M_V_def2_TZVPP_SMD_Single_Point = "wB97M-V/def2-TZVPP/SMD Single Point" wB97M_V_def2_TZVPP_SMD_Force = "wB97M-V/def2-TZVPP/SMD Force" wB97M_V_def2_TZVPP_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPP/SMD Transition State 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_Unknown = "wB97M-V/def2-TZVPP/SMD Unknown" wB97M_V_def2_TZVPPD_VACUUM_Single_Point = "wB97M-V/def2-TZVPPD/VACUUM Single Point" wB97M_V_def2_TZVPPD_VACUUM_Force = "wB97M-V/def2-TZVPPD/VACUUM Force" wB97M_V_def2_TZVPPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/VACUUM Transition State 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_Unknown = "wB97M-V/def2-TZVPPD/VACUUM Unknown" wB97M_V_def2_TZVPPD_PCM_Single_Point = "wB97M-V/def2-TZVPPD/PCM Single Point" wB97M_V_def2_TZVPPD_PCM_Force = "wB97M-V/def2-TZVPPD/PCM Force" wB97M_V_def2_TZVPPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/PCM Transition State 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_Unknown = "wB97M-V/def2-TZVPPD/PCM Unknown" wB97M_V_def2_TZVPPD_SMD_Single_Point = "wB97M-V/def2-TZVPPD/SMD Single Point" wB97M_V_def2_TZVPPD_SMD_Force = "wB97M-V/def2-TZVPPD/SMD Force" wB97M_V_def2_TZVPPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-TZVPPD/SMD Transition State 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_Unknown = "wB97M-V/def2-TZVPPD/SMD Unknown" wB97M_V_def2_QZVPD_VACUUM_Single_Point = "wB97M-V/def2-QZVPD/VACUUM Single Point" wB97M_V_def2_QZVPD_VACUUM_Force = "wB97M-V/def2-QZVPD/VACUUM Force" wB97M_V_def2_QZVPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/VACUUM Transition State 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_Unknown = "wB97M-V/def2-QZVPD/VACUUM Unknown" wB97M_V_def2_QZVPD_PCM_Single_Point = "wB97M-V/def2-QZVPD/PCM Single Point" wB97M_V_def2_QZVPD_PCM_Force = "wB97M-V/def2-QZVPD/PCM Force" wB97M_V_def2_QZVPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/PCM Transition State 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_Unknown = "wB97M-V/def2-QZVPD/PCM Unknown" wB97M_V_def2_QZVPD_SMD_Single_Point = "wB97M-V/def2-QZVPD/SMD Single Point" wB97M_V_def2_QZVPD_SMD_Force = "wB97M-V/def2-QZVPD/SMD Force" wB97M_V_def2_QZVPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPD/SMD Transition State 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_Unknown = "wB97M-V/def2-QZVPD/SMD Unknown" wB97M_V_def2_QZVPPD_VACUUM_Single_Point = "wB97M-V/def2-QZVPPD/VACUUM Single Point" wB97M_V_def2_QZVPPD_VACUUM_Force = "wB97M-V/def2-QZVPPD/VACUUM Force" wB97M_V_def2_QZVPPD_VACUUM_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/VACUUM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/VACUUM Transition State 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_Unknown = "wB97M-V/def2-QZVPPD/VACUUM Unknown" wB97M_V_def2_QZVPPD_PCM_Single_Point = "wB97M-V/def2-QZVPPD/PCM Single Point" wB97M_V_def2_QZVPPD_PCM_Force = "wB97M-V/def2-QZVPPD/PCM Force" wB97M_V_def2_QZVPPD_PCM_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/PCM Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/PCM Transition State 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_Unknown = "wB97M-V/def2-QZVPPD/PCM Unknown" wB97M_V_def2_QZVPPD_SMD_Single_Point = "wB97M-V/def2-QZVPPD/SMD Single Point" wB97M_V_def2_QZVPPD_SMD_Force = "wB97M-V/def2-QZVPPD/SMD Force" wB97M_V_def2_QZVPPD_SMD_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/SMD Geometry Optimization" ) 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_Transition_State_Geometry_Optimization = ( "wB97M-V/def2-QZVPPD/SMD Transition State 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_Unknown = "wB97M-V/def2-QZVPPD/SMD Unknown" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/generate.py0000644000175100001770000000353414551165444022714 0ustar00runnerdocker""" Module to define various calculation types as Enums for Q-Chem""" from itertools import product from pathlib import Path from emmet.core.utils import get_enum_source from emmet.core.qchem.calc_types.calc_types import ( TASK_TYPES, FUNCTIONALS, BASIS_SETS, SOLVENT_MODELS, ) __author__ = "Evan Spotte-Smith " _LOTS = list() for funct in FUNCTIONALS: for basis in BASIS_SETS: for solv_model in SOLVENT_MODELS: _LOTS.append(f"{funct}/{basis}/{solv_model}") lot_enum = get_enum_source( "LevelOfTheory", "Levels of theory for calculations in Q-Chem", dict( { "_".join(lot.split()) .replace("+", "_") .replace("-", "_") .replace("(", "_") .replace(")", "_") .replace("/", "_") .replace("*", "_d"): lot for lot in _LOTS } ), ) task_type_enum = get_enum_source( "TaskType", "Calculation task types for Q-Chem", {"_".join(tt.split()).replace("-", "_"): tt for tt in TASK_TYPES}, ) calc_type_enum = get_enum_source( "CalcType", "Calculation types (LOT + task type) for Q-Chem", { f"{'_'.join(lot.split()).replace('+','_').replace('-','_').replace('(', '_').replace(')', '_').replace('/', '_').replace('*', '_d')}_{'_'.join(tt.split()).replace('-', '_')}": f"{lot} {tt}" # noqa: E501 for lot, tt in product(_LOTS, TASK_TYPES) }, ) with open(Path(__file__).parent / "enums.py", "w") as f: f.write( """\"\"\" Autogenerated Enums for Q-Chem LevelOfTheory, TaskType, and CalcType Do not edit this by hand. Edit generate.py or types.py instead \"\"\" from emmet.core.utils import ValueEnum """ ) f.write(lot_enum) f.write("\n\n") f.write(task_type_enum) f.write("\n\n") f.write(calc_type_enum) f.write("\n") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calc_types/utils.py0000644000175100001770000001613014551165444022256 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 " 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/calculation.py0000644000175100001770000005451114551165444021273 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 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("enthalpy", None), entropy=qcoutput.data.get("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: LevelOfTheory = 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: CalcType = 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], 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), solvation_lot_info=lot_solvent_string(input_doc), task_type=task_type(input_doc), calc_type=calc_type(input_doc), ) 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(?:\..+)?)\.gz$") for file in path.iterdir(): if file.is_file(): in_match = in_file_pattern.match(file.name) if in_match: in_task_name = in_match.group("in_task_name").replace("mol.qin.", "") if in_task_name == "orig": task_files[in_task_name] = {"orig_input_file": file} elif in_task_name == "mol.qin": task_files["standard"] = { "qcinput_file": file, "qcoutput_file": Path("mol.qout.gz"), } else: try: task_files[in_task_name] = { "qcinput_file": file, "qcoutput_file": Path("mol.qout." + in_task_name + ".gz"), } except FileNotFoundError: task_files[in_task_name] = { "qcinput_file": file, "qcoutput_file": "No qout files exist for this in file", } return task_files 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() 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 = 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, 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: parameters: CalculationInput parameters """ 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/molecule.py0000644000175100001770000004540014551165444020577 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() inchikey = ad.pybel_mol.write("inchikey").strip() 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() inchikey = ad.pybel_mol.write("inchikey").strip() 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=1705306916.0 emmet-core-0.76.2/emmet/core/qchem/task.py0000644000175100001770000001611314551165444017733 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=1705306916.0 emmet-core-0.76.2/emmet/core/robocrys.py0000644000175100001770000000551114551165444017536 0ustar00runnerdockerfrom typing import Union, Optional from pydantic import BaseModel, Field from pymatgen.core.structure import Structure from emmet.core.material_property import PropertyDoc from emmet.core.mpid import MPID 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, **kwargs): # type: ignore[override] try: from robocrys import StructureCondenser, StructureDescriber from robocrys import __version__ as __robocrys_version__ except ImportError: raise ImportError( "robocrys needs to be installed to generate RobocrystallographerDoc" ) condensed_structure = StructureCondenser().condense_structure(structure) description = StructureDescriber( describe_symmetry_labels=False, fmt="unicode", return_parts=False ).describe(condensed_structure=condensed_structure) 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=1705306916.0 emmet-core-0.76.2/emmet/core/settings.py0000644000175100001770000001714614551165444017543 0ustar00runnerdocker# mypy: ignore-errors """ Settings for defaults in the core definitions of Materials Project Documents """ import json from pathlib import Path from typing import Dict, List, Type, TypeVar, Union 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_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_HASHES: bool = Field( True, description="Whether to validate POTCAR hash 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=1705306916.0 emmet-core-0.76.2/emmet/core/similarity.py0000644000175100001770000000223114551165444020056 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=1705306916.0 emmet-core-0.76.2/emmet/core/spectrum.py0000644000175100001770000000203314551165444017532 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=1705306916.0 emmet-core-0.76.2/emmet/core/structure.py0000644000175100001770000002311714551165444017736 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=1705306916.0 emmet-core-0.76.2/emmet/core/structure_group.py0000644000175100001770000002551714551165444021160 0ustar00runnerdockerimport logging import operator from datetime import datetime from itertools import groupby from typing import Iterable, List, Optional, Union from monty.json import MontyDecoder 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 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 last_updated_dict_ok(cls, v): return MontyDecoder().process_decoded(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_num) 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]]]: """ 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_num(task_id) -> Union[int, str]: if isinstance(task_id, int): return task_id if isinstance(task_id, str): return int(task_id.split("-")[-1]) else: raise ValueError("TaskID needs to be either a number or of the form xxx-#####") 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=1705306916.0 emmet-core-0.76.2/emmet/core/stubs.py0000644000175100001770000000172414551165444017036 0ustar00runnerdocker# 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=1705306916.0 emmet-core-0.76.2/emmet/core/substrates.py0000644000175100001770000000234514551165444020075 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=1705306916.0 emmet-core-0.76.2/emmet/core/summary.py0000644000175100001770000003701014551165444017370 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=1705306916.0 emmet-core-0.76.2/emmet/core/surface_properties.py0000644000175100001770000000514214551165444021600 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.", ) task_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=1705306916.0 emmet-core-0.76.2/emmet/core/symmetry.py0000644000175100001770000001201214551165444017557 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=1705306921.9032564 emmet-core-0.76.2/emmet/core/synthesis/0000755000175100001770000000000014551165452017350 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/synthesis/__init__.py0000644000175100001770000000062014551165444021460 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=1705306916.0 emmet-core-0.76.2/emmet/core/synthesis/core.py0000644000175100001770000000434414551165444020660 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=1705306916.0 emmet-core-0.76.2/emmet/core/synthesis/materials.py0000644000175100001770000000360314551165444021706 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=1705306916.0 emmet-core-0.76.2/emmet/core/synthesis/operations.py0000644000175100001770000000311414551165444022105 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=1705306916.0 emmet-core-0.76.2/emmet/core/synthesis/reaction.py0000644000175100001770000000160414551165444021530 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=1705306916.0 emmet-core-0.76.2/emmet/core/task.py0000644000175100001770000000215614551165444016640 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=1705306916.0 emmet-core-0.76.2/emmet/core/tasks.py0000644000175100001770000010346614551165444017031 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 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 from emmet.core.structure import StructureMetadata from emmet.core.vasp.calc_types import CalcType, TaskType from emmet.core.vasp.calculation import ( Calculation, PotcarSpec, RunStatistics, VaspObject, ) from emmet.core.vasp.task_valid import TaskState 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(BaseModel): incar: Optional[Union[Incar, Dict]] = Field( None, description="Pymatgen object representing the INCAR file.", ) poscar: Optional[Poscar] = Field( None, description="Pymatgen object representing the POSCAR file.", ) kpoints: Optional[Kpoints] = Field( None, description="Pymatgen object representing the KPOINTS 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): if isinstance(v, list): return list(v) 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: float = Field(..., 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(BaseModel): structure: Optional[Structure] = Field( None, title="Input Structure", description="Output Structure from the VASP calculation.", ) parameters: Optional[Dict] = Field( None, description="Parameters from vasprun for the last calculation in the series", ) pseudo_potentials: Optional[Potcar] = Field( None, description="Summary of the pseudo-potentials used in this calculation" ) potcar_spec: Optional[List[PotcarSpec]] = Field( None, description="Title and hash of POTCAR files used in the 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" ) 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_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") 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( structure=calc_doc.input.structure, parameters=calc_doc.input.parameters, pseudo_potentials=pps, potcar_spec=calc_doc.input.potcar_spec, is_hubbard=calc_doc.input.is_hubbard, hubbards=calc_doc.input.hubbards, xc_override=xc, is_lasph=calc_doc.input.parameters.get("LASPH", False), ) 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[CalcType, TaskType]] = Field( None, description="The type of calculation." ) 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-******.", ) 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[Dict[str, 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( None, description="Timestamp for the most recent calculation for this task document", ) # 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 v if isinstance(v, datetime) else monty_decoder.process_decoded(v) @model_validator(mode="after") def set_entry(self) -> datetime: if not self.entry and self.calcs_reversed: 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, **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. **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) 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[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 "potcar_spec": [dict(d) for d in calcs_reversed[0].input.potcar_spec], # 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(datetime.utcnow()), }, } return ComputedEntry.from_dict(entry_dict) @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.""" 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, ) -> 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=1705306916.0 emmet-core-0.76.2/emmet/core/thermo.py0000644000175100001770000002631014551165444017172 0ustar00runnerdocker""" Core definition of a Thermo Document """ from collections import defaultdict from typing import Dict, List, Optional, Union from datetime import datetime from emmet.core.base import EmmetMeta from emmet.core.utils import ValueEnum from pydantic import BaseModel, Field from pymatgen.analysis.phase_diagram import PhaseDiagram from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry from emmet.core.material_property import PropertyDoc from emmet.core.material import PropertyOrigin from emmet.core.mpid import MPID 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: ComputedStructureEntry): """ 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) 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), "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) else: d["decomposes_to"] = [ { "material_id": de.data["material_id"], "formula": de.composition.formula, "amount": amt, } for de, amt in decomp.items() ] try: decomp, energy = pd.get_decomp_and_phase_separation_energy( blessed_entry ) d["decomposition_enthalpy"] = energy d["decomposition_enthalpy_decomposes_to"] = [ { "material_id": de.data["material_id"], "formula": de.composition.formula, "amount": amt, } for de, amt in decomp.items() ] 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 ) ) 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=1705306916.0 emmet-core-0.76.2/emmet/core/utils.py0000644000175100001770000002562214551165444017041 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.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.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 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 """ 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)) def as_dict(self): """Create a serializable representation of the enum.""" return str(self.value) 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 def get_enum_source(enum_name, doc, items): header = f""" class {enum_name}(ValueEnum): \"\"\" {doc} \"\"\"\n """ items = [f' {const} = "{val}"' for const, val in items.items()] return header + "\n".join(items) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9032564 emmet-core-0.76.2/emmet/core/vasp/0000755000175100001770000000000014551165452016270 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/__init__.py0000644000175100001770000000000014551165444020370 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9032564 emmet-core-0.76.2/emmet/core/vasp/calc_types/0000755000175100001770000000000014551165452020416 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calc_types/__init__.py0000644000175100001770000000047114551165444022532 0ustar00runnerdocker"""Module defining vasp calculation types.""" try: import emmet.core.vasp.calc_types.enums except ImportError: import emmet.core.vasp.calc_types.generate 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=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calc_types/enums.py0000644000175100001770000013255214551165444022130 0ustar00runnerdocker""" Autogenerated Enums for VASP RunType, TaskType, and CalcType. Do not edit this by hand. Edit generate.py or run_types.yaml instead. """ from emmet.core.utils import ValueEnum class RunType(ValueEnum): """VASP calculation run types.""" AM05 = "AM05" GGA = "GGA" PBE = "PBE" PBESol = "PBESol" RevPBE_PADE = "RevPBE+PADE" optB86b = "optB86b" optB88 = "optB88" optPBE = "optPBE" revPBE = "revPBE" B3LYP = "B3LYP" HF = "HF" HSE03 = "HSE03" HSE06 = "HSE06" HFCus = "HFCus" PBE0 = "PBE0" M06L = "M06L" MBJL = "MBJL" MS0 = "MS0" MS1 = "MS1" MS2 = "MS2" RTPSS = "RTPSS" SCAN = "SCAN" R2SCAN = "R2SCAN" TPSS = "TPSS" R2SCAN_rVV10 = "R2SCAN-rVV10" SCAN_rVV10 = "SCAN-rVV10" optB86b_vdW = "optB86b-vdW" optB88_vdW = "optB88-vdW" optPBE_vdW = "optPBE-vdW" rev_vdW_DF2 = "rev-vdW-DF2" revPBE_vdW = "revPBE-vdW" vdW_DF2 = "vdW-DF2" AM05_U = "AM05+U" GGA_U = "GGA+U" PBE_U = "PBE+U" PBESol_U = "PBESol+U" RevPBE_PADE_U = "RevPBE+PADE+U" optB86b_U = "optB86b+U" optB88_U = "optB88+U" optPBE_U = "optPBE+U" revPBE_U = "revPBE+U" B3LYP_U = "B3LYP+U" HF_U = "HF+U" HSE03_U = "HSE03+U" HSE06_U = "HSE06+U" HFCus_U = "HFCus+U" PBE0_U = "PBE0+U" M06L_U = "M06L+U" MBJL_U = "MBJL+U" MS0_U = "MS0+U" MS1_U = "MS1+U" MS2_U = "MS2+U" RTPSS_U = "RTPSS+U" SCAN_U = "SCAN+U" R2SCAN_U = "R2SCAN+U" TPSS_U = "TPSS+U" R2SCAN_rVV10_U = "R2SCAN-rVV10+U" SCAN_rVV10_U = "SCAN-rVV10+U" optB86b_vdW_U = "optB86b-vdW+U" optB88_vdW_U = "optB88-vdW+U" optPBE_vdW_U = "optPBE-vdW+U" rev_vdW_DF2_U = "rev-vdW-DF2+U" revPBE_vdW_U = "revPBE-vdW+U" vdW_DF2_U = "vdW-DF2+U" LDA = "LDA" LDA_U = "LDA+U" @classmethod def _missing_(cls, value): for member in cls: if member.value.upper() == value.upper(): return member class TaskType(ValueEnum): """VASP calculation task types.""" NSCF_Line = "NSCF Line" NSCF_Uniform = "NSCF Uniform" Dielectric = "Dielectric" DFPT = "DFPT" DFPT_Dielectric = "DFPT Dielectric" NMR_Nuclear_Shielding = "NMR Nuclear Shielding" NMR_Electric_Field_Gradient = "NMR Electric Field Gradient" Static = "Static" Structure_Optimization = "Structure Optimization" Deformation = "Deformation" Optic = "Optic" Molecular_Dynamics = "Molecular Dynamics" Unrecognized = "Unrecognized" class CalcType(ValueEnum): """VASP calculation types.""" AM05_NSCF_Line = "AM05 NSCF Line" AM05_NSCF_Uniform = "AM05 NSCF Uniform" AM05_Dielectric = "AM05 Dielectric" AM05_DFPT = "AM05 DFPT" AM05_DFPT_Dielectric = "AM05 DFPT Dielectric" AM05_NMR_Nuclear_Shielding = "AM05 NMR Nuclear Shielding" AM05_NMR_Electric_Field_Gradient = "AM05 NMR Electric Field Gradient" AM05_Static = "AM05 Static" AM05_Structure_Optimization = "AM05 Structure Optimization" AM05_Deformation = "AM05 Deformation" AM05_Optic = "AM05 Optic" AM05_Molecular_Dynamics = "AM05 Molecular Dynamics" AM05_Unrecognized = "AM05 Unrecognized" GGA_NSCF_Line = "GGA NSCF Line" GGA_NSCF_Uniform = "GGA NSCF Uniform" GGA_Dielectric = "GGA Dielectric" GGA_DFPT = "GGA DFPT" GGA_DFPT_Dielectric = "GGA DFPT Dielectric" GGA_NMR_Nuclear_Shielding = "GGA NMR Nuclear Shielding" GGA_NMR_Electric_Field_Gradient = "GGA NMR Electric Field Gradient" GGA_Static = "GGA Static" GGA_Structure_Optimization = "GGA Structure Optimization" GGA_Deformation = "GGA Deformation" GGA_Optic = "GGA Optic" GGA_Molecular_Dynamics = "GGA Molecular Dynamics" GGA_Unrecognized = "GGA Unrecognized" PBE_NSCF_Line = "PBE NSCF Line" PBE_NSCF_Uniform = "PBE NSCF Uniform" PBE_Dielectric = "PBE Dielectric" PBE_DFPT = "PBE DFPT" PBE_DFPT_Dielectric = "PBE DFPT Dielectric" PBE_NMR_Nuclear_Shielding = "PBE NMR Nuclear Shielding" PBE_NMR_Electric_Field_Gradient = "PBE NMR Electric Field Gradient" PBE_Static = "PBE Static" PBE_Structure_Optimization = "PBE Structure Optimization" PBE_Deformation = "PBE Deformation" PBE_Optic = "PBE Optic" PBE_Molecular_Dynamics = "PBE Molecular Dynamics" PBE_Unrecognized = "PBE Unrecognized" PBESol_NSCF_Line = "PBESol NSCF Line" PBESol_NSCF_Uniform = "PBESol NSCF Uniform" PBESol_Dielectric = "PBESol Dielectric" PBESol_DFPT = "PBESol DFPT" PBESol_DFPT_Dielectric = "PBESol DFPT Dielectric" PBESol_NMR_Nuclear_Shielding = "PBESol NMR Nuclear Shielding" PBESol_NMR_Electric_Field_Gradient = "PBESol NMR Electric Field Gradient" PBESol_Static = "PBESol Static" PBESol_Structure_Optimization = "PBESol Structure Optimization" PBESol_Deformation = "PBESol Deformation" PBESol_Optic = "PBESol Optic" PBESol_Molecular_Dynamics = "PBESol Molecular Dynamics" PBESol_Unrecognized = "PBESol Unrecognized" RevPBE_PADE_NSCF_Line = "RevPBE+PADE NSCF Line" RevPBE_PADE_NSCF_Uniform = "RevPBE+PADE NSCF Uniform" RevPBE_PADE_Dielectric = "RevPBE+PADE Dielectric" RevPBE_PADE_DFPT = "RevPBE+PADE DFPT" RevPBE_PADE_DFPT_Dielectric = "RevPBE+PADE DFPT Dielectric" RevPBE_PADE_NMR_Nuclear_Shielding = "RevPBE+PADE NMR Nuclear Shielding" RevPBE_PADE_NMR_Electric_Field_Gradient = "RevPBE+PADE NMR Electric Field Gradient" RevPBE_PADE_Static = "RevPBE+PADE Static" RevPBE_PADE_Structure_Optimization = "RevPBE+PADE Structure Optimization" RevPBE_PADE_Deformation = "RevPBE+PADE Deformation" RevPBE_PADE_Optic = "RevPBE+PADE Optic" RevPBE_PADE_Molecular_Dynamics = "RevPBE+PADE Molecular Dynamics" RevPBE_PADE_Unrecognized = "RevPBE+PADE Unrecognized" optB86b_NSCF_Line = "optB86b NSCF Line" optB86b_NSCF_Uniform = "optB86b NSCF Uniform" optB86b_Dielectric = "optB86b Dielectric" optB86b_DFPT = "optB86b DFPT" optB86b_DFPT_Dielectric = "optB86b DFPT Dielectric" optB86b_NMR_Nuclear_Shielding = "optB86b NMR Nuclear Shielding" optB86b_NMR_Electric_Field_Gradient = "optB86b NMR Electric Field Gradient" optB86b_Static = "optB86b Static" optB86b_Structure_Optimization = "optB86b Structure Optimization" optB86b_Deformation = "optB86b Deformation" optB86b_Optic = "optB86b Optic" optB86b_Molecular_Dynamics = "optB86b Molecular Dynamics" optB86b_Unrecognized = "optB86b Unrecognized" optB88_NSCF_Line = "optB88 NSCF Line" optB88_NSCF_Uniform = "optB88 NSCF Uniform" optB88_Dielectric = "optB88 Dielectric" optB88_DFPT = "optB88 DFPT" optB88_DFPT_Dielectric = "optB88 DFPT Dielectric" optB88_NMR_Nuclear_Shielding = "optB88 NMR Nuclear Shielding" optB88_NMR_Electric_Field_Gradient = "optB88 NMR Electric Field Gradient" optB88_Static = "optB88 Static" optB88_Structure_Optimization = "optB88 Structure Optimization" optB88_Deformation = "optB88 Deformation" optB88_Optic = "optB88 Optic" optB88_Molecular_Dynamics = "optB88 Molecular Dynamics" optB88_Unrecognized = "optB88 Unrecognized" optPBE_NSCF_Line = "optPBE NSCF Line" optPBE_NSCF_Uniform = "optPBE NSCF Uniform" optPBE_Dielectric = "optPBE Dielectric" optPBE_DFPT = "optPBE DFPT" optPBE_DFPT_Dielectric = "optPBE DFPT Dielectric" optPBE_NMR_Nuclear_Shielding = "optPBE NMR Nuclear Shielding" optPBE_NMR_Electric_Field_Gradient = "optPBE NMR Electric Field Gradient" optPBE_Static = "optPBE Static" optPBE_Structure_Optimization = "optPBE Structure Optimization" optPBE_Deformation = "optPBE Deformation" optPBE_Optic = "optPBE Optic" optPBE_Molecular_Dynamics = "optPBE Molecular Dynamics" optPBE_Unrecognized = "optPBE Unrecognized" revPBE_NSCF_Line = "revPBE NSCF Line" revPBE_NSCF_Uniform = "revPBE NSCF Uniform" revPBE_Dielectric = "revPBE Dielectric" revPBE_DFPT = "revPBE DFPT" revPBE_DFPT_Dielectric = "revPBE DFPT Dielectric" revPBE_NMR_Nuclear_Shielding = "revPBE NMR Nuclear Shielding" revPBE_NMR_Electric_Field_Gradient = "revPBE NMR Electric Field Gradient" revPBE_Static = "revPBE Static" revPBE_Structure_Optimization = "revPBE Structure Optimization" revPBE_Deformation = "revPBE Deformation" revPBE_Optic = "revPBE Optic" revPBE_Molecular_Dynamics = "revPBE Molecular Dynamics" revPBE_Unrecognized = "revPBE Unrecognized" B3LYP_NSCF_Line = "B3LYP NSCF Line" B3LYP_NSCF_Uniform = "B3LYP NSCF Uniform" B3LYP_Dielectric = "B3LYP Dielectric" B3LYP_DFPT = "B3LYP DFPT" B3LYP_DFPT_Dielectric = "B3LYP DFPT Dielectric" B3LYP_NMR_Nuclear_Shielding = "B3LYP NMR Nuclear Shielding" B3LYP_NMR_Electric_Field_Gradient = "B3LYP NMR Electric Field Gradient" B3LYP_Static = "B3LYP Static" B3LYP_Structure_Optimization = "B3LYP Structure Optimization" B3LYP_Deformation = "B3LYP Deformation" B3LYP_Optic = "B3LYP Optic" B3LYP_Molecular_Dynamics = "B3LYP Molecular Dynamics" B3LYP_Unrecognized = "B3LYP Unrecognized" HF_NSCF_Line = "HF NSCF Line" HF_NSCF_Uniform = "HF NSCF Uniform" HF_Dielectric = "HF Dielectric" HF_DFPT = "HF DFPT" HF_DFPT_Dielectric = "HF DFPT Dielectric" HF_NMR_Nuclear_Shielding = "HF NMR Nuclear Shielding" HF_NMR_Electric_Field_Gradient = "HF NMR Electric Field Gradient" HF_Static = "HF Static" HF_Structure_Optimization = "HF Structure Optimization" HF_Deformation = "HF Deformation" HF_Optic = "HF Optic" HF_Molecular_Dynamics = "HF Molecular Dynamics" HF_Unrecognized = "HF Unrecognized" HSE03_NSCF_Line = "HSE03 NSCF Line" HSE03_NSCF_Uniform = "HSE03 NSCF Uniform" HSE03_Dielectric = "HSE03 Dielectric" HSE03_DFPT = "HSE03 DFPT" HSE03_DFPT_Dielectric = "HSE03 DFPT Dielectric" HSE03_NMR_Nuclear_Shielding = "HSE03 NMR Nuclear Shielding" HSE03_NMR_Electric_Field_Gradient = "HSE03 NMR Electric Field Gradient" HSE03_Static = "HSE03 Static" HSE03_Structure_Optimization = "HSE03 Structure Optimization" HSE03_Deformation = "HSE03 Deformation" HSE03_Optic = "HSE03 Optic" HSE03_Molecular_Dynamics = "HSE03 Molecular Dynamics" HSE03_Unrecognized = "HSE03 Unrecognized" HSE06_NSCF_Line = "HSE06 NSCF Line" HSE06_NSCF_Uniform = "HSE06 NSCF Uniform" HSE06_Dielectric = "HSE06 Dielectric" HSE06_DFPT = "HSE06 DFPT" HSE06_DFPT_Dielectric = "HSE06 DFPT Dielectric" HSE06_NMR_Nuclear_Shielding = "HSE06 NMR Nuclear Shielding" HSE06_NMR_Electric_Field_Gradient = "HSE06 NMR Electric Field Gradient" HSE06_Static = "HSE06 Static" HSE06_Structure_Optimization = "HSE06 Structure Optimization" HSE06_Deformation = "HSE06 Deformation" HSE06_Optic = "HSE06 Optic" HSE06_Molecular_Dynamics = "HSE06 Molecular Dynamics" HSE06_Unrecognized = "HSE06 Unrecognized" PBE0_NSCF_Line = "PBE0 NSCF Line" PBE0_NSCF_Uniform = "PBE0 NSCF Uniform" PBE0_Dielectric = "PBE0 Dielectric" PBE0_DFPT = "PBE0 DFPT" PBE0_DFPT_Dielectric = "PBE0 DFPT Dielectric" PBE0_NMR_Nuclear_Shielding = "PBE0 NMR Nuclear Shielding" PBE0_NMR_Electric_Field_Gradient = "PBE0 NMR Electric Field Gradient" PBE0_Static = "PBE0 Static" PBE0_Structure_Optimization = "PBE0 Structure Optimization" PBE0_Deformation = "PBE0 Deformation" PBE0_Optic = "PBE0 Optic" PBE0_Molecular_Dynamics = "PBE0 Molecular Dynamics" PBE0_Unrecognized = "PBE0 Unrecognized" M06L_NSCF_Line = "M06L NSCF Line" M06L_NSCF_Uniform = "M06L NSCF Uniform" M06L_Dielectric = "M06L Dielectric" M06L_DFPT = "M06L DFPT" M06L_DFPT_Dielectric = "M06L DFPT Dielectric" M06L_NMR_Nuclear_Shielding = "M06L NMR Nuclear Shielding" M06L_NMR_Electric_Field_Gradient = "M06L NMR Electric Field Gradient" M06L_Static = "M06L Static" M06L_Structure_Optimization = "M06L Structure Optimization" M06L_Deformation = "M06L Deformation" M06L_Optic = "M06L Optic" M06L_Molecular_Dynamics = "M06L Molecular Dynamics" M06L_Unrecognized = "M06L Unrecognized" MBJL_NSCF_Line = "MBJL NSCF Line" MBJL_NSCF_Uniform = "MBJL NSCF Uniform" MBJL_Dielectric = "MBJL Dielectric" MBJL_DFPT = "MBJL DFPT" MBJL_DFPT_Dielectric = "MBJL DFPT Dielectric" MBJL_NMR_Nuclear_Shielding = "MBJL NMR Nuclear Shielding" MBJL_NMR_Electric_Field_Gradient = "MBJL NMR Electric Field Gradient" MBJL_Static = "MBJL Static" MBJL_Structure_Optimization = "MBJL Structure Optimization" MBJL_Deformation = "MBJL Deformation" MBJL_Optic = "MBJL Optic" MBJL_Molecular_Dynamics = "MBJL Molecular Dynamics" MBJL_Unrecognized = "MBJL Unrecognized" MS0_NSCF_Line = "MS0 NSCF Line" MS0_NSCF_Uniform = "MS0 NSCF Uniform" MS0_Dielectric = "MS0 Dielectric" MS0_DFPT = "MS0 DFPT" MS0_DFPT_Dielectric = "MS0 DFPT Dielectric" MS0_NMR_Nuclear_Shielding = "MS0 NMR Nuclear Shielding" MS0_NMR_Electric_Field_Gradient = "MS0 NMR Electric Field Gradient" MS0_Static = "MS0 Static" MS0_Structure_Optimization = "MS0 Structure Optimization" MS0_Deformation = "MS0 Deformation" MS0_Optic = "MS0 Optic" MS0_Molecular_Dynamics = "MS0 Molecular Dynamics" MS0_Unrecognized = "MS0 Unrecognized" MS1_NSCF_Line = "MS1 NSCF Line" MS1_NSCF_Uniform = "MS1 NSCF Uniform" MS1_Dielectric = "MS1 Dielectric" MS1_DFPT = "MS1 DFPT" MS1_DFPT_Dielectric = "MS1 DFPT Dielectric" MS1_NMR_Nuclear_Shielding = "MS1 NMR Nuclear Shielding" MS1_NMR_Electric_Field_Gradient = "MS1 NMR Electric Field Gradient" MS1_Static = "MS1 Static" MS1_Structure_Optimization = "MS1 Structure Optimization" MS1_Deformation = "MS1 Deformation" MS1_Optic = "MS1 Optic" MS1_Molecular_Dynamics = "MS1 Molecular Dynamics" MS1_Unrecognized = "MS1 Unrecognized" MS2_NSCF_Line = "MS2 NSCF Line" MS2_NSCF_Uniform = "MS2 NSCF Uniform" MS2_Dielectric = "MS2 Dielectric" MS2_DFPT = "MS2 DFPT" MS2_DFPT_Dielectric = "MS2 DFPT Dielectric" MS2_NMR_Nuclear_Shielding = "MS2 NMR Nuclear Shielding" MS2_NMR_Electric_Field_Gradient = "MS2 NMR Electric Field Gradient" MS2_Static = "MS2 Static" MS2_Structure_Optimization = "MS2 Structure Optimization" MS2_Deformation = "MS2 Deformation" MS2_Optic = "MS2 Optic" MS2_Molecular_Dynamics = "MS2 Molecular Dynamics" MS2_Unrecognized = "MS2 Unrecognized" RTPSS_NSCF_Line = "RTPSS NSCF Line" RTPSS_NSCF_Uniform = "RTPSS NSCF Uniform" RTPSS_Dielectric = "RTPSS Dielectric" RTPSS_DFPT = "RTPSS DFPT" RTPSS_DFPT_Dielectric = "RTPSS DFPT Dielectric" RTPSS_NMR_Nuclear_Shielding = "RTPSS NMR Nuclear Shielding" RTPSS_NMR_Electric_Field_Gradient = "RTPSS NMR Electric Field Gradient" RTPSS_Static = "RTPSS Static" RTPSS_Structure_Optimization = "RTPSS Structure Optimization" RTPSS_Deformation = "RTPSS Deformation" RTPSS_Optic = "RTPSS Optic" RTPSS_Molecular_Dynamics = "RTPSS Molecular Dynamics" RTPSS_Unrecognized = "RTPSS Unrecognized" SCAN_NSCF_Line = "SCAN NSCF Line" SCAN_NSCF_Uniform = "SCAN NSCF Uniform" SCAN_Dielectric = "SCAN Dielectric" SCAN_DFPT = "SCAN DFPT" SCAN_DFPT_Dielectric = "SCAN DFPT Dielectric" SCAN_NMR_Nuclear_Shielding = "SCAN NMR Nuclear Shielding" SCAN_NMR_Electric_Field_Gradient = "SCAN NMR Electric Field Gradient" SCAN_Static = "SCAN Static" SCAN_Structure_Optimization = "SCAN Structure Optimization" SCAN_Deformation = "SCAN Deformation" SCAN_Optic = "SCAN Optic" SCAN_Molecular_Dynamics = "SCAN Molecular Dynamics" SCAN_Unrecognized = "SCAN Unrecognized" R2SCAN_NSCF_Line = "R2SCAN NSCF Line" R2SCAN_NSCF_Uniform = "R2SCAN NSCF Uniform" R2SCAN_Dielectric = "R2SCAN Dielectric" R2SCAN_DFPT = "R2SCAN DFPT" R2SCAN_DFPT_Dielectric = "R2SCAN DFPT Dielectric" R2SCAN_NMR_Nuclear_Shielding = "R2SCAN NMR Nuclear Shielding" R2SCAN_NMR_Electric_Field_Gradient = "R2SCAN NMR Electric Field Gradient" R2SCAN_Static = "R2SCAN Static" R2SCAN_Structure_Optimization = "R2SCAN Structure Optimization" R2SCAN_Deformation = "R2SCAN Deformation" R2SCAN_Optic = "R2SCAN Optic" R2SCAN_Molecular_Dynamics = "R2SCAN Molecular Dynamics" R2SCAN_Unrecognized = "R2SCAN Unrecognized" TPSS_NSCF_Line = "TPSS NSCF Line" TPSS_NSCF_Uniform = "TPSS NSCF Uniform" TPSS_Dielectric = "TPSS Dielectric" TPSS_DFPT = "TPSS DFPT" TPSS_DFPT_Dielectric = "TPSS DFPT Dielectric" TPSS_NMR_Nuclear_Shielding = "TPSS NMR Nuclear Shielding" TPSS_NMR_Electric_Field_Gradient = "TPSS NMR Electric Field Gradient" TPSS_Static = "TPSS Static" TPSS_Structure_Optimization = "TPSS Structure Optimization" TPSS_Deformation = "TPSS Deformation" TPSS_Optic = "TPSS Optic" TPSS_Molecular_Dynamics = "TPSS Molecular Dynamics" TPSS_Unrecognized = "TPSS Unrecognized" R2SCAN_rVV10_NSCF_Line = "R2SCAN-rVV10 NSCF Line" R2SCAN_rVV10_NSCF_Uniform = "R2SCAN-rVV10 NSCF Uniform" R2SCAN_rVV10_Dielectric = "R2SCAN-rVV10 Dielectric" R2SCAN_rVV10_DFPT = "R2SCAN-rVV10 DFPT" R2SCAN_rVV10_DFPT_Dielectric = "R2SCAN-rVV10 DFPT Dielectric" R2SCAN_rVV10_NMR_Nuclear_Shielding = "R2SCAN-rVV10 NMR Nuclear Shielding" R2SCAN_rVV10_NMR_Electric_Field_Gradient = ( "R2SCAN-rVV10 NMR Electric Field Gradient" ) R2SCAN_rVV10_Static = "R2SCAN-rVV10 Static" R2SCAN_rVV10_Structure_Optimization = "R2SCAN-rVV10 Structure Optimization" R2SCAN_rVV10_Deformation = "R2SCAN-rVV10 Deformation" R2SCAN_rVV10_Optic = "R2SCAN-rVV10 Optic" R2SCAN_rVV10_Molecular_Dynamics = "R2SCAN-rVV10 Molecular Dynamics" R2SCAN_rVV10_Unrecognized = "R2SCAN-rVV10 Unrecognized" SCAN_rVV10_NSCF_Line = "SCAN-rVV10 NSCF Line" SCAN_rVV10_NSCF_Uniform = "SCAN-rVV10 NSCF Uniform" SCAN_rVV10_Dielectric = "SCAN-rVV10 Dielectric" SCAN_rVV10_DFPT = "SCAN-rVV10 DFPT" SCAN_rVV10_DFPT_Dielectric = "SCAN-rVV10 DFPT Dielectric" SCAN_rVV10_NMR_Nuclear_Shielding = "SCAN-rVV10 NMR Nuclear Shielding" SCAN_rVV10_NMR_Electric_Field_Gradient = "SCAN-rVV10 NMR Electric Field Gradient" SCAN_rVV10_Static = "SCAN-rVV10 Static" SCAN_rVV10_Structure_Optimization = "SCAN-rVV10 Structure Optimization" SCAN_rVV10_Deformation = "SCAN-rVV10 Deformation" SCAN_rVV10_Optic = "SCAN-rVV10 Optic" SCAN_rVV10_Molecular_Dynamics = "SCAN-rVV10 Molecular Dynamics" SCAN_rVV10_Unrecognized = "SCAN-rVV10 Unrecognized" optB86b_vdW_NSCF_Line = "optB86b-vdW NSCF Line" optB86b_vdW_NSCF_Uniform = "optB86b-vdW NSCF Uniform" optB86b_vdW_Dielectric = "optB86b-vdW Dielectric" optB86b_vdW_DFPT = "optB86b-vdW DFPT" optB86b_vdW_DFPT_Dielectric = "optB86b-vdW DFPT Dielectric" optB86b_vdW_NMR_Nuclear_Shielding = "optB86b-vdW NMR Nuclear Shielding" optB86b_vdW_NMR_Electric_Field_Gradient = "optB86b-vdW NMR Electric Field Gradient" optB86b_vdW_Static = "optB86b-vdW Static" optB86b_vdW_Structure_Optimization = "optB86b-vdW Structure Optimization" optB86b_vdW_Deformation = "optB86b-vdW Deformation" optB86b_vdW_Optic = "optB86b-vdW Optic" optB86b_vdW_Molecular_Dynamics = "optB86b-vdW Molecular Dynamics" optB86b_vdW_Unrecognized = "optB86b-vdW Unrecognized" optB88_vdW_NSCF_Line = "optB88-vdW NSCF Line" optB88_vdW_NSCF_Uniform = "optB88-vdW NSCF Uniform" optB88_vdW_Dielectric = "optB88-vdW Dielectric" optB88_vdW_DFPT = "optB88-vdW DFPT" optB88_vdW_DFPT_Dielectric = "optB88-vdW DFPT Dielectric" optB88_vdW_NMR_Nuclear_Shielding = "optB88-vdW NMR Nuclear Shielding" optB88_vdW_NMR_Electric_Field_Gradient = "optB88-vdW NMR Electric Field Gradient" optB88_vdW_Static = "optB88-vdW Static" optB88_vdW_Structure_Optimization = "optB88-vdW Structure Optimization" optB88_vdW_Deformation = "optB88-vdW Deformation" optB88_vdW_Optic = "optB88-vdW Optic" optB88_vdW_Molecular_Dynamics = "optB88-vdW Molecular Dynamics" optB88_vdW_Unrecognized = "optB88-vdW Unrecognized" optPBE_vdW_NSCF_Line = "optPBE-vdW NSCF Line" optPBE_vdW_NSCF_Uniform = "optPBE-vdW NSCF Uniform" optPBE_vdW_Dielectric = "optPBE-vdW Dielectric" optPBE_vdW_DFPT = "optPBE-vdW DFPT" optPBE_vdW_DFPT_Dielectric = "optPBE-vdW DFPT Dielectric" optPBE_vdW_NMR_Nuclear_Shielding = "optPBE-vdW NMR Nuclear Shielding" optPBE_vdW_NMR_Electric_Field_Gradient = "optPBE-vdW NMR Electric Field Gradient" optPBE_vdW_Static = "optPBE-vdW Static" optPBE_vdW_Structure_Optimization = "optPBE-vdW Structure Optimization" optPBE_vdW_Deformation = "optPBE-vdW Deformation" optPBE_vdW_Optic = "optPBE-vdW Optic" optPBE_vdW_Molecular_Dynamics = "optPBE-vdW Molecular Dynamics" optPBE_vdW_Unrecognized = "optPBE-vdW Unrecognized" rev_vdW_DF2_NSCF_Line = "rev-vdW-DF2 NSCF Line" rev_vdW_DF2_NSCF_Uniform = "rev-vdW-DF2 NSCF Uniform" rev_vdW_DF2_Dielectric = "rev-vdW-DF2 Dielectric" rev_vdW_DF2_DFPT = "rev-vdW-DF2 DFPT" rev_vdW_DF2_DFPT_Dielectric = "rev-vdW-DF2 DFPT Dielectric" rev_vdW_DF2_NMR_Nuclear_Shielding = "rev-vdW-DF2 NMR Nuclear Shielding" rev_vdW_DF2_NMR_Electric_Field_Gradient = "rev-vdW-DF2 NMR Electric Field Gradient" rev_vdW_DF2_Static = "rev-vdW-DF2 Static" rev_vdW_DF2_Structure_Optimization = "rev-vdW-DF2 Structure Optimization" rev_vdW_DF2_Deformation = "rev-vdW-DF2 Deformation" rev_vdW_DF2_Optic = "rev-vdW-DF2 Optic" rev_vdW_DF2_Molecular_Dynamics = "rev-vdW-DF2 Molecular Dynamics" rev_vdW_DF2_Unrecognized = "rev-vdW-DF2 Unrecognized" revPBE_vdW_NSCF_Line = "revPBE-vdW NSCF Line" revPBE_vdW_NSCF_Uniform = "revPBE-vdW NSCF Uniform" revPBE_vdW_Dielectric = "revPBE-vdW Dielectric" revPBE_vdW_DFPT = "revPBE-vdW DFPT" revPBE_vdW_DFPT_Dielectric = "revPBE-vdW DFPT Dielectric" revPBE_vdW_NMR_Nuclear_Shielding = "revPBE-vdW NMR Nuclear Shielding" revPBE_vdW_NMR_Electric_Field_Gradient = "revPBE-vdW NMR Electric Field Gradient" revPBE_vdW_Static = "revPBE-vdW Static" revPBE_vdW_Structure_Optimization = "revPBE-vdW Structure Optimization" revPBE_vdW_Deformation = "revPBE-vdW Deformation" revPBE_vdW_Optic = "revPBE-vdW Optic" revPBE_vdW_Molecular_Dynamics = "revPBE-vdW Molecular Dynamics" revPBE_vdW_Unrecognized = "revPBE-vdW Unrecognized" vdW_DF2_NSCF_Line = "vdW-DF2 NSCF Line" vdW_DF2_NSCF_Uniform = "vdW-DF2 NSCF Uniform" vdW_DF2_Dielectric = "vdW-DF2 Dielectric" vdW_DF2_DFPT = "vdW-DF2 DFPT" vdW_DF2_DFPT_Dielectric = "vdW-DF2 DFPT Dielectric" vdW_DF2_NMR_Nuclear_Shielding = "vdW-DF2 NMR Nuclear Shielding" vdW_DF2_NMR_Electric_Field_Gradient = "vdW-DF2 NMR Electric Field Gradient" vdW_DF2_Static = "vdW-DF2 Static" vdW_DF2_Structure_Optimization = "vdW-DF2 Structure Optimization" vdW_DF2_Deformation = "vdW-DF2 Deformation" vdW_DF2_Optic = "vdW-DF2 Optic" vdW_DF2_Molecular_Dynamics = "vdW-DF2 Molecular Dynamics" vdW_DF2_Unrecognized = "vdW-DF2 Unrecognized" AM05_U_NSCF_Line = "AM05+U NSCF Line" AM05_U_NSCF_Uniform = "AM05+U NSCF Uniform" AM05_U_Dielectric = "AM05+U Dielectric" AM05_U_DFPT = "AM05+U DFPT" AM05_U_DFPT_Dielectric = "AM05+U DFPT Dielectric" AM05_U_NMR_Nuclear_Shielding = "AM05+U NMR Nuclear Shielding" AM05_U_NMR_Electric_Field_Gradient = "AM05+U NMR Electric Field Gradient" AM05_U_Static = "AM05+U Static" AM05_U_Structure_Optimization = "AM05+U Structure Optimization" AM05_U_Deformation = "AM05+U Deformation" AM05_U_Optic = "AM05+U Optic" AM05_U_Molecular_Dynamics = "AM05+U Molecular Dynamics" AM05_U_Unrecognized = "AM05+U Unrecognized" GGA_U_NSCF_Line = "GGA+U NSCF Line" GGA_U_NSCF_Uniform = "GGA+U NSCF Uniform" GGA_U_Dielectric = "GGA+U Dielectric" GGA_U_DFPT = "GGA+U DFPT" GGA_U_DFPT_Dielectric = "GGA+U DFPT Dielectric" GGA_U_NMR_Nuclear_Shielding = "GGA+U NMR Nuclear Shielding" GGA_U_NMR_Electric_Field_Gradient = "GGA+U NMR Electric Field Gradient" GGA_U_Static = "GGA+U Static" GGA_U_Structure_Optimization = "GGA+U Structure Optimization" GGA_U_Deformation = "GGA+U Deformation" GGA_U_Optic = "GGA+U Optic" GGA_U_Molecular_Dynamics = "GGA+U Molecular Dynamics" GGA_U_Unrecognized = "GGA+U Unrecognized" PBE_U_NSCF_Line = "PBE+U NSCF Line" PBE_U_NSCF_Uniform = "PBE+U NSCF Uniform" PBE_U_Dielectric = "PBE+U Dielectric" PBE_U_DFPT = "PBE+U DFPT" PBE_U_DFPT_Dielectric = "PBE+U DFPT Dielectric" PBE_U_NMR_Nuclear_Shielding = "PBE+U NMR Nuclear Shielding" PBE_U_NMR_Electric_Field_Gradient = "PBE+U NMR Electric Field Gradient" PBE_U_Static = "PBE+U Static" PBE_U_Structure_Optimization = "PBE+U Structure Optimization" PBE_U_Deformation = "PBE+U Deformation" PBE_U_Optic = "PBE+U Optic" PBE_U_Molecular_Dynamics = "PBE+U Molecular Dynamics" PBE_U_Unrecognized = "PBE+U Unrecognized" PBESol_U_NSCF_Line = "PBESol+U NSCF Line" PBESol_U_NSCF_Uniform = "PBESol+U NSCF Uniform" PBESol_U_Dielectric = "PBESol+U Dielectric" PBESol_U_DFPT = "PBESol+U DFPT" PBESol_U_DFPT_Dielectric = "PBESol+U DFPT Dielectric" PBESol_U_NMR_Nuclear_Shielding = "PBESol+U NMR Nuclear Shielding" PBESol_U_NMR_Electric_Field_Gradient = "PBESol+U NMR Electric Field Gradient" PBESol_U_Static = "PBESol+U Static" PBESol_U_Structure_Optimization = "PBESol+U Structure Optimization" PBESol_U_Deformation = "PBESol+U Deformation" PBESol_U_Optic = "PBESol+U Optic" PBESol_U_Molecular_Dynamics = "PBESol+U Molecular Dynamics" PBESol_U_Unrecognized = "PBESol+U Unrecognized" RevPBE_PADE_U_NSCF_Line = "RevPBE+PADE+U NSCF Line" RevPBE_PADE_U_NSCF_Uniform = "RevPBE+PADE+U NSCF Uniform" RevPBE_PADE_U_Dielectric = "RevPBE+PADE+U Dielectric" RevPBE_PADE_U_DFPT = "RevPBE+PADE+U DFPT" RevPBE_PADE_U_DFPT_Dielectric = "RevPBE+PADE+U DFPT Dielectric" RevPBE_PADE_U_NMR_Nuclear_Shielding = "RevPBE+PADE+U NMR Nuclear Shielding" RevPBE_PADE_U_NMR_Electric_Field_Gradient = ( "RevPBE+PADE+U NMR Electric Field Gradient" ) RevPBE_PADE_U_Static = "RevPBE+PADE+U Static" RevPBE_PADE_U_Structure_Optimization = "RevPBE+PADE+U Structure Optimization" RevPBE_PADE_U_Deformation = "RevPBE+PADE+U Deformation" RevPBE_PADE_U_Optic = "RevPBE+PADE+U Optic" RevPBE_PADE_U_Molecular_Dynamics = "RevPBE+PADE+U Molecular Dynamics" RevPBE_PADE_U_Unrecognized = "RevPBE+PADE+U Unrecognized" optB86b_U_NSCF_Line = "optB86b+U NSCF Line" optB86b_U_NSCF_Uniform = "optB86b+U NSCF Uniform" optB86b_U_Dielectric = "optB86b+U Dielectric" optB86b_U_DFPT = "optB86b+U DFPT" optB86b_U_DFPT_Dielectric = "optB86b+U DFPT Dielectric" optB86b_U_NMR_Nuclear_Shielding = "optB86b+U NMR Nuclear Shielding" optB86b_U_NMR_Electric_Field_Gradient = "optB86b+U NMR Electric Field Gradient" optB86b_U_Static = "optB86b+U Static" optB86b_U_Structure_Optimization = "optB86b+U Structure Optimization" optB86b_U_Deformation = "optB86b+U Deformation" optB86b_U_Optic = "optB86b+U Optic" optB86b_U_Molecular_Dynamics = "optB86b+U Molecular Dynamics" optB86b_U_Unrecognized = "optB86b+U Unrecognized" optB88_U_NSCF_Line = "optB88+U NSCF Line" optB88_U_NSCF_Uniform = "optB88+U NSCF Uniform" optB88_U_Dielectric = "optB88+U Dielectric" optB88_U_DFPT = "optB88+U DFPT" optB88_U_DFPT_Dielectric = "optB88+U DFPT Dielectric" optB88_U_NMR_Nuclear_Shielding = "optB88+U NMR Nuclear Shielding" optB88_U_NMR_Electric_Field_Gradient = "optB88+U NMR Electric Field Gradient" optB88_U_Static = "optB88+U Static" optB88_U_Structure_Optimization = "optB88+U Structure Optimization" optB88_U_Deformation = "optB88+U Deformation" optB88_U_Optic = "optB88+U Optic" optB88_U_Molecular_Dynamics = "optB88+U Molecular Dynamics" optB88_U_Unrecognized = "optB88+U Unrecognized" optPBE_U_NSCF_Line = "optPBE+U NSCF Line" optPBE_U_NSCF_Uniform = "optPBE+U NSCF Uniform" optPBE_U_Dielectric = "optPBE+U Dielectric" optPBE_U_DFPT = "optPBE+U DFPT" optPBE_U_DFPT_Dielectric = "optPBE+U DFPT Dielectric" optPBE_U_NMR_Nuclear_Shielding = "optPBE+U NMR Nuclear Shielding" optPBE_U_NMR_Electric_Field_Gradient = "optPBE+U NMR Electric Field Gradient" optPBE_U_Static = "optPBE+U Static" optPBE_U_Structure_Optimization = "optPBE+U Structure Optimization" optPBE_U_Deformation = "optPBE+U Deformation" optPBE_U_Optic = "optPBE+U Optic" optPBE_U_Molecular_Dynamics = "optPBE+U Molecular Dynamics" optPBE_U_Unrecognized = "optPBE+U Unrecognized" revPBE_U_NSCF_Line = "revPBE+U NSCF Line" revPBE_U_NSCF_Uniform = "revPBE+U NSCF Uniform" revPBE_U_Dielectric = "revPBE+U Dielectric" revPBE_U_DFPT = "revPBE+U DFPT" revPBE_U_DFPT_Dielectric = "revPBE+U DFPT Dielectric" revPBE_U_NMR_Nuclear_Shielding = "revPBE+U NMR Nuclear Shielding" revPBE_U_NMR_Electric_Field_Gradient = "revPBE+U NMR Electric Field Gradient" revPBE_U_Static = "revPBE+U Static" revPBE_U_Structure_Optimization = "revPBE+U Structure Optimization" revPBE_U_Deformation = "revPBE+U Deformation" revPBE_U_Optic = "revPBE+U Optic" revPBE_U_Molecular_Dynamics = "revPBE+U Molecular Dynamics" revPBE_U_Unrecognized = "revPBE+U Unrecognized" B3LYP_U_NSCF_Line = "B3LYP+U NSCF Line" B3LYP_U_NSCF_Uniform = "B3LYP+U NSCF Uniform" B3LYP_U_Dielectric = "B3LYP+U Dielectric" B3LYP_U_DFPT = "B3LYP+U DFPT" B3LYP_U_DFPT_Dielectric = "B3LYP+U DFPT Dielectric" B3LYP_U_NMR_Nuclear_Shielding = "B3LYP+U NMR Nuclear Shielding" B3LYP_U_NMR_Electric_Field_Gradient = "B3LYP+U NMR Electric Field Gradient" B3LYP_U_Static = "B3LYP+U Static" B3LYP_U_Structure_Optimization = "B3LYP+U Structure Optimization" B3LYP_U_Deformation = "B3LYP+U Deformation" B3LYP_U_Optic = "B3LYP+U Optic" B3LYP_U_Molecular_Dynamics = "B3LYP+U Molecular Dynamics" B3LYP_U_Unrecognized = "B3LYP+U Unrecognized" HF_U_NSCF_Line = "HF+U NSCF Line" HF_U_NSCF_Uniform = "HF+U NSCF Uniform" HF_U_Dielectric = "HF+U Dielectric" HF_U_DFPT = "HF+U DFPT" HF_U_DFPT_Dielectric = "HF+U DFPT Dielectric" HF_U_NMR_Nuclear_Shielding = "HF+U NMR Nuclear Shielding" HF_U_NMR_Electric_Field_Gradient = "HF+U NMR Electric Field Gradient" HF_U_Static = "HF+U Static" HF_U_Structure_Optimization = "HF+U Structure Optimization" HF_U_Deformation = "HF+U Deformation" HF_U_Optic = "HF+U Optic" HF_U_Molecular_Dynamics = "HF+U Molecular Dynamics" HF_U_Unrecognized = "HF+U Unrecognized" HSE03_U_NSCF_Line = "HSE03+U NSCF Line" HSE03_U_NSCF_Uniform = "HSE03+U NSCF Uniform" HSE03_U_Dielectric = "HSE03+U Dielectric" HSE03_U_DFPT = "HSE03+U DFPT" HSE03_U_DFPT_Dielectric = "HSE03+U DFPT Dielectric" HSE03_U_NMR_Nuclear_Shielding = "HSE03+U NMR Nuclear Shielding" HSE03_U_NMR_Electric_Field_Gradient = "HSE03+U NMR Electric Field Gradient" HSE03_U_Static = "HSE03+U Static" HSE03_U_Structure_Optimization = "HSE03+U Structure Optimization" HSE03_U_Deformation = "HSE03+U Deformation" HSE03_U_Optic = "HSE03+U Optic" HSE03_U_Molecular_Dynamics = "HSE03+U Molecular Dynamics" HSE03_U_Unrecognized = "HSE03+U Unrecognized" HSE06_U_NSCF_Line = "HSE06+U NSCF Line" HSE06_U_NSCF_Uniform = "HSE06+U NSCF Uniform" HSE06_U_Dielectric = "HSE06+U Dielectric" HSE06_U_DFPT = "HSE06+U DFPT" HSE06_U_DFPT_Dielectric = "HSE06+U DFPT Dielectric" HSE06_U_NMR_Nuclear_Shielding = "HSE06+U NMR Nuclear Shielding" HSE06_U_NMR_Electric_Field_Gradient = "HSE06+U NMR Electric Field Gradient" HSE06_U_Static = "HSE06+U Static" HSE06_U_Structure_Optimization = "HSE06+U Structure Optimization" HSE06_U_Deformation = "HSE06+U Deformation" HSE06_U_Optic = "HSE06+U Optic" HSE06_U_Molecular_Dynamics = "HSE06+U Molecular Dynamics" HSE06_U_Unrecognized = "HSE06+U Unrecognized" PBE0_U_NSCF_Line = "PBE0+U NSCF Line" PBE0_U_NSCF_Uniform = "PBE0+U NSCF Uniform" PBE0_U_Dielectric = "PBE0+U Dielectric" PBE0_U_DFPT = "PBE0+U DFPT" PBE0_U_DFPT_Dielectric = "PBE0+U DFPT Dielectric" PBE0_U_NMR_Nuclear_Shielding = "PBE0+U NMR Nuclear Shielding" PBE0_U_NMR_Electric_Field_Gradient = "PBE0+U NMR Electric Field Gradient" PBE0_U_Static = "PBE0+U Static" PBE0_U_Structure_Optimization = "PBE0+U Structure Optimization" PBE0_U_Deformation = "PBE0+U Deformation" PBE0_U_Optic = "PBE0+U Optic" PBE0_U_Molecular_Dynamics = "PBE0+U Molecular Dynamics" PBE0_U_Unrecognized = "PBE0+U Unrecognized" M06L_U_NSCF_Line = "M06L+U NSCF Line" M06L_U_NSCF_Uniform = "M06L+U NSCF Uniform" M06L_U_Dielectric = "M06L+U Dielectric" M06L_U_DFPT = "M06L+U DFPT" M06L_U_DFPT_Dielectric = "M06L+U DFPT Dielectric" M06L_U_NMR_Nuclear_Shielding = "M06L+U NMR Nuclear Shielding" M06L_U_NMR_Electric_Field_Gradient = "M06L+U NMR Electric Field Gradient" M06L_U_Static = "M06L+U Static" M06L_U_Structure_Optimization = "M06L+U Structure Optimization" M06L_U_Deformation = "M06L+U Deformation" M06L_U_Optic = "M06L+U Optic" M06L_U_Molecular_Dynamics = "M06L+U Molecular Dynamics" M06L_U_Unrecognized = "M06L+U Unrecognized" MBJL_U_NSCF_Line = "MBJL+U NSCF Line" MBJL_U_NSCF_Uniform = "MBJL+U NSCF Uniform" MBJL_U_Dielectric = "MBJL+U Dielectric" MBJL_U_DFPT = "MBJL+U DFPT" MBJL_U_DFPT_Dielectric = "MBJL+U DFPT Dielectric" MBJL_U_NMR_Nuclear_Shielding = "MBJL+U NMR Nuclear Shielding" MBJL_U_NMR_Electric_Field_Gradient = "MBJL+U NMR Electric Field Gradient" MBJL_U_Static = "MBJL+U Static" MBJL_U_Structure_Optimization = "MBJL+U Structure Optimization" MBJL_U_Deformation = "MBJL+U Deformation" MBJL_U_Optic = "MBJL+U Optic" MBJL_U_Molecular_Dynamics = "MBJL+U Molecular Dynamics" MBJL_U_Unrecognized = "MBJL+U Unrecognized" MS0_U_NSCF_Line = "MS0+U NSCF Line" MS0_U_NSCF_Uniform = "MS0+U NSCF Uniform" MS0_U_Dielectric = "MS0+U Dielectric" MS0_U_DFPT = "MS0+U DFPT" MS0_U_DFPT_Dielectric = "MS0+U DFPT Dielectric" MS0_U_NMR_Nuclear_Shielding = "MS0+U NMR Nuclear Shielding" MS0_U_NMR_Electric_Field_Gradient = "MS0+U NMR Electric Field Gradient" MS0_U_Static = "MS0+U Static" MS0_U_Structure_Optimization = "MS0+U Structure Optimization" MS0_U_Deformation = "MS0+U Deformation" MS0_U_Optic = "MS0+U Optic" MS0_U_Molecular_Dynamics = "MS0+U Molecular Dynamics" MS0_U_Unrecognized = "MS0+U Unrecognized" MS1_U_NSCF_Line = "MS1+U NSCF Line" MS1_U_NSCF_Uniform = "MS1+U NSCF Uniform" MS1_U_Dielectric = "MS1+U Dielectric" MS1_U_DFPT = "MS1+U DFPT" MS1_U_DFPT_Dielectric = "MS1+U DFPT Dielectric" MS1_U_NMR_Nuclear_Shielding = "MS1+U NMR Nuclear Shielding" MS1_U_NMR_Electric_Field_Gradient = "MS1+U NMR Electric Field Gradient" MS1_U_Static = "MS1+U Static" MS1_U_Structure_Optimization = "MS1+U Structure Optimization" MS1_U_Deformation = "MS1+U Deformation" MS1_U_Optic = "MS1+U Optic" MS1_U_Molecular_Dynamics = "MS1+U Molecular Dynamics" MS1_U_Unrecognized = "MS1+U Unrecognized" MS2_U_NSCF_Line = "MS2+U NSCF Line" MS2_U_NSCF_Uniform = "MS2+U NSCF Uniform" MS2_U_Dielectric = "MS2+U Dielectric" MS2_U_DFPT = "MS2+U DFPT" MS2_U_DFPT_Dielectric = "MS2+U DFPT Dielectric" MS2_U_NMR_Nuclear_Shielding = "MS2+U NMR Nuclear Shielding" MS2_U_NMR_Electric_Field_Gradient = "MS2+U NMR Electric Field Gradient" MS2_U_Static = "MS2+U Static" MS2_U_Structure_Optimization = "MS2+U Structure Optimization" MS2_U_Deformation = "MS2+U Deformation" MS2_U_Optic = "MS2+U Optic" MS2_U_Molecular_Dynamics = "MS2+U Molecular Dynamics" MS2_U_Unrecognized = "MS2+U Unrecognized" RTPSS_U_NSCF_Line = "RTPSS+U NSCF Line" RTPSS_U_NSCF_Uniform = "RTPSS+U NSCF Uniform" RTPSS_U_Dielectric = "RTPSS+U Dielectric" RTPSS_U_DFPT = "RTPSS+U DFPT" RTPSS_U_DFPT_Dielectric = "RTPSS+U DFPT Dielectric" RTPSS_U_NMR_Nuclear_Shielding = "RTPSS+U NMR Nuclear Shielding" RTPSS_U_NMR_Electric_Field_Gradient = "RTPSS+U NMR Electric Field Gradient" RTPSS_U_Static = "RTPSS+U Static" RTPSS_U_Structure_Optimization = "RTPSS+U Structure Optimization" RTPSS_U_Deformation = "RTPSS+U Deformation" RTPSS_U_Optic = "RTPSS+U Optic" RTPSS_U_Molecular_Dynamics = "RTPSS+U Molecular Dynamics" RTPSS_U_Unrecognized = "RTPSS+U Unrecognized" SCAN_U_NSCF_Line = "SCAN+U NSCF Line" SCAN_U_NSCF_Uniform = "SCAN+U NSCF Uniform" SCAN_U_Dielectric = "SCAN+U Dielectric" SCAN_U_DFPT = "SCAN+U DFPT" SCAN_U_DFPT_Dielectric = "SCAN+U DFPT Dielectric" SCAN_U_NMR_Nuclear_Shielding = "SCAN+U NMR Nuclear Shielding" SCAN_U_NMR_Electric_Field_Gradient = "SCAN+U NMR Electric Field Gradient" SCAN_U_Static = "SCAN+U Static" SCAN_U_Structure_Optimization = "SCAN+U Structure Optimization" SCAN_U_Deformation = "SCAN+U Deformation" SCAN_U_Optic = "SCAN+U Optic" SCAN_U_Molecular_Dynamics = "SCAN+U Molecular Dynamics" SCAN_U_Unrecognized = "SCAN+U Unrecognized" R2SCAN_U_NSCF_Line = "R2SCAN+U NSCF Line" R2SCAN_U_NSCF_Uniform = "R2SCAN+U NSCF Uniform" R2SCAN_U_Dielectric = "R2SCAN+U Dielectric" R2SCAN_U_DFPT = "R2SCAN+U DFPT" R2SCAN_U_DFPT_Dielectric = "R2SCAN+U DFPT Dielectric" R2SCAN_U_NMR_Nuclear_Shielding = "R2SCAN+U NMR Nuclear Shielding" R2SCAN_U_NMR_Electric_Field_Gradient = "R2SCAN+U NMR Electric Field Gradient" R2SCAN_U_Static = "R2SCAN+U Static" R2SCAN_U_Structure_Optimization = "R2SCAN+U Structure Optimization" R2SCAN_U_Deformation = "R2SCAN+U Deformation" R2SCAN_U_Optic = "R2SCAN+U Optic" R2SCAN_U_Molecular_Dynamics = "R2SCAN+U Molecular Dynamics" R2SCAN_U_Unrecognized = "R2SCAN+U Unrecognized" TPSS_U_NSCF_Line = "TPSS+U NSCF Line" TPSS_U_NSCF_Uniform = "TPSS+U NSCF Uniform" TPSS_U_Dielectric = "TPSS+U Dielectric" TPSS_U_DFPT = "TPSS+U DFPT" TPSS_U_DFPT_Dielectric = "TPSS+U DFPT Dielectric" TPSS_U_NMR_Nuclear_Shielding = "TPSS+U NMR Nuclear Shielding" TPSS_U_NMR_Electric_Field_Gradient = "TPSS+U NMR Electric Field Gradient" TPSS_U_Static = "TPSS+U Static" TPSS_U_Structure_Optimization = "TPSS+U Structure Optimization" TPSS_U_Deformation = "TPSS+U Deformation" TPSS_U_Optic = "TPSS+U Optic" TPSS_U_Molecular_Dynamics = "TPSS+U Molecular Dynamics" TPSS_U_Unrecognized = "TPSS+U Unrecognized" R2SCAN_rVV10_U_NSCF_Line = "R2SCAN-rVV10+U NSCF Line" R2SCAN_rVV10_U_NSCF_Uniform = "R2SCAN-rVV10+U NSCF Uniform" R2SCAN_rVV10_U_Dielectric = "R2SCAN-rVV10+U Dielectric" R2SCAN_rVV10_U_DFPT = "R2SCAN-rVV10+U DFPT" R2SCAN_rVV10_U_DFPT_Dielectric = "R2SCAN-rVV10+U DFPT Dielectric" R2SCAN_rVV10_U_NMR_Nuclear_Shielding = "R2SCAN-rVV10+U NMR Nuclear Shielding" R2SCAN_rVV10_U_NMR_Electric_Field_Gradient = ( "R2SCAN-rVV10+U NMR Electric Field Gradient" ) R2SCAN_rVV10_U_Static = "R2SCAN-rVV10+U Static" R2SCAN_rVV10_U_Structure_Optimization = "R2SCAN-rVV10+U Structure Optimization" R2SCAN_rVV10_U_Deformation = "R2SCAN-rVV10+U Deformation" R2SCAN_rVV10_U_Optic = "R2SCAN-rVV10+U Optic" R2SCAN_rVV10_U_Molecular_Dynamics = "R2SCAN-rVV10+U Molecular Dynamics" R2SCAN_rVV10_U_Unrecognized = "R2SCAN-rVV10+U Unrecognized" SCAN_rVV10_U_NSCF_Line = "SCAN-rVV10+U NSCF Line" SCAN_rVV10_U_NSCF_Uniform = "SCAN-rVV10+U NSCF Uniform" SCAN_rVV10_U_Dielectric = "SCAN-rVV10+U Dielectric" SCAN_rVV10_U_DFPT = "SCAN-rVV10+U DFPT" SCAN_rVV10_U_DFPT_Dielectric = "SCAN-rVV10+U DFPT Dielectric" SCAN_rVV10_U_NMR_Nuclear_Shielding = "SCAN-rVV10+U NMR Nuclear Shielding" SCAN_rVV10_U_NMR_Electric_Field_Gradient = ( "SCAN-rVV10+U NMR Electric Field Gradient" ) SCAN_rVV10_U_Static = "SCAN-rVV10+U Static" SCAN_rVV10_U_Structure_Optimization = "SCAN-rVV10+U Structure Optimization" SCAN_rVV10_U_Deformation = "SCAN-rVV10+U Deformation" SCAN_rVV10_U_Optic = "SCAN-rVV10+U Optic" SCAN_rVV10_U_Molecular_Dynamics = "SCAN-rVV10+U Molecular Dynamics" SCAN_rVV10_U_Unrecognized = "SCAN-rVV10+U Unrecognized" optB86b_vdW_U_NSCF_Line = "optB86b-vdW+U NSCF Line" optB86b_vdW_U_NSCF_Uniform = "optB86b-vdW+U NSCF Uniform" optB86b_vdW_U_Dielectric = "optB86b-vdW+U Dielectric" optB86b_vdW_U_DFPT = "optB86b-vdW+U DFPT" optB86b_vdW_U_DFPT_Dielectric = "optB86b-vdW+U DFPT Dielectric" optB86b_vdW_U_NMR_Nuclear_Shielding = "optB86b-vdW+U NMR Nuclear Shielding" optB86b_vdW_U_NMR_Electric_Field_Gradient = ( "optB86b-vdW+U NMR Electric Field Gradient" ) optB86b_vdW_U_Static = "optB86b-vdW+U Static" optB86b_vdW_U_Structure_Optimization = "optB86b-vdW+U Structure Optimization" optB86b_vdW_U_Deformation = "optB86b-vdW+U Deformation" optB86b_vdW_U_Optic = "optB86b-vdW+U Optic" optB86b_vdW_U_Molecular_Dynamics = "optB86b-vdW+U Molecular Dynamics" optB86b_vdW_U_Unrecognized = "optB86b-vdW+U Unrecognized" optB88_vdW_U_NSCF_Line = "optB88-vdW+U NSCF Line" optB88_vdW_U_NSCF_Uniform = "optB88-vdW+U NSCF Uniform" optB88_vdW_U_Dielectric = "optB88-vdW+U Dielectric" optB88_vdW_U_DFPT = "optB88-vdW+U DFPT" optB88_vdW_U_DFPT_Dielectric = "optB88-vdW+U DFPT Dielectric" optB88_vdW_U_NMR_Nuclear_Shielding = "optB88-vdW+U NMR Nuclear Shielding" optB88_vdW_U_NMR_Electric_Field_Gradient = ( "optB88-vdW+U NMR Electric Field Gradient" ) optB88_vdW_U_Static = "optB88-vdW+U Static" optB88_vdW_U_Structure_Optimization = "optB88-vdW+U Structure Optimization" optB88_vdW_U_Deformation = "optB88-vdW+U Deformation" optB88_vdW_U_Optic = "optB88-vdW+U Optic" optB88_vdW_U_Molecular_Dynamics = "optB88-vdW+U Molecular Dynamics" optB88_vdW_U_Unrecognized = "optB88-vdW+U Unrecognized" optPBE_vdW_U_NSCF_Line = "optPBE-vdW+U NSCF Line" optPBE_vdW_U_NSCF_Uniform = "optPBE-vdW+U NSCF Uniform" optPBE_vdW_U_Dielectric = "optPBE-vdW+U Dielectric" optPBE_vdW_U_DFPT = "optPBE-vdW+U DFPT" optPBE_vdW_U_DFPT_Dielectric = "optPBE-vdW+U DFPT Dielectric" optPBE_vdW_U_NMR_Nuclear_Shielding = "optPBE-vdW+U NMR Nuclear Shielding" optPBE_vdW_U_NMR_Electric_Field_Gradient = ( "optPBE-vdW+U NMR Electric Field Gradient" ) optPBE_vdW_U_Static = "optPBE-vdW+U Static" optPBE_vdW_U_Structure_Optimization = "optPBE-vdW+U Structure Optimization" optPBE_vdW_U_Deformation = "optPBE-vdW+U Deformation" optPBE_vdW_U_Optic = "optPBE-vdW+U Optic" optPBE_vdW_U_Molecular_Dynamics = "optPBE-vdW+U Molecular Dynamics" optPBE_vdW_U_Unrecognized = "optPBE-vdW+U Unrecognized" 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_Dielectric = "rev-vdW-DF2+U Dielectric" 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_NMR_Nuclear_Shielding = "rev-vdW-DF2+U NMR Nuclear Shielding" rev_vdW_DF2_U_NMR_Electric_Field_Gradient = ( "rev-vdW-DF2+U NMR Electric Field Gradient" ) 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_Deformation = "rev-vdW-DF2+U Deformation" rev_vdW_DF2_U_Optic = "rev-vdW-DF2+U Optic" rev_vdW_DF2_U_Molecular_Dynamics = "rev-vdW-DF2+U Molecular Dynamics" rev_vdW_DF2_U_Unrecognized = "rev-vdW-DF2+U Unrecognized" revPBE_vdW_U_NSCF_Line = "revPBE-vdW+U NSCF Line" revPBE_vdW_U_NSCF_Uniform = "revPBE-vdW+U NSCF Uniform" revPBE_vdW_U_Dielectric = "revPBE-vdW+U Dielectric" revPBE_vdW_U_DFPT = "revPBE-vdW+U DFPT" revPBE_vdW_U_DFPT_Dielectric = "revPBE-vdW+U DFPT Dielectric" revPBE_vdW_U_NMR_Nuclear_Shielding = "revPBE-vdW+U NMR Nuclear Shielding" revPBE_vdW_U_NMR_Electric_Field_Gradient = ( "revPBE-vdW+U NMR Electric Field Gradient" ) revPBE_vdW_U_Static = "revPBE-vdW+U Static" revPBE_vdW_U_Structure_Optimization = "revPBE-vdW+U Structure Optimization" revPBE_vdW_U_Deformation = "revPBE-vdW+U Deformation" revPBE_vdW_U_Optic = "revPBE-vdW+U Optic" revPBE_vdW_U_Molecular_Dynamics = "revPBE-vdW+U Molecular Dynamics" revPBE_vdW_U_Unrecognized = "revPBE-vdW+U Unrecognized" vdW_DF2_U_NSCF_Line = "vdW-DF2+U NSCF Line" vdW_DF2_U_NSCF_Uniform = "vdW-DF2+U NSCF Uniform" vdW_DF2_U_Dielectric = "vdW-DF2+U Dielectric" vdW_DF2_U_DFPT = "vdW-DF2+U DFPT" vdW_DF2_U_DFPT_Dielectric = "vdW-DF2+U DFPT Dielectric" vdW_DF2_U_NMR_Nuclear_Shielding = "vdW-DF2+U NMR Nuclear Shielding" vdW_DF2_U_NMR_Electric_Field_Gradient = "vdW-DF2+U NMR Electric Field Gradient" vdW_DF2_U_Static = "vdW-DF2+U Static" vdW_DF2_U_Structure_Optimization = "vdW-DF2+U Structure Optimization" vdW_DF2_U_Deformation = "vdW-DF2+U Deformation" vdW_DF2_U_Optic = "vdW-DF2+U Optic" vdW_DF2_U_Molecular_Dynamics = "vdW-DF2+U Molecular Dynamics" vdW_DF2_U_Unrecognized = "vdW-DF2+U Unrecognized" LDA_NSCF_Line = "LDA NSCF Line" LDA_NSCF_Uniform = "LDA NSCF Uniform" LDA_Dielectric = "LDA Dielectric" LDA_DFPT = "LDA DFPT" LDA_DFPT_Dielectric = "LDA DFPT Dielectric" LDA_NMR_Nuclear_Shielding = "LDA NMR Nuclear Shielding" LDA_NMR_Electric_Field_Gradient = "LDA NMR Electric Field Gradient" LDA_Static = "LDA Static" LDA_Structure_Optimization = "LDA Structure Optimization" LDA_Deformation = "LDA Deformation" LDA_Optic = "LDA Optic" LDA_Molecular_Dynamics = "LDA Molecular Dynamics" LDA_Unrecognized = "LDA Unrecognized" LDA_U_NSCF_Line = "LDA+U NSCF Line" LDA_U_NSCF_Uniform = "LDA+U NSCF Uniform" LDA_U_Dielectric = "LDA+U Dielectric" LDA_U_DFPT = "LDA+U DFPT" LDA_U_DFPT_Dielectric = "LDA+U DFPT Dielectric" LDA_U_NMR_Nuclear_Shielding = "LDA+U NMR Nuclear Shielding" LDA_U_NMR_Electric_Field_Gradient = "LDA+U NMR Electric Field Gradient" LDA_U_Static = "LDA+U Static" LDA_U_Structure_Optimization = "LDA+U Structure Optimization" LDA_U_Deformation = "LDA+U Deformation" LDA_U_Optic = "LDA+U Optic" LDA_U_Molecular_Dynamics = "LDA+U Molecular Dynamics" LDA_U_Unrecognized = "LDA+U Unrecognized" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calc_types/generate.py0000644000175100001770000000354414551165444022571 0ustar00runnerdocker"""Module to define various calculation types as Enums for VASP.""" from itertools import product from pathlib import Path from monty.serialization import loadfn from emmet.core.utils import get_enum_source _RUN_TYPE_DATA = loadfn(str(Path(__file__).parent.joinpath("run_types.yaml").resolve())) _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", ] _RUN_TYPES = ( [ rt for functional_class in _RUN_TYPE_DATA for rt in _RUN_TYPE_DATA[functional_class] ] + [ f"{rt}+U" for functional_class in _RUN_TYPE_DATA for rt in _RUN_TYPE_DATA[functional_class] ] + ["LDA", "LDA+U"] ) run_type_enum = get_enum_source( "RunType", "VASP calculation run types.", {"_".join(rt.split()).replace("+", "_").replace("-", "_"): rt for rt in _RUN_TYPES}, ) task_type_enum = get_enum_source( "TaskType", "VASP calculation task types.", {"_".join(tt.split()): tt for tt in _TASK_TYPES}, ) calc_type_enum = get_enum_source( "CalcType", "VASP calculation types.", { f"{'_'.join(rt.split()).replace('+','_').replace('-','_')}" f"_{'_'.join(tt.split())}": f"{rt} {tt}" for rt, tt in product(_RUN_TYPES, _TASK_TYPES) }, ) with open(Path(__file__).parent / "enums.py", "w") as f: f.write( """\"\"\" Autogenerated Enums for VASP RunType, TaskType, and CalcType. Do not edit this by hand. Edit generate.py or run_types.yaml instead. \"\"\" from emmet.core.utils import ValueEnum """ ) f.write(run_type_enum) f.write("\n\n") f.write(task_type_enum) f.write("\n\n") f.write(calc_type_enum) f.write("\n") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calc_types/run_types.yaml0000644000175100001770000000330514551165444023334 0ustar00runnerdockerGGA: 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 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calc_types/utils.py0000644000175100001770000001040014551165444022124 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("run_types.yaml").resolve())) __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=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/calculation.py0000644000175100001770000011526714551165444021155 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 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(BaseModel): """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) ] return cls( structure=vasprun.initial_structure, incar=dict(vasprun.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=dict(vasprun.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)", ) 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, ) -> "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. 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") # 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(BaseModel): """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, 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. 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, ) 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.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(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=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/material.py0000644000175100001770000002371014551165444020444 0ustar00runnerdocker""" Core definition of a Materials Document """ from typing import Dict, List, Mapping, Optional from emmet.core.base import EmmetMeta from pydantic import Field, BaseModel from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer from pymatgen.analysis.structure_matcher import StructureMatcher from pymatgen.entries.computed_entries import ComputedStructureEntry 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.vasp.calc_types import CalcType, RunType, TaskType from emmet.core.vasp.task_valid import TaskDocument 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[TaskDocument], 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 ) # 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: TaskDocument): """ 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) 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: TaskDocument): """ 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) 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) 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[TaskDocument], 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=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/task_valid.py0000644000175100001770000001550514551165444020772 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( [], description="Forces on atoms from the last calculation" ) stress: Optional[Matrix3D] = Field( [], 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=1705306916.0 emmet-core-0.76.2/emmet/core/vasp/validation.py0000644000175100001770000003550214551165444021002 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.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.vasp.task_valid import TaskDocument from emmet.core.vasp.calc_types.enums import CalcType, TaskType SETTINGS = EmmetSettings() class DeprecationMessage(DocEnum): MANUAL = "M", "Manual deprecation" 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") @classmethod def from_task_doc( cls, task_doc: 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, potcar_hashes: 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_hashes: Dictionary of potcar hash data. Mapping is calculation type -> potcar symbol -> hash value. """ 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 = task_doc.calcs_reversed if calcs_reversed[0].get("input", {}).get("structure", None): structure = Structure.from_dict(calcs_reversed[0]["input"]["structure"]) else: structure = task_doc.input.structure or task_doc.output.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 if valid_input_set: # Checking POTCAR summary_stats if a directory is supplied if potcar_hashes: if _potcar_hash_check(task_doc, potcar_hashes): 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 != task_type.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) curr_ismear = inputs.get("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 = inputs.get("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(task_doc, chemsys): 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, ) 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 = 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 num_kpts = input_dict.get("kpoints", {}).get("nkpoints", 0) or np.prod( input_dict.get("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 inputs.get("incar", {}).get("KSPACING"): data["kspacing_delta"] = inputs["incar"].get("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_hash_check(task_doc, potcar_hashes): """ 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]["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 all_match = True for entry in potcar_details: symbol = entry["titel"].split(" ")[1] ref_summ_stats = potcar_hashes[str(task_doc.calc_type)].get(symbol, None) if not ref_summ_stats: all_match = False break key_match = all( set(ref_summ_stats["keywords"][key]) == set(entry["summary_stats"]["keywords"][key]) for key in ["header", "data"] ) data_match = all( abs( ref_summ_stats["stats"][key][stat] - entry["summary_stats"]["stats"][key][stat] ) < data_tol for stat in ["MEAN", "ABSMEAN", "VAR", "MIN", "MAX"] for key in ["header", "data"] ) if (not key_match) or (not data_match): all_match = False break return not all_match def _magmom_check(task_doc, chemsys): """ Checks for maximum magnetization values for specific elements. Returns True if the maximum absolute value outlined below is exceded for the associated element. """ eles_max_vals = {"Cr": 5} for ele, max_val in eles_max_vals.items(): if ele in chemsys: for site_num, mag in enumerate( task_doc.calcs_reversed[0]["output"]["outcar"]["magnetization"] ): if "structure" in task_doc.calcs_reversed[0]["output"]: output_structure = task_doc.calcs_reversed[0]["output"]["structure"] else: output_structure = task_doc.output.structure.as_dict() if output_structure["sites"][site_num]["label"] == ele: if abs(mag["tot"]) > max_val: return True 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=1705306916.0 emmet-core-0.76.2/emmet/core/xas.py0000644000175100001770000002152314551165444016470 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 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 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 = [ id for spectrum in relevant_spectra for id in spectrum.task_ids ] avg_spectrum.last_updated = max( [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=1705306916.0 emmet-core-0.76.2/emmet/core/xrd.py0000644000175100001770000000652114551165444016473 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=1705306921.9072564 emmet-core-0.76.2/emmet_core.egg-info/0000755000175100001770000000000014551165452017071 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/PKG-INFO0000644000175100001770000000156514551165451020174 0ustar00runnerdockerMetadata-Version: 2.1 Name: emmet-core Version: 0.76.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=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/SOURCES.txt0000644000175100001770000001005614551165451020756 0ustar00runnerdockerredox_doc_test.json setup.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/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/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/em_utils.py emmet/core/qchem/calc_types/enums.py emmet/core/qchem/calc_types/generate.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/enums.py emmet/core/vasp/calc_types/generate.py emmet/core/vasp/calc_types/run_types.yaml 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 requirements/ubuntu-latest_py3.9.txt requirements/ubuntu-latest_py3.9_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_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/qchem/__init__.py tests/qchem/test_molecules.py tests/qchem/test_qchem.py tests/vasp/test_materials.py tests/vasp/test_vasp.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/dependency_links.txt0000644000175100001770000000000114551165451023136 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/not-zip-safe0000644000175100001770000000000114551165451021316 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/requires.txt0000644000175100001770000000112114551165451021463 0ustar00runnerdockerpymatgen>=2023.10.11 monty>=2023.9.25 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-diffusion>=2023.8.15 pymatgen-analysis-alloys>=0.0.3 [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 [test] pre-commit pytest pytest-cov pycodestyle pydocstyle flake8 mypy mypy-extensions types-setuptools types-requests wincertstore custodian ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306921.0 emmet-core-0.76.2/emmet_core.egg-info/top_level.txt0000644000175100001770000000000614551165451021616 0ustar00runnerdockeremmet ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/redox_doc_test.json0000644000175100001770000000604614551165444017167 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=1705306921.9072564 emmet-core-0.76.2/requirements/0000755000175100001770000000000014551165452016003 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/deployment.txt0000644000175100001770000000470514551165444020733 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.6.0 # via pydantic certifi==2023.11.17 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.2.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.47.0 # via matplotlib future==0.18.3 # via uncertainties idna==3.6 # via requests joblib==1.3.2 # via pymatgen kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex matplotlib==3.8.2 # via # -r python/requirements.txt # pymatgen monty==2023.11.3 # via # emmet-core (emmet/emmet-core/setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.2.1 # via pymatgen numpy==1.26.3 # via # -r python/requirements.txt # contourpy # matplotlib # pandas # pymatgen # scipy # spglib packaging==23.2 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==1.5.3 # via # -r python/requirements.txt # pymatgen pillow==10.2.0 # via matplotlib plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via # emmet-core (emmet/emmet-core/setup.py) # pymatgen pydantic==2.5.3 # via # emmet-core (emmet/emmet-core/setup.py) # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (emmet/emmet-core/setup.py) pymatgen==2023.12.18 # via emmet-core (emmet/emmet-core/setup.py) pyparsing==3.1.1 # via matplotlib python-dateutil==2.8.2 # via # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via pybtex requests==2.31.0 # via pymatgen ruamel-yaml==0.18.5 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.11.4 # via # -r python/requirements.txt # pymatgen six==1.16.0 # via # latexcodec # pybtex # python-dateutil spglib==2.2.0 # via pymatgen sympy==1.12 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly tqdm==4.66.1 # via pymatgen typing-extensions==4.9.0 # via # emmet-core (emmet/emmet-core/setup.py) # pydantic # pydantic-core uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.10.txt0000644000175100001770000000424214551165444022375 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.6.0 # via pydantic certifi==2023.11.17 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.2.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.47.0 # via matplotlib future==0.18.3 # via uncertainties idna==3.6 # via requests joblib==1.3.2 # via pymatgen kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex matplotlib==3.8.2 # via pymatgen monty==2023.11.3 # via # emmet-core (setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.2.1 # via pymatgen numpy==1.26.3 # via # contourpy # matplotlib # pandas # pymatgen # scipy # spglib packaging==23.2 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.1.4 # via pymatgen pillow==10.2.0 # via matplotlib plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen pydantic==2.5.3 # via # emmet-core (setup.py) # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pymatgen==2023.12.18 # via emmet-core (setup.py) pyparsing==3.1.1 # via matplotlib python-dateutil==2.8.2 # via # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via pybtex requests==2.31.0 # via pymatgen ruamel-yaml==0.18.5 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.11.4 # via pymatgen six==1.16.0 # via # latexcodec # pybtex # python-dateutil spglib==2.2.0 # via pymatgen sympy==1.12 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly tqdm==4.66.1 # via pymatgen typing-extensions==4.9.0 # via # emmet-core (setup.py) # pydantic # pydantic-core tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.10_extras.txt0000644000175100001770000002236714551165444023773 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 # aiohttp==3.9.1 # via fsspec aiosignal==1.3.1 # via aiohttp annotated-types==0.6.0 # via pydantic ase==3.22.1 # via # chgnet # matcalc # matgl async-timeout==4.0.3 # via aiohttp attrs==23.2.0 # via aiohttp bracex==2.4 # via wcmatch certifi==2023.11.17 # via # requests # sentry-sdk cfgv==3.4.0 # via pre-commit charset-normalizer==3.3.2 # via requests chgnet==0.3.3 # via emmet-core (setup.py) click==8.1.7 # via # mkdocs # mkdocstrings colorama==0.4.6 # via griffe contourpy==1.2.0 # via matplotlib coverage[toml]==7.4.0 # via # coverage # pytest-cov csscompressor==0.9.5 # via mkdocs-minify-plugin custodian==2023.10.9 # via emmet-core (setup.py) cycler==0.12.1 # via matplotlib cython==3.0.7 # via chgnet dgl==1.1.3 # via matgl distlib==0.3.8 # via virtualenv dnspython==2.4.2 # via pymongo exceptiongroup==1.2.0 # via pytest filelock==3.13.1 # via # torch # triton # virtualenv flake8==7.0.0 # via emmet-core (setup.py) fonttools==4.47.0 # via matplotlib frozenlist==1.4.1 # via # aiohttp # aiosignal fsspec[http]==2023.12.2 # via # pytorch-lightning # torch future==0.18.3 # via # matminer # uncertainties ghp-import==2.1.0 # via mkdocs griffe==0.38.1 # via mkdocstrings-python h5py==3.10.0 # via phonopy htmlmin2==0.1.13 # via mkdocs-minify-plugin identify==2.5.33 # via pre-commit idna==3.6 # via # requests # yarl inflect==7.0.0 # via robocrys iniconfig==2.0.0 # via pytest jinja2==3.1.2 # via # emmet-core (setup.py) # mkdocs # mkdocs-material # mkdocstrings # torch joblib==1.3.2 # via # matcalc # pymatgen # pymatgen-analysis-diffusion # scikit-learn jsmin==3.0.1 # via mkdocs-minify-plugin kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex lightning-utilities==0.10.0 # via # pytorch-lightning # torchmetrics livereload==2.6.3 # via emmet-core (setup.py) markdown==3.5.1 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions markupsafe==2.1.3 # via # jinja2 # mkdocs # mkdocstrings matcalc==0.0.4 # via emmet-core (setup.py) matgl==0.9.1 # via emmet-core (setup.py) matminer==0.9.0 # via robocrys matplotlib==3.8.2 # via # ase # phonopy # pymatgen mccabe==0.7.0 # via flake8 mergedeep==1.3.4 # via mkdocs mkdocs==1.5.3 # via # emmet-core (setup.py) # mkdocs-autorefs # mkdocs-awesome-pages-plugin # mkdocs-markdownextradata-plugin # mkdocs-material # mkdocs-minify-plugin # mkdocstrings mkdocs-autorefs==0.5.0 # via mkdocstrings mkdocs-awesome-pages-plugin==2.9.2 # via emmet-core (setup.py) mkdocs-markdownextradata-plugin==0.2.5 # 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.7.2 # via emmet-core (setup.py) mkdocstrings[python]==0.24.0 # via # emmet-core (setup.py) # mkdocstrings-python mkdocstrings-python==1.8.0 # via mkdocstrings monty==2023.11.3 # via # custodian # emmet-core (setup.py) # matminer # pymatgen # robocrys mpmath==1.3.0 # via sympy multidict==6.0.4 # via # aiohttp # yarl mypy==1.8.0 # 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.2.1 # via # dgl # pymatgen # robocrys # torch nodeenv==1.8.0 # via pre-commit numpy==1.26.3 # via # ase # chgnet # contourpy # dgl # h5py # matminer # matplotlib # pandas # phonopy # pymatgen # pytorch-lightning # robocrys # scikit-learn # scipy # seekpath # shapely # spglib # 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==8.9.2.26 # 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.18.1 # via torch nvidia-nvjitlink-cu12==12.3.101 # via # nvidia-cusolver-cu12 # nvidia-cusparse-cu12 nvidia-nvtx-cu12==12.1.105 # via torch packaging==23.2 # via # lightning-utilities # matplotlib # mkdocs # plotly # pytest # pytorch-lightning # torchmetrics palettable==3.3.3 # via pymatgen pandas==1.5.3 # via # matminer # pymatgen pathspec==0.12.1 # via mkdocs phonopy==2.21.0 # via matcalc pillow==10.2.0 # via matplotlib platformdirs==4.1.0 # via # mkdocs # mkdocstrings # virtualenv plotly==5.18.0 # via pymatgen pluggy==1.3.0 # via pytest pre-commit==3.6.0 # via emmet-core (setup.py) psutil==5.9.7 # via # custodian # dgl pubchempy==1.0.4 # via robocrys pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen # robocrys pycodestyle==2.11.1 # via # emmet-core (setup.py) # flake8 pydantic==2.5.3 # via # emmet-core (setup.py) # inflect # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pydocstyle==6.3.0 # via emmet-core (setup.py) pyflakes==3.2.0 # via flake8 pygments==2.17.2 # via mkdocs-material pymatgen==2023.12.18 # via # chgnet # emmet-core (setup.py) # matcalc # matgl # matminer # pymatgen-analysis-alloys # pymatgen-analysis-diffusion # robocrys pymatgen-analysis-alloys==0.0.6 # via emmet-core (setup.py) pymatgen-analysis-diffusion==2023.8.15 # via emmet-core (setup.py) pymdown-extensions==10.7 # via # mkdocs-material # mkdocstrings pymongo==4.6.1 # via matminer pyparsing==3.1.1 # via matplotlib pytest==7.4.4 # via # emmet-core (setup.py) # pytest-cov pytest-cov==4.1.0 # via emmet-core (setup.py) python-dateutil==2.8.2 # via # ghp-import # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytorch-lightning==2.1.3 # via matgl pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via # mkdocs # mkdocs-markdownextradata-plugin # phonopy # pre-commit # pybtex # pymdown-extensions # pytorch-lightning # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs requests==2.31.0 # via # dgl # fsspec # matminer # pymatgen robocrys==0.2.8 # via emmet-core (setup.py) ruamel-yaml==0.18.5 # via # custodian # pymatgen # robocrys ruamel-yaml-clib==0.2.8 # via ruamel-yaml scikit-learn==1.3.2 # via matminer scipy==1.11.4 # via # ase # dgl # pymatgen # robocrys # scikit-learn seekpath==2.1.0 # via emmet-core (setup.py) sentry-sdk==1.39.1 # via custodian shapely==2.0.2 # via pymatgen-analysis-alloys six==1.16.0 # via # latexcodec # livereload # pybtex # python-dateutil snowballstemmer==2.2.0 # via pydocstyle spglib==2.2.0 # via # phonopy # pymatgen # robocrys # seekpath sympy==1.12 # via # matminer # pymatgen # torch tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly threadpoolctl==3.2.0 # via scikit-learn tomli==2.0.1 # via # coverage # mypy # pytest torch==2.1.2 # via # chgnet # matgl # pytorch-lightning # torchmetrics torchmetrics==1.2.1 # via pytorch-lightning tornado==6.4 # via livereload tqdm==4.66.1 # via # dgl # matminer # pymatgen # pytorch-lightning triton==2.1.0 # via torch types-requests==2.31.0.20240106 # via emmet-core (setup.py) types-setuptools==69.0.0.20240106 # via emmet-core (setup.py) typing-extensions==4.9.0 # via # emmet-core (setup.py) # inflect # lightning-utilities # mypy # pydantic # pydantic-core # pytorch-lightning # torch uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via # requests # sentry-sdk # types-requests virtualenv==20.25.0 # via pre-commit watchdog==3.0.0 # via mkdocs wcmatch==8.5 # via mkdocs-awesome-pages-plugin wincertstore==0.2 # via emmet-core (setup.py) yarl==1.9.4 # via aiohttp # The following packages are considered to be unsafe in a requirements file: # setuptools ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.11.txt0000644000175100001770000000424214551165444022376 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.6.0 # via pydantic certifi==2023.11.17 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.2.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.47.0 # via matplotlib future==0.18.3 # via uncertainties idna==3.6 # via requests joblib==1.3.2 # via pymatgen kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex matplotlib==3.8.2 # via pymatgen monty==2023.11.3 # via # emmet-core (setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.2.1 # via pymatgen numpy==1.26.3 # via # contourpy # matplotlib # pandas # pymatgen # scipy # spglib packaging==23.2 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.1.4 # via pymatgen pillow==10.2.0 # via matplotlib plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen pydantic==2.5.3 # via # emmet-core (setup.py) # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pymatgen==2023.12.18 # via emmet-core (setup.py) pyparsing==3.1.1 # via matplotlib python-dateutil==2.8.2 # via # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via pybtex requests==2.31.0 # via pymatgen ruamel-yaml==0.18.5 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.11.4 # via pymatgen six==1.16.0 # via # latexcodec # pybtex # python-dateutil spglib==2.2.0 # via pymatgen sympy==1.12 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly tqdm==4.66.1 # via pymatgen typing-extensions==4.9.0 # via # emmet-core (setup.py) # pydantic # pydantic-core tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via requests ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.11_extras.txt0000644000175100001770000002214514551165444023766 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 # aiohttp==3.9.1 # via fsspec aiosignal==1.3.1 # via aiohttp annotated-types==0.6.0 # via pydantic ase==3.22.1 # via # chgnet # matcalc # matgl attrs==23.2.0 # via aiohttp bracex==2.4 # via wcmatch certifi==2023.11.17 # via # requests # sentry-sdk cfgv==3.4.0 # via pre-commit charset-normalizer==3.3.2 # via requests chgnet==0.3.3 # via emmet-core (setup.py) click==8.1.7 # via # mkdocs # mkdocstrings colorama==0.4.6 # via griffe contourpy==1.2.0 # via matplotlib coverage[toml]==7.4.0 # via # coverage # pytest-cov csscompressor==0.9.5 # via mkdocs-minify-plugin custodian==2023.10.9 # via emmet-core (setup.py) cycler==0.12.1 # via matplotlib cython==3.0.7 # via chgnet dgl==1.1.3 # via matgl distlib==0.3.8 # via virtualenv dnspython==2.4.2 # via pymongo filelock==3.13.1 # via # torch # triton # virtualenv flake8==7.0.0 # via emmet-core (setup.py) fonttools==4.47.0 # via matplotlib frozenlist==1.4.1 # via # aiohttp # aiosignal fsspec[http]==2023.12.2 # via # pytorch-lightning # torch future==0.18.3 # via # matminer # uncertainties ghp-import==2.1.0 # via mkdocs griffe==0.38.1 # via mkdocstrings-python h5py==3.10.0 # via phonopy htmlmin2==0.1.13 # via mkdocs-minify-plugin identify==2.5.33 # via pre-commit idna==3.6 # via # requests # yarl inflect==7.0.0 # via robocrys iniconfig==2.0.0 # via pytest jinja2==3.1.2 # via # emmet-core (setup.py) # mkdocs # mkdocs-material # mkdocstrings # torch joblib==1.3.2 # via # matcalc # pymatgen # pymatgen-analysis-diffusion # scikit-learn jsmin==3.0.1 # via mkdocs-minify-plugin kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex lightning-utilities==0.10.0 # via # pytorch-lightning # torchmetrics livereload==2.6.3 # via emmet-core (setup.py) markdown==3.5.1 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions markupsafe==2.1.3 # via # jinja2 # mkdocs # mkdocstrings matcalc==0.0.4 # via emmet-core (setup.py) matgl==0.9.1 # via emmet-core (setup.py) matminer==0.9.0 # via robocrys matplotlib==3.8.2 # via # ase # phonopy # pymatgen mccabe==0.7.0 # via flake8 mergedeep==1.3.4 # via mkdocs mkdocs==1.5.3 # via # emmet-core (setup.py) # mkdocs-autorefs # mkdocs-awesome-pages-plugin # mkdocs-markdownextradata-plugin # mkdocs-material # mkdocs-minify-plugin # mkdocstrings mkdocs-autorefs==0.5.0 # via mkdocstrings mkdocs-awesome-pages-plugin==2.9.2 # via emmet-core (setup.py) mkdocs-markdownextradata-plugin==0.2.5 # 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.7.2 # via emmet-core (setup.py) mkdocstrings[python]==0.24.0 # via # emmet-core (setup.py) # mkdocstrings-python mkdocstrings-python==1.8.0 # via mkdocstrings monty==2023.11.3 # via # custodian # emmet-core (setup.py) # matminer # pymatgen # robocrys mpmath==1.3.0 # via sympy multidict==6.0.4 # via # aiohttp # yarl mypy==1.8.0 # 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.2.1 # via # dgl # pymatgen # robocrys # torch nodeenv==1.8.0 # via pre-commit numpy==1.26.3 # via # ase # chgnet # contourpy # dgl # h5py # matminer # matplotlib # pandas # phonopy # pymatgen # pytorch-lightning # robocrys # scikit-learn # scipy # seekpath # shapely # spglib # 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==8.9.2.26 # 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.18.1 # via torch nvidia-nvjitlink-cu12==12.3.101 # via # nvidia-cusolver-cu12 # nvidia-cusparse-cu12 nvidia-nvtx-cu12==12.1.105 # via torch packaging==23.2 # via # lightning-utilities # matplotlib # mkdocs # plotly # pytest # pytorch-lightning # torchmetrics palettable==3.3.3 # via pymatgen pandas==1.5.3 # via # matminer # pymatgen pathspec==0.12.1 # via mkdocs phonopy==2.21.0 # via matcalc pillow==10.2.0 # via matplotlib platformdirs==4.1.0 # via # mkdocs # mkdocstrings # virtualenv plotly==5.18.0 # via pymatgen pluggy==1.3.0 # via pytest pre-commit==3.6.0 # via emmet-core (setup.py) psutil==5.9.7 # via # custodian # dgl pubchempy==1.0.4 # via robocrys pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen # robocrys pycodestyle==2.11.1 # via # emmet-core (setup.py) # flake8 pydantic==2.5.3 # via # emmet-core (setup.py) # inflect # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pydocstyle==6.3.0 # via emmet-core (setup.py) pyflakes==3.2.0 # via flake8 pygments==2.17.2 # via mkdocs-material pymatgen==2023.12.18 # via # chgnet # emmet-core (setup.py) # matcalc # matgl # matminer # pymatgen-analysis-alloys # pymatgen-analysis-diffusion # robocrys pymatgen-analysis-alloys==0.0.6 # via emmet-core (setup.py) pymatgen-analysis-diffusion==2023.8.15 # via emmet-core (setup.py) pymdown-extensions==10.7 # via # mkdocs-material # mkdocstrings pymongo==4.6.1 # via matminer pyparsing==3.1.1 # via matplotlib pytest==7.4.4 # via # emmet-core (setup.py) # pytest-cov pytest-cov==4.1.0 # via emmet-core (setup.py) python-dateutil==2.8.2 # via # ghp-import # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytorch-lightning==2.1.3 # via matgl pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via # mkdocs # mkdocs-markdownextradata-plugin # phonopy # pre-commit # pybtex # pymdown-extensions # pytorch-lightning # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs requests==2.31.0 # via # dgl # fsspec # matminer # pymatgen robocrys==0.2.8 # via emmet-core (setup.py) ruamel-yaml==0.18.5 # via # custodian # pymatgen # robocrys ruamel-yaml-clib==0.2.8 # via ruamel-yaml scikit-learn==1.3.2 # via matminer scipy==1.11.4 # via # ase # dgl # pymatgen # robocrys # scikit-learn seekpath==2.1.0 # via emmet-core (setup.py) sentry-sdk==1.39.1 # via custodian shapely==2.0.2 # via pymatgen-analysis-alloys six==1.16.0 # via # latexcodec # livereload # pybtex # python-dateutil snowballstemmer==2.2.0 # via pydocstyle spglib==2.2.0 # via # phonopy # pymatgen # robocrys # seekpath sympy==1.12 # via # matminer # pymatgen # torch tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly threadpoolctl==3.2.0 # via scikit-learn torch==2.1.2 # via # chgnet # matgl # pytorch-lightning # torchmetrics torchmetrics==1.2.1 # via pytorch-lightning tornado==6.4 # via livereload tqdm==4.66.1 # via # dgl # matminer # pymatgen # pytorch-lightning triton==2.1.0 # via torch types-requests==2.31.0.20240106 # via emmet-core (setup.py) types-setuptools==69.0.0.20240106 # via emmet-core (setup.py) typing-extensions==4.9.0 # via # emmet-core (setup.py) # inflect # lightning-utilities # mypy # pydantic # pydantic-core # pytorch-lightning # torch uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via # requests # sentry-sdk # types-requests virtualenv==20.25.0 # via pre-commit watchdog==3.0.0 # via mkdocs wcmatch==8.5 # via mkdocs-awesome-pages-plugin wincertstore==0.2 # via emmet-core (setup.py) yarl==1.9.4 # via aiohttp # The following packages are considered to be unsafe in a requirements file: # setuptools ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.9.txt0000644000175100001770000000437314551165444022332 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile --output-file=requirements/ubuntu-latest_py3.9.txt # annotated-types==0.6.0 # via pydantic certifi==2023.11.17 # via requests charset-normalizer==3.3.2 # via requests contourpy==1.2.0 # via matplotlib cycler==0.12.1 # via matplotlib fonttools==4.47.0 # via matplotlib future==0.18.3 # via uncertainties idna==3.6 # via requests importlib-resources==6.1.1 # via matplotlib joblib==1.3.2 # via pymatgen kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex matplotlib==3.8.2 # via pymatgen monty==2023.11.3 # via # emmet-core (setup.py) # pymatgen mpmath==1.3.0 # via sympy networkx==3.2.1 # via pymatgen numpy==1.26.3 # via # contourpy # matplotlib # pandas # pymatgen # scipy # spglib packaging==23.2 # via # matplotlib # plotly palettable==3.3.3 # via pymatgen pandas==2.1.4 # via pymatgen pillow==10.2.0 # via matplotlib plotly==5.18.0 # via pymatgen pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen pydantic==2.5.3 # via # emmet-core (setup.py) # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pymatgen==2023.12.18 # via emmet-core (setup.py) pyparsing==3.1.1 # via matplotlib python-dateutil==2.8.2 # via # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via pybtex requests==2.31.0 # via pymatgen ruamel-yaml==0.18.5 # via pymatgen ruamel-yaml-clib==0.2.8 # via ruamel-yaml scipy==1.11.4 # via pymatgen six==1.16.0 # via # latexcodec # pybtex # python-dateutil spglib==2.2.0 # via pymatgen sympy==1.12 # via pymatgen tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly tqdm==4.66.1 # via pymatgen typing-extensions==4.9.0 # via # emmet-core (setup.py) # pydantic # pydantic-core tzdata==2023.4 # via pandas uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via requests zipp==3.17.0 # via importlib-resources ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/requirements/ubuntu-latest_py3.9_extras.txt0000644000175100001770000002274114551165444023717 0ustar00runnerdocker# # This file is autogenerated by pip-compile with Python 3.9 # by the following command: # # pip-compile --all-extras --output-file=requirements/ubuntu-latest_py3.9_extras.txt # aiohttp==3.9.1 # via fsspec aiosignal==1.3.1 # via aiohttp annotated-types==0.6.0 # via pydantic ase==3.22.1 # via # chgnet # matcalc # matgl async-timeout==4.0.3 # via aiohttp attrs==23.2.0 # via aiohttp bracex==2.4 # via wcmatch certifi==2023.11.17 # via # requests # sentry-sdk cfgv==3.4.0 # via pre-commit charset-normalizer==3.3.2 # via requests chgnet==0.3.3 # via emmet-core (setup.py) click==8.1.7 # via # mkdocs # mkdocstrings colorama==0.4.6 # via griffe contourpy==1.2.0 # via matplotlib coverage[toml]==7.4.0 # via # coverage # pytest-cov csscompressor==0.9.5 # via mkdocs-minify-plugin custodian==2023.10.9 # via emmet-core (setup.py) cycler==0.12.1 # via matplotlib cython==3.0.7 # via chgnet dgl==1.1.3 # via matgl distlib==0.3.8 # via virtualenv dnspython==2.4.2 # via pymongo exceptiongroup==1.2.0 # via pytest filelock==3.13.1 # via # torch # triton # virtualenv flake8==7.0.0 # via emmet-core (setup.py) fonttools==4.47.0 # via matplotlib frozenlist==1.4.1 # via # aiohttp # aiosignal fsspec[http]==2023.12.2 # via # pytorch-lightning # torch future==0.18.3 # via # matminer # uncertainties ghp-import==2.1.0 # via mkdocs griffe==0.38.1 # via mkdocstrings-python h5py==3.10.0 # via phonopy htmlmin2==0.1.13 # via mkdocs-minify-plugin identify==2.5.33 # via pre-commit idna==3.6 # via # requests # yarl importlib-metadata==7.0.1 # via # markdown # mkdocs # mkdocstrings importlib-resources==6.1.1 # via matplotlib inflect==7.0.0 # via robocrys iniconfig==2.0.0 # via pytest jinja2==3.1.2 # via # emmet-core (setup.py) # mkdocs # mkdocs-material # mkdocstrings # torch joblib==1.3.2 # via # matcalc # pymatgen # pymatgen-analysis-diffusion # scikit-learn jsmin==3.0.1 # via mkdocs-minify-plugin kiwisolver==1.4.5 # via matplotlib latexcodec==2.0.1 # via pybtex lightning-utilities==0.10.0 # via # pytorch-lightning # torchmetrics livereload==2.6.3 # via emmet-core (setup.py) markdown==3.5.1 # via # mkdocs # mkdocs-autorefs # mkdocs-material # mkdocstrings # pymdown-extensions markupsafe==2.1.3 # via # jinja2 # mkdocs # mkdocstrings matcalc==0.0.4 # via emmet-core (setup.py) matgl==0.9.1 # via emmet-core (setup.py) matminer==0.9.0 # via robocrys matplotlib==3.8.2 # via # ase # phonopy # pymatgen mccabe==0.7.0 # via flake8 mergedeep==1.3.4 # via mkdocs mkdocs==1.5.3 # via # emmet-core (setup.py) # mkdocs-autorefs # mkdocs-awesome-pages-plugin # mkdocs-markdownextradata-plugin # mkdocs-material # mkdocs-minify-plugin # mkdocstrings mkdocs-autorefs==0.5.0 # via mkdocstrings mkdocs-awesome-pages-plugin==2.9.2 # via emmet-core (setup.py) mkdocs-markdownextradata-plugin==0.2.5 # 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.7.2 # via emmet-core (setup.py) mkdocstrings[python]==0.24.0 # via # emmet-core (setup.py) # mkdocstrings-python mkdocstrings-python==1.8.0 # via mkdocstrings monty==2023.11.3 # via # custodian # emmet-core (setup.py) # matminer # pymatgen # robocrys mpmath==1.3.0 # via sympy multidict==6.0.4 # via # aiohttp # yarl mypy==1.8.0 # 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.2.1 # via # dgl # pymatgen # robocrys # torch nodeenv==1.8.0 # via pre-commit numpy==1.26.3 # via # ase # chgnet # contourpy # dgl # h5py # matminer # matplotlib # pandas # phonopy # pymatgen # pytorch-lightning # robocrys # scikit-learn # scipy # seekpath # shapely # spglib # 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==8.9.2.26 # 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.18.1 # via torch nvidia-nvjitlink-cu12==12.3.101 # via # nvidia-cusolver-cu12 # nvidia-cusparse-cu12 nvidia-nvtx-cu12==12.1.105 # via torch packaging==23.2 # via # lightning-utilities # matplotlib # mkdocs # plotly # pytest # pytorch-lightning # torchmetrics palettable==3.3.3 # via pymatgen pandas==1.5.3 # via # matminer # pymatgen pathspec==0.12.1 # via mkdocs phonopy==2.21.0 # via matcalc pillow==10.2.0 # via matplotlib platformdirs==4.1.0 # via # mkdocs # mkdocstrings # virtualenv plotly==5.18.0 # via pymatgen pluggy==1.3.0 # via pytest pre-commit==3.6.0 # via emmet-core (setup.py) psutil==5.9.7 # via # custodian # dgl pubchempy==1.0.4 # via robocrys pybtex==0.24.0 # via # emmet-core (setup.py) # pymatgen # robocrys pycodestyle==2.11.1 # via # emmet-core (setup.py) # flake8 pydantic==2.5.3 # via # emmet-core (setup.py) # inflect # pydantic-settings pydantic-core==2.14.6 # via pydantic pydantic-settings==2.1.0 # via emmet-core (setup.py) pydocstyle==6.3.0 # via emmet-core (setup.py) pyflakes==3.2.0 # via flake8 pygments==2.17.2 # via mkdocs-material pymatgen==2023.12.18 # via # chgnet # emmet-core (setup.py) # matcalc # matgl # matminer # pymatgen-analysis-alloys # pymatgen-analysis-diffusion # robocrys pymatgen-analysis-alloys==0.0.6 # via emmet-core (setup.py) pymatgen-analysis-diffusion==2023.8.15 # via emmet-core (setup.py) pymdown-extensions==10.7 # via # mkdocs-material # mkdocstrings pymongo==4.6.1 # via matminer pyparsing==3.1.1 # via matplotlib pytest==7.4.4 # via # emmet-core (setup.py) # pytest-cov pytest-cov==4.1.0 # via emmet-core (setup.py) python-dateutil==2.8.2 # via # ghp-import # matplotlib # pandas python-dotenv==1.0.0 # via pydantic-settings pytorch-lightning==2.1.3 # via matgl pytz==2023.3.post1 # via pandas pyyaml==6.0.1 # via # mkdocs # mkdocs-markdownextradata-plugin # phonopy # pre-commit # pybtex # pymdown-extensions # pytorch-lightning # pyyaml-env-tag pyyaml-env-tag==0.1 # via mkdocs requests==2.31.0 # via # dgl # fsspec # matminer # pymatgen robocrys==0.2.8 # via emmet-core (setup.py) ruamel-yaml==0.18.5 # via # custodian # pymatgen # robocrys ruamel-yaml-clib==0.2.8 # via ruamel-yaml scikit-learn==1.3.2 # via matminer scipy==1.11.4 # via # ase # dgl # pymatgen # robocrys # scikit-learn seekpath==2.1.0 # via emmet-core (setup.py) sentry-sdk==1.39.1 # via custodian shapely==2.0.2 # via pymatgen-analysis-alloys six==1.16.0 # via # latexcodec # livereload # pybtex # python-dateutil snowballstemmer==2.2.0 # via pydocstyle spglib==2.2.0 # via # phonopy # pymatgen # robocrys # seekpath sympy==1.12 # via # matminer # pymatgen # torch tabulate==0.9.0 # via pymatgen tenacity==8.2.3 # via plotly threadpoolctl==3.2.0 # via scikit-learn tomli==2.0.1 # via # coverage # mypy # pytest torch==2.1.2 # via # chgnet # matgl # pytorch-lightning # torchmetrics torchmetrics==1.2.1 # via pytorch-lightning tornado==6.4 # via livereload tqdm==4.66.1 # via # dgl # matminer # pymatgen # pytorch-lightning triton==2.1.0 # via torch types-requests==2.31.0.20240106 # via emmet-core (setup.py) types-setuptools==69.0.0.20240106 # via emmet-core (setup.py) typing-extensions==4.9.0 # via # emmet-core (setup.py) # inflect # lightning-utilities # mkdocstrings # mypy # pydantic # pydantic-core # pytorch-lightning # torch uncertainties==3.1.7 # via pymatgen urllib3==2.1.0 # via # requests # sentry-sdk # types-requests virtualenv==20.25.0 # via pre-commit watchdog==3.0.0 # via mkdocs wcmatch==8.5 # via mkdocs-awesome-pages-plugin wincertstore==0.2 # via emmet-core (setup.py) yarl==1.9.4 # via aiohttp zipp==3.17.0 # via # importlib-metadata # importlib-resources # The following packages are considered to be unsafe in a requirements file: # setuptools ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1705306921.9112563 emmet-core-0.76.2/setup.cfg0000644000175100001770000000004614551165452015101 0ustar00runnerdocker[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/setup.py0000644000175100001770000000366114551165444015001 0ustar00runnerdockerfrom setuptools import find_namespace_packages, setup 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=open("../README.md").read(), # noqa: SIM115 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.subtrates": ["*.json"], }, include_package_data=True, install_requires=[ "pymatgen>=2023.10.11", "monty>=2023.9.25", "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-diffusion>=2023.8.15", "pymatgen-analysis-alloys>=0.0.3", ], "ml": ["chgnet", "matgl"], "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=1705306921.9112563 emmet-core-0.76.2/tests/0000755000175100001770000000000014551165452014422 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/__init__.py0000644000175100001770000000056014551165444016535 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=1705306916.0 emmet-core-0.76.2/tests/conftest.py0000644000175100001770000002110514551165444016621 0ustar00runnerdockerfrom pathlib import Path import pytest @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. """ 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=1705306916.0 emmet-core-0.76.2/tests/conftest_qchem.py0000644000175100001770000003505014551165444020002 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_nfo": "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_nfo": "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=1705306921.9112563 emmet-core-0.76.2/tests/mobility/0000755000175100001770000000000014551165452016252 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/mobility/test_migrationgraph.py0000644000175100001770000001025514551165444022702 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 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 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=1705306921.9112563 emmet-core-0.76.2/tests/molecules/0000755000175100001770000000000014551165452016412 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/molecules/__init__.py0000644000175100001770000000000014551165444020512 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/molecules/test_atomic.py0000644000175100001770000000552114551165444021303 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_bonds.py0000644000175100001770000000377114551165444021141 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_metal_binding.py0000644000175100001770000000535714551165444022632 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_mol_thermo.py0000644000175100001770000000350614551165444022175 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_orbitals.py0000644000175100001770000000374214551165444021651 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_redox.py0000644000175100001770000000376314551165444021156 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_summary.py0000644000175100001770000000147314551165444021526 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=1705306916.0 emmet-core-0.76.2/tests/molecules/test_vibration.py0000644000175100001770000000202114551165444022014 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=1705306921.9112563 emmet-core-0.76.2/tests/qchem/0000755000175100001770000000000014551165452015517 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/qchem/__init__.py0000644000175100001770000000000014551165444017617 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/qchem/test_molecules.py0000644000175100001770000000411114551165444021116 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=1705306916.0 emmet-core-0.76.2/tests/qchem/test_qchem.py0000644000175100001770000001325314551165444020232 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=1705306916.0 emmet-core-0.76.2/tests/test_absorption.py0000644000175100001770000000366014551165444020221 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=1705306916.0 emmet-core-0.76.2/tests/test_calculation.py0000644000175100001770000001506014551165444020334 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_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=1705306916.0 emmet-core-0.76.2/tests/test_chemenv.py0000644000175100001770000000216014551165444017460 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=1705306916.0 emmet-core-0.76.2/tests/test_elasticity.py0000644000175100001770000000507414551165444020214 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=1705306916.0 emmet-core-0.76.2/tests/test_electrodes.py0000644000175100001770000001103614551165444020166 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=1705306916.0 emmet-core-0.76.2/tests/test_electronic_structure.py0000644000175100001770000000554214551165444022311 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=1705306916.0 emmet-core-0.76.2/tests/test_magnetism.py0000644000175100001770000000171014551165444020017 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=1705306916.0 emmet-core-0.76.2/tests/test_ml.py0000644000175100001770000000403614551165444016447 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=1705306916.0 emmet-core-0.76.2/tests/test_molecule_metadata.py0000644000175100001770000000326514551165444021507 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=1705306916.0 emmet-core-0.76.2/tests/test_mpid.py0000644000175100001770000000321614551165444016767 0ustar00runnerdockerfrom emmet.core.mpid import MPID, MPculeID 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) 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=1705306916.0 emmet-core-0.76.2/tests/test_optimade.py0000644000175100001770000000130014551165444017630 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=1705306916.0 emmet-core-0.76.2/tests/test_oxidation_states.py0000644000175100001770000000100514551165444021411 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=1705306916.0 emmet-core-0.76.2/tests/test_polar.py0000644000175100001770000002267514551165444017165 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=1705306916.0 emmet-core-0.76.2/tests/test_provenance.py0000644000175100001770000000317614551165444020203 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=1705306916.0 emmet-core-0.76.2/tests/test_qc_task.py0000644000175100001770000000577414551165444017476 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"} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/test_robocrys.py0000644000175100001770000000105714551165444017701 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=1705306916.0 emmet-core-0.76.2/tests/test_settings.py0000644000175100001770000000270314551165444017676 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=1705306916.0 emmet-core-0.76.2/tests/test_structure_group.py0000644000175100001770000000356514551165444021321 0ustar00runnerdockerimport pytest from monty.serialization import loadfn from pymatgen.core import Composition from emmet.core.structure_group import StructureGroupDoc @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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/test_structure_metadata.py0000644000175100001770000000375014551165444021741 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=1705306916.0 emmet-core-0.76.2/tests/test_task.py0000644000175100001770000001140314551165444016775 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): from monty.json import jsanitize from pymatgen.entries.computed_entries import ComputedEntry 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}" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/test_thermo.py0000644000175100001770000001110414551165444017327 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=1705306916.0 emmet-core-0.76.2/tests/test_utils.py0000644000175100001770000000426414551165444017202 0ustar00runnerdockerimport datetime import json import numpy as np import pytest from bson.objectid import ObjectId from monty.json import MSONable from emmet.core.utils import DocEnum, ValueEnum, jsanitize 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(): class TempEnum(ValueEnum): A = "A" B = "B" assert str(TempEnum.A) == "A" assert str(TempEnum.B) == "B" 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=1705306916.0 emmet-core-0.76.2/tests/test_xrd.py0000644000175100001770000000230214551165444016626 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=1705306921.9112563 emmet-core-0.76.2/tests/vasp/0000755000175100001770000000000014551165452015373 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1705306916.0 emmet-core-0.76.2/tests/vasp/test_materials.py0000644000175100001770000000241214551165444020765 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=1705306916.0 emmet-core-0.76.2/tests/vasp/test_vasp.py0000644000175100001770000001073014551165444017757 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.vasp.task_valid import TaskDocument from emmet.core.vasp.validation import ValidationDoc, _potcar_hash_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 [TaskDocument(**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_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 TaskDocument(**data) def test_ldau(task_ldau): task_ldau.input.is_hubbard = True assert task_ldau.run_type == RunType.GGA_U assert ValidationDoc.from_task_doc(task_ldau).valid is False def test_ldau_validation(test_dir): with open(test_dir / "old_aflow_ggau_task.json") as f: data = json.load(f) task = TaskDocument(**data) assert task.run_type == "GGA+U" valid = ValidationDoc.from_task_doc(task) assert valid.valid def test_potcar_hash_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"}) # First check: generate hashes from POTCARs in TaskDoc, check should pass calc_type = str(task_doc.calc_type) expected_hashes = {calc_type: {}} try: for spec in task_doc.calcs_reversed[0]["input"]["potcar_spec"]: symbol = spec["titel"].split(" ")[1] expected_hashes[calc_type][ symbol ] = PotcarSingle.from_symbol_and_functional( symbol=symbol, functional="PBE" )._summary_stats assert not _potcar_hash_check(task_doc, expected_hashes) # Second check: remove POTCAR from expected_hashes, check should fail missing_hashes = {calc_type: {**expected_hashes[calc_type]}} first_element = list(missing_hashes[calc_type])[0] missing_hashes[calc_type].pop(first_element) assert _potcar_hash_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]["stats"]["data"]: wrong_hashes[calc_type][first_element]["stats"]["data"][key] *= 1.1 assert _potcar_hash_check(task_doc, wrong_hashes) except (OSError, ValueError): # missing Pymatgen POTCARs, cannot perform test assert True