diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/source/setup.rst b/docs/source/setup.rst new file mode 100644 index 00000000..552eb49d --- /dev/null +++ b/docs/source/setup.rst @@ -0,0 +1,7 @@ +setup module +============ + +.. automodule:: setup + :members: + :undoc-members: + :show-inheritance: diff --git a/doctrees/changelog.doctree b/doctrees/changelog.doctree new file mode 100644 index 00000000..6932afa2 Binary files /dev/null and b/doctrees/changelog.doctree differ diff --git a/doctrees/citing.doctree b/doctrees/citing.doctree new file mode 100644 index 00000000..182972f9 Binary files /dev/null and b/doctrees/citing.doctree differ diff --git a/doctrees/environment.pickle b/doctrees/environment.pickle new file mode 100644 index 00000000..6483192f Binary files /dev/null and b/doctrees/environment.pickle differ diff --git a/doctrees/index.doctree b/doctrees/index.doctree new file mode 100644 index 00000000..80cb0cee Binary files /dev/null and b/doctrees/index.doctree differ diff --git a/doctrees/installation/configuration.doctree b/doctrees/installation/configuration.doctree new file mode 100644 index 00000000..47bcc6d5 Binary files /dev/null and b/doctrees/installation/configuration.doctree differ diff --git a/doctrees/installation/dependencies.doctree b/doctrees/installation/dependencies.doctree new file mode 100644 index 00000000..2b03ec5f Binary files /dev/null and b/doctrees/installation/dependencies.doctree differ diff --git a/doctrees/installation/index.doctree b/doctrees/installation/index.doctree new file mode 100644 index 00000000..434150d1 Binary files /dev/null and b/doctrees/installation/index.doctree differ diff --git a/doctrees/installation/test.doctree b/doctrees/installation/test.doctree new file mode 100644 index 00000000..163c7f16 Binary files /dev/null and b/doctrees/installation/test.doctree differ diff --git a/doctrees/keywords.doctree b/doctrees/keywords.doctree new file mode 100644 index 00000000..a564b5ab Binary files /dev/null and b/doctrees/keywords.doctree differ diff --git a/doctrees/license.doctree b/doctrees/license.doctree new file mode 100644 index 00000000..4dd56130 Binary files /dev/null and b/doctrees/license.doctree differ diff --git a/doctrees/mispr.common.doctree b/doctrees/mispr.common.doctree new file mode 100644 index 00000000..f2b9e9b4 Binary files /dev/null and b/doctrees/mispr.common.doctree differ diff --git a/doctrees/mispr.doctree b/doctrees/mispr.doctree new file mode 100644 index 00000000..4c45f249 Binary files /dev/null and b/doctrees/mispr.doctree differ diff --git a/doctrees/mispr.gaussian.doctree b/doctrees/mispr.gaussian.doctree new file mode 100644 index 00000000..e036081d Binary files /dev/null and b/doctrees/mispr.gaussian.doctree differ diff --git a/doctrees/mispr.gaussian.firetasks.doctree b/doctrees/mispr.gaussian.firetasks.doctree new file mode 100644 index 00000000..413c6224 Binary files /dev/null and b/doctrees/mispr.gaussian.firetasks.doctree differ diff --git a/doctrees/mispr.gaussian.fireworks.doctree b/doctrees/mispr.gaussian.fireworks.doctree new file mode 100644 index 00000000..d7feaa44 Binary files /dev/null and b/doctrees/mispr.gaussian.fireworks.doctree differ diff --git a/doctrees/mispr.gaussian.utilities.doctree b/doctrees/mispr.gaussian.utilities.doctree new file mode 100644 index 00000000..a194fcc2 Binary files /dev/null and b/doctrees/mispr.gaussian.utilities.doctree differ diff --git a/doctrees/mispr.gaussian.workflows.base.doctree b/doctrees/mispr.gaussian.workflows.base.doctree new file mode 100644 index 00000000..654973c2 Binary files /dev/null and b/doctrees/mispr.gaussian.workflows.base.doctree differ diff --git a/doctrees/mispr.gaussian.workflows.doctree b/doctrees/mispr.gaussian.workflows.doctree new file mode 100644 index 00000000..ce6ae330 Binary files /dev/null and b/doctrees/mispr.gaussian.workflows.doctree differ diff --git a/doctrees/mispr.hybrid.doctree b/doctrees/mispr.hybrid.doctree new file mode 100644 index 00000000..2dcb38f2 Binary files /dev/null and b/doctrees/mispr.hybrid.doctree differ diff --git a/doctrees/mispr.hybrid.firetasks.doctree b/doctrees/mispr.hybrid.firetasks.doctree new file mode 100644 index 00000000..f5481c15 Binary files /dev/null and b/doctrees/mispr.hybrid.firetasks.doctree differ diff --git a/doctrees/mispr.hybrid.workflows.doctree b/doctrees/mispr.hybrid.workflows.doctree new file mode 100644 index 00000000..bba258f8 Binary files /dev/null and b/doctrees/mispr.hybrid.workflows.doctree differ diff --git a/doctrees/mispr.lammps.doctree b/doctrees/mispr.lammps.doctree new file mode 100644 index 00000000..13143831 Binary files /dev/null and b/doctrees/mispr.lammps.doctree differ diff --git a/doctrees/mispr.lammps.firetasks.doctree b/doctrees/mispr.lammps.firetasks.doctree new file mode 100644 index 00000000..21a0c99f Binary files /dev/null and b/doctrees/mispr.lammps.firetasks.doctree differ diff --git a/doctrees/mispr.lammps.fireworks.doctree b/doctrees/mispr.lammps.fireworks.doctree new file mode 100644 index 00000000..be0d9bfd Binary files /dev/null and b/doctrees/mispr.lammps.fireworks.doctree differ diff --git a/doctrees/mispr.lammps.tests.doctree b/doctrees/mispr.lammps.tests.doctree new file mode 100644 index 00000000..e24eb326 Binary files /dev/null and b/doctrees/mispr.lammps.tests.doctree differ diff --git a/doctrees/mispr.lammps.utilities.doctree b/doctrees/mispr.lammps.utilities.doctree new file mode 100644 index 00000000..8a9feec6 Binary files /dev/null and b/doctrees/mispr.lammps.utilities.doctree differ diff --git a/doctrees/mispr.lammps.workflows.doctree b/doctrees/mispr.lammps.workflows.doctree new file mode 100644 index 00000000..e508bb27 Binary files /dev/null and b/doctrees/mispr.lammps.workflows.doctree differ diff --git a/doctrees/modules.doctree b/doctrees/modules.doctree new file mode 100644 index 00000000..8e30b6de Binary files /dev/null and b/doctrees/modules.doctree differ diff --git a/doctrees/overview.doctree b/doctrees/overview.doctree new file mode 100644 index 00000000..8f1cbd8b Binary files /dev/null and b/doctrees/overview.doctree differ diff --git a/doctrees/resources/faq.doctree b/doctrees/resources/faq.doctree new file mode 100644 index 00000000..e407c858 Binary files /dev/null and b/doctrees/resources/faq.doctree differ diff --git a/doctrees/resources/resources.doctree b/doctrees/resources/resources.doctree new file mode 100644 index 00000000..c0a4c0c0 Binary files /dev/null and b/doctrees/resources/resources.doctree differ diff --git a/doctrees/setup.doctree b/doctrees/setup.doctree new file mode 100644 index 00000000..189324f5 Binary files /dev/null and b/doctrees/setup.doctree differ diff --git a/doctrees/workflows/basics.doctree b/doctrees/workflows/basics.doctree new file mode 100644 index 00000000..785cc6ae Binary files /dev/null and b/doctrees/workflows/basics.doctree differ diff --git a/doctrees/workflows/custom.doctree b/doctrees/workflows/custom.doctree new file mode 100644 index 00000000..db747459 Binary files /dev/null and b/doctrees/workflows/custom.doctree differ diff --git a/doctrees/workflows/supported.doctree b/doctrees/workflows/supported.doctree new file mode 100644 index 00000000..e81c5455 Binary files /dev/null and b/doctrees/workflows/supported.doctree differ diff --git a/doctrees/workflows/tutorials.doctree b/doctrees/workflows/tutorials.doctree new file mode 100644 index 00000000..8e413367 Binary files /dev/null and b/doctrees/workflows/tutorials.doctree differ diff --git a/html/.buildinfo b/html/.buildinfo new file mode 100644 index 00000000..dfa58080 --- /dev/null +++ b/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 53aa0c497316ff79c248f7e4f876c526 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/html/_downloads/06920989aa58eec95718018206509e48/nmr_citation.bib b/html/_downloads/06920989aa58eec95718018206509e48/nmr_citation.bib new file mode 100644 index 00000000..af6f0ea5 --- /dev/null +++ b/html/_downloads/06920989aa58eec95718018206509e48/nmr_citation.bib @@ -0,0 +1,10 @@ +@article{atwi2022automated, + title={An automated framework for high-throughput predictions of NMR chemical shifts within liquid solutions}, + author={Atwi, Rasha and Chen, Ying and Han, Kee Sung and Mueller, Karl T and Murugesan, Vijayakumar and Rajput, Nav Nidhi}, + journal={Nature Computational Science}, + volume={2}, + number={2}, + pages={112--122}, + year={2022}, + publisher={Nature Publishing Group} +} diff --git a/html/_downloads/d67a679cb2e669df06832fe26664fc83/esp_tutorial.py b/html/_downloads/d67a679cb2e669df06832fe26664fc83/esp_tutorial.py new file mode 100644 index 00000000..3ab646df --- /dev/null +++ b/html/_downloads/d67a679cb2e669df06832fe26664fc83/esp_tutorial.py @@ -0,0 +1,16 @@ +from fireworks import LaunchPad + +from mispr.gaussian.workflows.base.esp import get_esp_charges + +lpad = LaunchPad.auto_load() + +wf, _ = get_esp_charges( + mol_operation_type="get_from_pubchem", # (1)! + mol="monoglyme", + format_chk=True, + save_to_db=True, + save_to_file=True, + additional_prop_doc_fields={"name": "monoglyme"}, + tag="mispr_tutorial", +) +lpad.add_wf(wf) # (2)! diff --git a/html/_downloads/fdd29a5720b48392c0789affcc4fb5e8/mispr_citation.bib b/html/_downloads/fdd29a5720b48392c0789affcc4fb5e8/mispr_citation.bib new file mode 100644 index 00000000..3d60a500 --- /dev/null +++ b/html/_downloads/fdd29a5720b48392c0789affcc4fb5e8/mispr_citation.bib @@ -0,0 +1,5 @@ +@article{atwi2022mispr, + title={MISPR: An automated infrastructure for high-throughput DFT and MD simulations}, + author={Atwi, Rasha and Bliss, Matthew and Makeev, Maxim and Rajput, Nav Nidhi}, + year={2022} +} diff --git a/html/_images/analysis.png b/html/_images/analysis.png new file mode 100644 index 00000000..2c8fa034 Binary files /dev/null and b/html/_images/analysis.png differ diff --git a/html/_images/convergence.png b/html/_images/convergence.png new file mode 100644 index 00000000..a0abc66c Binary files /dev/null and b/html/_images/convergence.png differ diff --git a/html/_images/document.png b/html/_images/document.png new file mode 100644 index 00000000..4a59e8ef Binary files /dev/null and b/html/_images/document.png differ diff --git a/html/_images/overview.png b/html/_images/overview.png new file mode 100644 index 00000000..da7be327 Binary files /dev/null and b/html/_images/overview.png differ diff --git a/html/_images/summary.jpeg b/html/_images/summary.jpeg new file mode 100644 index 00000000..e4ae3800 Binary files /dev/null and b/html/_images/summary.jpeg differ diff --git a/html/_images/workflow.png b/html/_images/workflow.png new file mode 100644 index 00000000..e124bfdb Binary files /dev/null and b/html/_images/workflow.png differ diff --git a/html/_modules/index.html b/html/_modules/index.html new file mode 100644 index 00000000..e56a2c69 --- /dev/null +++ b/html/_modules/index.html @@ -0,0 +1,772 @@ + + + + + + + + + + + + + + + + Overview: module code - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/common/pubchem.html b/html/_modules/mispr/common/pubchem.html new file mode 100644 index 00000000..7a471c18 --- /dev/null +++ b/html/_modules/mispr/common/pubchem.html @@ -0,0 +1,832 @@ + + + + + + + + + + + + + + + + mispr.common.pubchem - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.common.pubchem

+"""Implement a core class PubChemRunner for retrieving molecules from the PubChem
+database using a molecule name as a query criteria."""
+
+import os
+
+import pubchempy as pcp
+
+from pymatgen.core.structure import Molecule
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Aug 2022"
+__version__ = "0.0.4"
+
+
+
[docs]class PubChemRunner: + """ + Wrapper for retrieving molecules from PubChem database. + """ + + def __init__(self, abbreviation, working_dir=None): + """ + Args: + abbreviation (str): Abbreviation to be used when saving molecule file. + working_dir (str, optional): Working directory for saving the molecule file + in; will use the current working directory if not specified. + """ + self.abbreviation = abbreviation + self.working_dir = working_dir or os.getcwd() + self.cid = None + +
[docs] def get_mol(self, name, save_to_file=True, fmt="pdb", cleanup=True): + """ + Wrapper function that searches for a molecule in the PubChem database, downloads + it in the form of an SDF file, and converts the file to a pymatgen ``Molecule`` + object. + + Args: + name (str): Name of the molecule to use for searching PubChem. + save_to_file (bool, optional): Whether to save the ``Molecule`` object to a + file. Defaults to ``True``. + fmt (str, optional): Molecule file format if ``save_to_file`` is ``True``; + defaults to "pdb". + cleanup (bool, optional): Whether to remove the intermediate sdf file. + + Returns: + Molecule: pymatgen ``Molecule`` object. + """ + self.download_sdf(name) + molecule = self.convert_sdf_to_mol(save_to_file, fmt) + if cleanup: + self.cleanup() + return molecule
+ +
[docs] def download_sdf(self, name): + """ + Download an SDF file from PubChem using a common name for the molecule as an + identifier. + + Args: + name (str): Name of the molecule to use for searching PubChem. + """ + cids = pcp.get_cids(name, record_type="3d") + if cids: + self.cid = cids[0] + pcp.download( + outformat="SDF", + path=f"{self.working_dir}/{self.abbreviation}_{self.cid}.sdf", + identifier=self.cid, + record_type="3d", + overwrite=True, + ) + else: + raise ValueError("No matching molecule found in the PubChem database")
+ +
[docs] def convert_sdf_to_mol(self, save_to_file, fmt): + """ + Convert an SDF file to a pymatgen ``Molecule`` object. + + Args: + save_to_file (bool): Whether to save the ``Molecule`` object to a file. + fmt (str): Molecule file format if ``save_to_file`` is ``True``. + + Returns: + Molecule: pymatgen ``Molecule`` object. + """ + mol = Molecule.from_file( + f"{self.working_dir}/{self.abbreviation}_{self.cid}.sdf" + ) + if save_to_file: + mol.to(fmt, f"{self.working_dir}/{self.abbreviation}_{self.cid}.{fmt}") + return mol
+ +
[docs] def cleanup(self): + """ + Delete the sdf file downloaded from PubChem. + """ + os.remove(f"{self.working_dir}/{self.abbreviation}_{self.cid}.sdf")
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/database.html b/html/_modules/mispr/gaussian/database.html new file mode 100644 index 00000000..38e9d79a --- /dev/null +++ b/html/_modules/mispr/gaussian/database.html @@ -0,0 +1,1241 @@ + + + + + + + + + + + + + + + + mispr.gaussian.database - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.database

+"""Define the Gaussian database class."""
+
+import ssl
+import sys
+import json
+import logging
+import datetime
+
+from abc import abstractmethod
+
+import pandas as pd
+
+from pymongo import ASCENDING, MongoClient
+from monty.serialization import loadfn
+
+from pymatgen.core.structure import Molecule
+from pymatgen.analysis.molecule_matcher import MoleculeMatcher
+
+from mispr import __version__ as infrastructure_version
+from mispr.gaussian.utilities.metadata import get_chem_schema
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger()
+ch = logging.StreamHandler(stream=sys.stdout)
+logger.addHandler(ch)
+logger.setLevel(20)
+
+
+
[docs]class GaussianCalcDb: + """ + Class to help manage database insertions of molecules and Gaussian calculations. + """ + + def __init__( + self, + host, + port=None, + name=None, + username=None, + password=None, + uri_mode=False, + **kwargs + ): + self.host = host + self.db_name = name + self.user = username + self.password = password + self.port = int(port) if port else None + try: + if uri_mode: + self.connection = MongoClient(host) + dbname = host.split("/")[-1].split("?")[ + 0 + ] # parse URI to extract dbname + self.db = self.connection[dbname] + else: + self.connection = MongoClient( + self.host, + self.port, + ssl=kwargs.get("ssl", False), + ssl_ca_certs=kwargs.get("ssl_ca_certs"), + ssl_certfile=kwargs.get("ssl_certfile"), + ssl_keyfile=kwargs.get("ssl_keyfile"), + ssl_pem_passphrase=kwargs.get("ssl_pem_passphrase"), + ssl_cert_reqs=kwargs.get("ssl_cert_reqs", ssl.CERT_NONE), + username=username, + password=password, + authsource=kwargs.get("authsource"), + ) + self.db = self.connection[self.db_name] + except: + logger.error("Mongodb connection failed") + raise Exception + try: + if self.user: + self.db.authenticate( + self.user, self.password, source=kwargs.get("authsource", None) + ) + except: + logger.error("Mongodb authentication failed") + raise ValueError + self.molecules = self.db["molecules"] + self.functional_groups = self.db["functional_groups"] + self.derived_molecules = self.db["derived_molecules"] + self.runs = self.db["runs"] + + self.build_indexes() + +
[docs] @abstractmethod + def build_indexes(self, background=True): + """ + Build indexes for the database. + + Args: + background (bool, optional): If ``True``, this index should be created. + """ + self.molecules.create_index("inchi", unique=False, background=background) + self.molecules.create_index("smiles", unique=True, background=background) + self.molecules.create_index( + "formula_alphabetical", unique=False, background=background + ) + self.molecules.create_index("chemsys", unique=False, background=background) + self.functional_groups.create_index("name", unique=True, background=background) + self.derived_molecules.create_index( + [ + ("inchi", ASCENDING), + ("smiles", ASCENDING), + ("formula_alphabetical", ASCENDING), + ("chemsys", ASCENDING), + ], + unique=False, + background=background, + ) + self.runs.create_index( + [ + ("inchi", ASCENDING), + ("smiles", ASCENDING), + ("formula_alphabetical", ASCENDING), + ("chemsys", ASCENDING), + ("type", ASCENDING), + ("functional", ASCENDING), + ("basis", ASCENDING), + ("phase", ASCENDING), + ("tag", ASCENDING), + ], + unique=False, + background=background, + )
+ +
[docs] def query_molecules(self, query): + """ + Query the molecules collection. + + Args: + query (dict): A query document that selects which documents to include in + the result set; e.g. keys can be inchi, smiles, chemsys, etc. + + Returns: + pd.DataFrame: A dataframe of documents that match the query. + """ + projection = { + "inchi": 1, + "smiles": 1, + "formula": 1, + "formula_pretty": 1, + "formula_anonymous": 1, + "formula_alphabetical": 1, + "chemsys": 1, + "nsites": 1, + "nelements": 1, + "is_ordered": 1, + "is_valid": 1, + } + return pd.DataFrame(list(self.molecules.find(query, projection)))
+ +
[docs] def insert_molecule(self, mol, update_duplicates=False): + """ + Insert a molecule into the molecules collection. + + Args: + mol (Molecule): A pymatgen ``Molecule`` object to insert. + update_duplicates (bool, optional): If ``True``, update the existing + molecule in the db with the new one. Defaults to ``False``. + """ + mol_dict = get_chem_schema(mol) + # Check if mol is already in db + result = self.molecules.find_one({"inchi": mol_dict["inchi"]}) + if result: + logger.info("{} already in database".format(mol_dict["inchi"])) + # If mol is not in db, checks if the same molecule exists with a + # different representation + if result is None: + m = MoleculeMatcher() + result_list = list( + self.molecules.find( + {"formula_alphabetical": mol_dict["formula_alphabetical"]} + ) + ) + if result_list: + logger.info( + "{} already in {} documents".format( + mol_dict["inchi"], len(result_list) + ) + ) + for i in result_list: + saved_mol = Molecule.from_dict(i) + if m.fit(saved_mol, mol): + result = i + mol_dict["inchi"] = i["inchi"] + break + # If update_duplicates is set to True, updates existing document with + # new geometry keeping the old inchi representation + if result and update_duplicates: + logger.info("Updating duplicate {}".format(mol_dict["inchi"])) + if result is None or update_duplicates: + mol_dict["version"] = infrastructure_version + mol_dict["last_updated"] = datetime.datetime.utcnow() + self.molecules.update_one( + {"inchi": mol_dict["inchi"]}, {"$set": mol_dict}, upsert=True + ) + return mol_dict["inchi"] + else: + logger.info("Skipping duplicate {}".format(mol_dict["inchi"])) + return mol_dict["inchi"]
+ +
[docs] def retrieve_molecule(self, inchi): + """ + Retrieve a molecule from the molecules collection. + + Args: + inchi (str): The inchi representation of the molecule. + + Returns: + dict + """ + return self.molecules.find_one({"inchi": inchi})
+ +
[docs] def delete_molecule(self, inchi): + """ + Delete a molecule from the molecules collection. + + Args: + inchi (str): The inchi representation of the molecule to delete. + """ + return self.molecules.delete_one({"inchi": inchi})
+ +
[docs] def insert_run(self, grun): + """ + Insert a Gaussian run into the runs collection. + + Args: + grun (dict): A dictionary containing the Gaussian run. + """ + if "_id" in grun: + stored_run = self.retrieve_run(_id=grun["_id"]) + if stored_run: + return grun["_id"] + grun["last_updated"] = datetime.datetime.utcnow() + result = self.runs.insert_one(grun, bypass_document_validation=True) + return result.inserted_id
+ +
[docs] def retrieve_doc( + self, + collection_name, + inchi=None, + smiles=None, + functional=None, + basis=None, + **kwargs + ): + """ + Retrieve a document from any collection of the database. + + Args: + collection_name (str): The name of the collection, e.g. bde, molecules, + runs, etc. + inchi (str, optional): The inchi representation of the molecule. + smiles (str, optional): The smiles representation of the molecule. + functional (str, optional): The name of the density functional. + basis (str, optional): The name of the basis set. + kwargs: Other kwargs that can be used to query the collection. + + Returns: + list: A list of documents that match the query + """ + query = {} + if inchi: + query["inchi"] = inchi + if smiles: + query["smiles"] = smiles + if functional: + query["functional"] = functional + if basis: + query["basis"] = basis + query = {**query, **kwargs} + return list(self.db[collection_name].find(query))
+ +
[docs] def retrieve_run( + self, inchi=None, smiles=None, functional=None, basis=None, **kwargs + ): + """ + Retrieve a run from the runs collection. + + Args: + inchi (str, optional): The inchi representation of the molecule. + smiles (str, optional): The smiles representation of the molecule. + functional (str, optional): The name of the density functional. + basis (str, optional): The name of the basis set. + kwargs: Other kwargs that can be used to query the collection. + + Returns: + list: A list of documents that match the query. + """ + result = self.retrieve_doc( + "runs", + inchi=inchi, + smiles=smiles, + functional=functional, + basis=basis, + **kwargs + ) + return result
+ +
[docs] def move_runs( + self, + new_collection, + inchi=None, + smiles=None, + functional=None, + basis=None, + **kwargs + ): + """ + Move documents from the runs collection to another collection. + + Args: + new_collection (str): The name of the collection to move the runs to. + inchi (str, optional): The inchi representation of the molecule. + smiles (str, optional): The smiles representation of the molecule. + functional (str, optional): The name of the density functional. + basis (str, optional): The name of the basis set. + kwargs: Other kwargs that can be used to query the collection. + """ + runs = self.retrieve_run(inchi, smiles, functional, basis, **kwargs) + self.db[new_collection].insert_many(runs)
+ +
[docs] def update_run( + self, + new_values, + inchi=None, + smiles=None, + job_type=None, + functional=None, + basis=None, + phase=None, + **kwargs + ): + """ + Update a document in the runs collection. If multiple documents match the query + criteria, will select the first one. + + Args: + new_values (dict): The new output values to update the document with, e.g. + + .. code-block:: python + + {"polarizability": 3.5} + + inchi (str, optional): The inchi representation of the molecule. + smiles (str, optional): The smiles representation of the molecule. + job_type (str, optional): The type of job, e.g. "opt", "freq". + functional (str, optional): The name of the density functional. + basis (str, optional): The name of the basis set. + phase (str, optional): The phase of the job, e.g. "gas", "solution". + kwargs: Other kwargs that can be used to query the collection. + """ + query = {} + if inchi: + query["inchi"] = inchi + if smiles: + query["smiles"] = smiles + if job_type: + query["type"] = job_type + if functional: + query["functional"] = functional + if basis: + query["basis"] = basis + if phase: + query["phase"] = phase + query = {**query, **kwargs} + run_ = self.retrieve_run(inchi, smiles, functional, basis, **kwargs)[0] + run_["output"]["output"].update(new_values) + self.runs.update_one(query, {"$set": run_})
+ +
[docs] @classmethod + def from_db_file(cls, db_file, admin=True): + """ + Create a new database object from a database file. + + Args: + db_file (str): The path to the database file. + admin (bool, optional): Whether to use admin credentials; defaults to + ``True``. + + Returns: + GaussianCalcDb. + """ + creds = loadfn(db_file) + + kwargs = creds.get( + "mongoclient_kwargs", {} + ) # any other MongoClient kwargs can go here ... + + if creds.get("uri_mode", False): + return cls(creds["host"], uri_mode=True, **kwargs) + else: + if admin and "admin_user" not in creds and "readonly_user" in creds: + raise ValueError( + "Trying to use admin credentials, " + "but no admin credentials are defined. " + "Use admin=False if only read_only " + "credentials are available." + ) + + if admin: + user = creds.get("admin_user") + password = creds.get("admin_password") + else: + user = creds.get("readonly_user") + password = creds.get("readonly_password") + + if "authsource" in creds: + kwargs["authsource"] = creds["authsource"] + else: + kwargs["authsource"] = creds["database"] + + return cls( + creds["host"], + int(creds.get("port", 27017)), + creds["database"], + user, + password, + **kwargs + )
+ +
[docs] def insert_fg(self, fg_file): + """ + Insert functional groups into their collection using a json file. The file can + contain one or more functional groups. + + Args: + fg_file (str): The path to the json file. + """ + # file can contain one fg dictionary or multiple ones + with open(fg_file) as f: + func_group = json.load(f) + list_of_groups = [] + search_query = [] + for i, j in func_group.items(): + list_of_groups.append({**j, "name": i}) + search_query.append(i) + existing = self.functional_groups.find( + {"name": {"$in": search_query}}, {"name": 1} + ) + existing = set([i["name"] for i in existing]) + list_of_groups = [i for i in list_of_groups if i["name"] not in existing] + self.functional_groups.insert_many(list_of_groups)
+ +
[docs] def retrieve_fg(self, name): + """ + Retrieve a functional group from the functional_groups collection. + + Args: + name (str): The name of the functional group to retrieve. + + Returns: + dict + """ + return self.functional_groups.find_one({"name": name})
+ +
[docs] def insert_derived_mol(self, derived_mol, update_duplicates): + """ + Insert a derived molecule into the derived_molecules collection. + + Args: + derived_mol (Molecule): ``pymatgen.Molecule`` object. + update_duplicates (bool): Whether to update duplicates if the molecule + already exists. + """ + if isinstance(derived_mol, Molecule): + derived_mol_dict = get_chem_schema(derived_mol) + result = self.derived_molecules.find_one( + {"inchi": derived_mol_dict["inchi"]} + ) + if result: + logger.info("{} already in database".format(derived_mol_dict["inchi"])) + if result and update_duplicates: + logger.info("Updating duplicate {}".format(derived_mol_dict["inchi"])) + if result is None or update_duplicates: + derived_mol_dict["last_updated"] = datetime.datetime.utcnow() + self.derived_molecules.update_one( + {"inchi": derived_mol_dict["inchi"]}, + {"$set": derived_mol_dict}, + upsert=True, + ) + return derived_mol_dict["inchi"] + else: + logger.info("No molecule provided")
+ +
[docs] def insert_property(self, collection_name, property_dict, index, **kwargs): + """ + Insert a document into a property collection in the database. + + Args: + collection_name (str): The name of the collection to insert the property + into; e.g. bde, binding_energy, etc. + property_dict (dict): The property dictionary to insert. + index (str, list[tuple]): The indexes to use for fast lookup. + kwargs: Additional kwargs to pass to ``pymongo.collection.create_index``. + """ + collection = self.db[collection_name] + collection.create_index(index, **kwargs) + collection.insert_one(property_dict)
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/firetasks/geo_transformation.html b/html/_modules/mispr/gaussian/firetasks/geo_transformation.html new file mode 100644 index 00000000..84b7d040 --- /dev/null +++ b/html/_modules/mispr/gaussian/firetasks/geo_transformation.html @@ -0,0 +1,1475 @@ + + + + + + + + + + + + + + + + mispr.gaussian.firetasks.geo_transformation - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.firetasks.geo_transformation

+"""Define firetasks for performing various molecule transformations."""
+
+import os
+import copy
+import logging
+import itertools
+
+from pymatgen.core.structure import Molecule
+from pymatgen.analysis.graphs import MoleculeGraph
+from pymatgen.analysis.local_env import OpenBabelNN
+from pymatgen.analysis.fragmenter import open_ring
+
+from fireworks import Workflow
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+
+from mispr.gaussian.utilities.mol import process_mol
+from mispr.gaussian.utilities.metadata import get_mol_formula
+from mispr.gaussian.utilities.db_utilities import get_db
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+DEFAULT_KEY = "gout_key"
+
+
+
[docs]@explicit_serialize +class ProcessMoleculeInput(FiretaskBase): + """ + Process a molecule and generates a Molecule object. Used for handling different + molecule formats provided to Gaussian workflows. + + Args: + mol (Molecule, str, GaussianOutput, dict): Source of the structure; should + correspond to that of the ``operation_type``; see + ``mispr.gaussian.utilities.mol.process_mol`` for more details; besides the + formats supported by ``mispr.gaussian.utilities.mol.process_mol``, if the + molecule is to be obtained via ``fw_spec``, mol should be a string + corresponding to the key in ``fw_spec``. + operation_type (str, optional): Type of operation to perform. See + ``mispr.gaussian.utilities.mol.process_mol`` for details of supported types. + db (str or dict, optional): Database credentials; could be provided as + the path to the db.json file or in the form of a dictionary; if none is + provided, attempts to get it from the configuration files. + save_to_db (bool, optional): Whether to save the processed molecule to the + molecules collection in the db. + charge (int, optional): Charge of the molecule. + update_duplicates (bool, optional): Whether to update molecule document in the + db if it already exists. + save_to_file (bool, optional): Whether to save the processed molecule to a file. + fmt (str, optional): Molecule file format if save_to_file is True. Defaults to xyz. + filename (str, optional): Name of the file to save the molecule to if + ``save_to_file`` is True. Defaults to molecular formula. + from_fw_spec (bool, optional): Whether to get the molecule from the ``fw_spec``; + mol in this case is the key to the dict in ``fw_spec``. + local_opt (bool, optional): Whether to perform local optimization on the + molecule. + force_field (str, optional): Force field to use for local optimization; see + ``mispr.gaussian.utilities.mol.process_mol`` for supported force field types. + steps (int, optional): Number of steps to perform local optimization. + str_type (str, optional): format of string if operation_type is ``get_from_str``; + e.g. ``smi`` or any other format supported by OpenBabel). + working_dir (str, optional): Working directory to save the molecule file to or + read input files from. + """ + + required_params = ["mol"] + optional_params = [ + "operation_type", + "db", + "save_to_db", + "charge", + "update_duplicates", + "save_to_file", + "fmt", + "filename", + "from_fw_spec", + "local_opt", + "force_field", + "steps", + "str_type", + "working_dir", + ] + + @staticmethod + def _run_to_mol_object(run): + return Molecule.from_dict(run["output"]["output"]["molecule"]) + + @staticmethod + def _from_fw_spec(mol, fw_spec): + # mol = key in this case + available_runs = fw_spec["gaussian_output"] + if not isinstance(mol, dict): + mol = available_runs.get(mol, mol) + else: + if isinstance(mol["mol"], list): + mol["mol"] = [ + ProcessMoleculeInput._from_fw_spec(i, fw_spec) for i in mol["mol"] + ] + else: + mol["mol"] = ProcessMoleculeInput._from_fw_spec(mol["mol"], fw_spec) + return mol + +
[docs] def run_task(self, fw_spec): + mol = self["mol"] + operation_type = self.get("operation_type", "get_from_mol") + working_dir = self.get("working_dir") or os.getcwd() + db = self.get("db") + + if self.get("from_fw_spec"): + mol = self._from_fw_spec(mol, fw_spec) + + output_mol = process_mol( + operation_type=operation_type, + mol=mol, + working_dir=working_dir, + db=db, + local_opt=self.get("local_opt", False), + force_field=self.get("force_field"), + steps=self.get("steps"), + charge=self.get("charge"), + str_type=self.get("str_type"), + ) + + if self.get("save_to_db"): + db = get_db(db) if db else get_db() + update_duplicates = self.get("update_duplicates", False) + db.insert_molecule(output_mol, update_duplicates=update_duplicates) + + if self.get("save_to_file"): + fmt = self.get("fmt", "xyz") + filename = self.get("filename", get_mol_formula(output_mol)) + file = os.path.join(working_dir, f"{filename}.{fmt}") + output_mol.to(fmt, file) + fw_spec["prev_calc_molecule"] = output_mol # Note: This should ideally
+ # be part of FWaction, however because mpi doesn't support pymatgen, we + # should be careful about what is being passed to the next firework + + +
[docs]@explicit_serialize +class ConvertToMoleculeObject(FiretaskBase): + """ + Read a molecule from a file, converts it to a Molecule object, and saves it as + dict to mongodb. + + Args: + mol_file (str): Molecule file; supported file formats include + xyz|pdb|mol|mdl|sdf|sd|ml2|sy2|mol2|cml|mrv, + gaussian input (gjf|g03|g09|com|inp), + Gaussian output (.out), and pymatgen's JSON serialized molecules. + db (str or dict, optional): Database credentials. + save_to_db (bool, optional): Whether to save the processed molecule to db. + update_duplicates (bool, optional): Whether to update molecule document in db + if it already exists. + """ + + required_params = ["mol_file"] + optional_params = ["db", "save_to_db", "update_duplicates"] + +
[docs] def run_task(self, fw_spec): + working_dir = os.getcwd() + file_name = self["mol_file"] + mol = process_mol( + operation_type="get_from_file", mol=file_name, working_dir=working_dir + ) + if self.get("save_to_db", True): + mol_db = get_db(self.get("db")) + mol_db.insert_molecule( + mol, update_duplicates=self.get("update_duplicates", False) + ) + fw_spec["prev_calc_molecule"] = mol # Note: This should ideally be
+ # part of FWaction, however because mpi doesn't support pymatgen, we + # should be careful about what is being passed to the next firework + + +
[docs]@explicit_serialize +class RetrieveMoleculeObject(FiretaskBase): + """ + Retrieve a molecule object from the database using InChI as an identifier and add + it to the ``fw_spec``. + + Args: + inchi (str): InChI string. + db (str or dict, optional): Database credentials. + save_mol_file (bool, optional): Whether to save the retrieved molecule to file. + fmt (str, optional): Format of the molecule file to create if save_mol_file is + True. Defaults to xyz. + filename (str): Name of the molecule file to create if ``save_mol_file`` is True; + will use molecular formula if not specified. + """ + + required_params = ["inchi"] + optional_params = ["db", "save_mol_file", "fmt", "filename"] + +
[docs] def run_task(self, fw_spec): + inchi = self["inchi"] + mol = process_mol("get_from_mol_db", inchi, db=self.get("db")) + if mol and self.get("save_mol_file", False): + working_dir = os.getcwd() + file_name = self.get( + "filename.{}".format(self.get("fmt", "xyz")), + "{}.{}".format(get_mol_formula(mol), self.get("fmt", "xyz")), + ) + mol_file = os.path.join(working_dir, file_name) + mol.to(self.get("fmt", "xyz"), mol_file) + fw_spec["prev_calc_molecule"] = mol
+ + +
[docs]@explicit_serialize +class AttachFunctionalGroup(FiretaskBase): + """ + Attach a functional group to a molecule and adds it to fw_spec. + + Args: + func_grp (str): Name of the functional group (e.g. carboxyl). + index (int): Site index in the molecule at which to attach the functional group. + db (str or dict, optional): Database credentials. + molecule (Molecule, optional): Molecule to attach the functional group to; + either provided directly or taken from a previous calculation through + ``fw_spec``; priority is given to the latter. + bond_order (int, optional): Bond order to calculate the bond length between + the two sites. Defaults to 1. + save_to_db (bool, optional): Whether to save the derived molecule to db. + update_duplicates (bool, optional): Whether to update molecule document in + db if it already exists. + save_mol_file (bool, optional): Whether to save the derived molecule to file + (xyz, pdb, etc.). + fmt (str, optional): Format of the molecule file to create if ``save_mol_file`` is + True; uses xyz if not specified. + filename (str, optional): Name of the molecule file to create if ``save_mol_file`` + is True; will use molecular formula if not specified. + """ + + required_params = ["func_grp", "index"] + optional_params = [ + "db", + "molecule", + "bond_order", + "save_to_db", + "update_duplicates", + "save_mol_file", + "fmt", + "filename", + ] + +
[docs] def run_task(self, fw_spec): + db = get_db(self.get("db")) + if fw_spec.get("prev_calc_molecule"): + mol = fw_spec.get("prev_calc_molecule") + elif self.get("molecule"): + mol = self.get("molecule") + func_grp_dict = db.retrieve_fg(self["func_grp"]) + func_grp = Molecule(func_grp_dict["species"], func_grp_dict["coords"]) + derived_mol = Molecule.copy(mol) + derived_mol.substitute( + index=self["index"], func_grp=func_grp, bond_order=self.get("bond_order", 1) + ) + if self.get("save_to_db", True): + db.insert_derived_mol( + derived_mol, update_duplicates=self.get("update_duplicates", False) + ) + if self.get("save_mol_file", False): + working_dir = os.getcwd() + file_name = self.get("filename", get_mol_formula(derived_mol)) + file_name = ("{}.{}".format(file_name, self.get("fmt", "xyz")),) + derived_mol_file = os.path.join(working_dir, file_name) + derived_mol.to(self.get("fmt", "xyz"), derived_mol_file) + fw_spec["prev_calc_molecule"] = derived_mol
+ + +
[docs]@explicit_serialize +class LinkMolecules(FiretaskBase): + """ + Link two molecules using one site from the first and another site from the second + molecule and adds the resulting molecule to ``fw_spec``. + + Args: + index1 (int): site index in the first molecule at which to link the two molecules. + index2 (int): site index in the second molecule at which to link the two molecules. + db (str or dict, optional): Database credentials. + mol1 (Molecule, optional): First molecule; can be provided directly or taken + from a previous calculation; priority is given to the latter. + mol2 (Molecule, optional): Second molecule; can be provided directly or taken + from a previous calculation; priority is given to the latter. + bond_order (int, optional): Bond order to calculate the bond length between the + two sites. Defaults to 1. + save_to_db (bool, optional): Whether to save the derived molecule to db. + update_duplicates (bool, optional): Whether to update molecule document in db + if it already exists. + save_mol_file (bool, optional): Whether to save the derived molecule to file + (xyz, pdb, etc.). + fmt (str, optional): Format of the molecule file to create if ``save_mol_file`` + is True; uses xyz if not specified. + filename (str, optional): Name of the molecule file to create if ``save_mol_file`` + is True; will use molecular formula if not specified. + """ + + required_params = ["index1", "index2"] + optional_params = [ + "db", + "mol1", + "mol2", + "bond_order", + "save_to_db", + "update_duplicates", + "save_mol_file", + "fmt", + "filename", + ] + +
[docs] def run_task(self, fw_spec): + db = get_db(self.get("db")) + mol1 = fw_spec.get("mol1", self.get("mol1")) + mol2 = fw_spec.get("mol2", self.get("mol2")) + linked_mol = mol1.link( + mol2, self["index1"], self["index2"], self.get["bond_order"] + ) + if self.get("save_to_db", True): + db.insert_derived_mol( + linked_mol, update_duplicates=self.get("update_duplicates", False) + ) + if self.get("save_mol_file", False): + working_dir = os.getcwd() + file_name = self.get( + "filename.{}".format(self.get("fmt", "xyz")), + "{}.{}".format(get_mol_formula(linked_mol), self.get("fmt", "xyz")), + ) + linked_mol_file = os.path.join(working_dir, file_name) + linked_mol.to(self.get("fmt", "xyz"), linked_mol_file) + fw_spec["prev_calc_molecule"] = linked_mol
+ + +
[docs]@explicit_serialize +class BreakMolecule(FiretaskBase): + """ + Break a molecule into unique fragments (uniqueness is in terms of structure and + assigned charge) and creates optimization and frequency Fireworks for each fragment + (optional). + + credits: Samuel Blau + + Args: + mol (Molecule, optional): Molecule to break into fragments; can be provided + directly or taken from a previous calculation; priority is given to the latter. + bonds (list, optional): List of tuples of the bonds to break; e.g. + [(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between + atoms 1 and 2; if none is specified, will attempt to break all bonds; + defaults to None. + ref_charge (int, optional): Charge on the principle molecule; if not provided, + charge on Molecule will be used. + fragment_charges (list, optional): List of charges to assign to the fragments + in addition to the ones already assigned. + + .. note:: + The following charges will be used: + 1. **Neutral molecule**: each fragment will have charges of 0, 1, and -1 + 2. **Molecule with charge -N**: each fragment will have charges of + 0, -N, -N+1, -N+2 + 3. **Molecule with charge +N**: each fragment will have charges of + 0, N, N-1, N-2 + If charges different from the above are provided via ``fragment_charges``, + additional fragments with these charges will be created. + + open_rings (bool, optional): Whether to open rings; if set to True, will + perform local optimization to get a good initial guess for the structure; + defaults to False. + opt_steps (int, optional): Number of optimization steps to perform when opening + the rings; uses 10000 if not specified. + working_dir (str, optional): Working directory to use for saving any files or + running the calculations. + db (str or dict, optional): Database credentials + opt_gaussian_inputs (dict, optional): Dictionary of parameters to use for + optimizing the fragments if ``calc_frags`` is True. + freq_gaussian_inputs (dict, optional): Dictionary of parameters to use for + performing a frequency analysis if ``calc_frags`` is True. + cart_coords (bool, optional): Whether to use cartesian coordinates in writing + Gaussian input files if ``calc_frags`` is True. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the molecule; + e.g.: {"Li":1, "O":-2}. + calc_frags (bool, optional): Whether to create optimization and frequency + Fireworks for the generated fragments and add them as children via FWAction. + save_to_db (bool, optional): Whether to save the generated fragments to db. + save_to_file (bool, optional): Whether to save the generated fragments to file. + fmt (str, optional): Format of the molecule file to create if ``save_to_file`` is + True (e.g. xyz, pdb, etc.). + update_duplicates (bool, optional): Whether to update fragment document in + the db if it already exists; works only if ``save_to_db`` is True. + """ + + required_params = [] + optional_params = [ + "mol", + "bonds", + "ref_charge", + "fragment_charges", + "open_rings", + "opt_steps", + "working_dir", + "db", + "opt_gaussian_inputs", + "freq_gaussian_inputs", + "cart_coords", + "oxidation_states", + "calc_frags", + "save_to_db", + "save_to_file", + "fmt", + "update_duplicates", + "additional_kwargs", + ] + + @staticmethod + def _define_charges(ref_charge, fragment_charges): + # TODO: check charges on metal atoms so as to not violate valence rule + # get a list of possible charges that each fragment can take + possible_charges = [] + if ref_charge == 0: + possible_charges.extend((-1, 0, 1)) + elif ref_charge > 0: + for i in range(ref_charge + 1): + possible_charges.append(ref_charge - i) + else: + for i in range(abs(ref_charge - 1)): + possible_charges.append(ref_charge + i) + # add additional charges to the list of possible charges + if fragment_charges: + fragment_charges += [ref_charge - charge for charge in fragment_charges] + possible_charges.extend( + charge for charge in fragment_charges if charge not in possible_charges + ) + # find possible charge pairs upon breaking a bond; sum = ref_charge + charge_pairs = [ + pair + for pair in list(itertools.product(possible_charges, repeat=2)) + if sum(pair) == ref_charge + ] + + charge_ind_map = {j: i for i, j in enumerate(possible_charges)} + return possible_charges, charge_pairs, charge_ind_map + + @staticmethod + def _find_unique_fragments(fragments_list): + # get unique fragments from the list of all fragments + # for each bond, store the new indexes of the unique fragments formed + # upon splitting the molecule (can be used for analysis purposes later) + unique_fragments = [] + fragments_indices = [] + for fragment in fragments_list: + indices = [] + for i in fragment: + flag = 0 + for ind, j in enumerate(unique_fragments): + if i.isomorphic_to(j): + flag = 1 + indices.append(ind) + break + if flag == 0: + indices.append(len(unique_fragments)) + unique_fragments.append(i) + fragments_indices.append(indices) + return unique_fragments, fragments_indices + + @staticmethod + def _find_unique_molecules( + unique_fragments, + fragment_charges, + db, + working_dir, + save_to_db, + update_duplicates, + save_to_file, + fmt, + calc_frags, + ): + # create molecule objects from the unique fragments and set the charge + # of each molecule + molecules = [fragment.molecule for fragment in unique_fragments] + unique_molecules = [] + if not calc_frags: + # only saving if frags will not be calculated; otherwise saving + # will be handled via the dynamically created fireworks; done to + # avoid double saving + if save_to_db: + db = get_db(db) if db else get_db() + for mol in molecules: + db.insert_molecule(mol, update_duplicates=update_duplicates) + if save_to_file: + for mol in molecules: + mol_formula = get_mol_formula(mol) + file = os.path.join(working_dir, f"{mol_formula}.{fmt}") + mol.to(fmt, file) + + for mol in molecules: + for charge in fragment_charges: + mol_copy = copy.deepcopy(mol) + mol_copy.set_charge_and_spin(charge) + unique_molecules.append(mol_copy) + return unique_molecules + + @staticmethod + def _find_molecule_indices( + fragments_indices, fragment_charges, charge_ind_map, charge_pairs, offset=0 + ): + num_charges = len(fragment_charges) + molecule_indices = [] + for fragment in fragments_indices: + split_possibilities = [] + for charge_pair in charge_pairs: + split_possibility = [ + offset + fragment[i] * num_charges + charge_ind_map[j] + for i, j in enumerate(charge_pair) + ] + split_possibilities.append(split_possibility) + molecule_indices.append(split_possibilities) + return molecule_indices + + def _cleanup_kwargs(self): + additional_kwargs = self.get("additional_kwargs", {}) + kwargs = { + i: j + for i, j in additional_kwargs.items() + if i + not in self.required_params + + self.optional_params + + [ + "mol_operation_type", + "dir_structure", + "process_mol_func", + "mol_name", + "from_fw_spec", + "skips", + ] + } + return kwargs + + @staticmethod + def _workflow( + mol, + gout_key, + working_dir, + db, + opt_gaussian_inputs, + freq_gaussian_inputs, + cart_coords, + oxidation_states, + save_to_db, + save_to_file, + fmt, + update_duplicates, + **kwargs, + ): + from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS + + dir_structure = ["charge_{}".format(str(mol.charge))] + mol_formula = get_mol_formula(mol) + + if len(mol) == 1: + skips = ["opt"] + else: + skips = None + + job_name = "opt_freq" + _, _, frag_fws = common_fw( + mol_operation_type="get_from_mol", + mol=mol, + working_dir=working_dir, + dir_structure=dir_structure, + db=db, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + process_mol_func=False, + mol_name=mol_formula, + from_fw_spec=False, + skips=skips, + gout_key=gout_key, + save_to_db=save_to_db, + save_to_file=save_to_file, + fmt=fmt, + update_duplicates=update_duplicates, + **kwargs, + ) + return Workflow( + frag_fws, + name="{}_{}".format(mol_formula, job_name), + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS}, + ) + +
[docs] def run_task(self, fw_spec): + # get principle molecule from fw_spec or user input + if fw_spec.get("prev_calc_molecule"): + mol = fw_spec.get("prev_calc_molecule") + elif self.get("molecule"): + mol = self.get("molecule") + else: + raise KeyError( + "No molecule present, add as an optional param or check fw_spec" + ) + + ref_charge = self.get("ref_charge", mol.charge) + db = self.get("db") + working_dir = self.get("working_dir", os.getcwd()) + calc_frags = self.get("calc_frags", False) + save_to_file = self.get("save_to_file") + save_to_db = self.get("save_to_db") + fmt = self.get("fmt", "xyz") + update_duplicates = self.get("update_duplicates", False) + + # break the bonds: either those specified by the user inputs or all + # the bonds in the molecule; only supports breaking bonds or opening + # ring in the principle molecule + mol_graph = MoleculeGraph.with_local_env_strategy(mol, OpenBabelNN()) + all_bonds = self.get("bonds", None) + if not all_bonds: + all_bonds = [ + tuple(sorted([idx1, idx2])) for idx1, idx2, _ in mol_graph.graph.edges + ] + + fragments = [] + bonds = [] + ring_fragments = [] + ring_bonds = [] + + # get fragments by splitting the molecule at each bond + for idx, bond in enumerate(all_bonds): + try: + fragments.append( + mol_graph.split_molecule_subgraphs([bond], allow_reverse=True) + ) + bonds.append(bond) + except Exception as e: + logger.info(e) + if self.get("open_rings"): + logger.info( + "opening ring by breaking bond between " + "site {} and site {}".format(str(bond[0]), str(bond[1])) + ) + ring_fragments.append( + [open_ring(mol_graph, [bond], self.get("opt_steps", 10000))] + ) + ring_bonds.append(bond) + else: + logger.info( + "encountered a ring bond; should set open_ring " + "to True to open the ring" + ) + + unique_molecules = [] + molecule_indices = [] + if fragments: + fragment_charges = self.get("fragment_charges", None) + possible_charges, charge_pairs, charge_ind_map = self._define_charges( + ref_charge, fragment_charges + ) + unique_fragments, fragments_indices = self._find_unique_fragments(fragments) + unique_molecules = self._find_unique_molecules( + unique_fragments, + possible_charges, + db, + working_dir, + save_to_db, + update_duplicates, + save_to_file, + fmt, + calc_frags, + ) + molecule_indices = self._find_molecule_indices( + fragments_indices, possible_charges, charge_ind_map, charge_pairs + ) + ring_unique_molecules = [] + ring_molecule_indices = [] + if ring_fragments: + ring_unique_fragments, ring_fragments_indices = self._find_unique_fragments( + ring_fragments + ) + ring_unique_molecules = self._find_unique_molecules( + ring_unique_fragments, + [ref_charge], + db, + working_dir, + save_to_db, + update_duplicates, + save_to_file, + fmt, + calc_frags, + ) + charge_pairs = [(ref_charge,)] + charge_ind_map = {ref_charge: 0} + ring_molecule_indices = self._find_molecule_indices( + ring_fragments_indices, + [ref_charge], + charge_ind_map, + charge_pairs, + len(unique_molecules), + ) + all_molecules = unique_molecules + ring_unique_molecules + + update_spec = { + "bonds": bonds + ring_bonds, + "fragments": all_molecules, + "molecule_indices": molecule_indices + ring_molecule_indices, + } + + if calc_frags: + wfs = [] + frag_keys = [] + opt_gaussian_inputs = self.get("opt_gaussian_inputs") or {} + freq_gaussian_inputs = self.get("freq_gaussian_inputs") or {} + cart_coords = self.get("cart_coords", True) + oxidation_states = self.get("oxidation_states") + additional_kwargs = self._cleanup_kwargs() + for mol_ind, mol in enumerate(all_molecules): + gout_key = "frag_{}".format(mol_ind) + frag_wf = self._workflow( + mol, + gout_key, + working_dir, + db, + opt_gaussian_inputs, + freq_gaussian_inputs, + cart_coords, + oxidation_states, + save_to_db, + save_to_file, + fmt, + update_duplicates, + **additional_kwargs, + ) + wfs.append(frag_wf) + frag_keys.append(gout_key) + update_spec["frag_keys"] = frag_keys + return FWAction(update_spec=update_spec, detours=wfs, propagate=True) + + else: + return FWAction(update_spec=update_spec)
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/firetasks/parse_outputs.html b/html/_modules/mispr/gaussian/firetasks/parse_outputs.html new file mode 100644 index 00000000..767f725c --- /dev/null +++ b/html/_modules/mispr/gaussian/firetasks/parse_outputs.html @@ -0,0 +1,1944 @@ + + + + + + + + + + + + + + + + mispr.gaussian.firetasks.parse_outputs - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.firetasks.parse_outputs

+"""Define firetasks for parsing Gaussian output files."""
+
+import os
+import sys
+import json
+import logging
+import datetime
+import subprocess
+
+from configparser import ConfigParser
+
+import numpy as np
+import pymongo
+import networkx as nx
+import matplotlib.image as img
+import matplotlib.pyplot as plt
+
+from bson.objectid import ObjectId
+
+from pymatgen.io.gaussian import GaussianInput
+from pymatgen.core.structure import Molecule
+from pymatgen.analysis.graphs import MoleculeGraph
+from pymatgen.analysis.local_env import OpenBabelNN
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+from fireworks.utilities.fw_serializers import DATETIME_HANDLER
+
+from mispr import __version__ as mispr_version
+from mispr.gaussian.utilities.mol import process_mol
+from mispr.gaussian.utilities.gout import process_run
+from mispr.gaussian.utilities.misc import pass_gout_dict
+from mispr.gaussian.utilities.dbdoc import add_solvent_to_prop_dict
+from mispr.gaussian.utilities.files import bibtex_parser
+from mispr.gaussian.utilities.rdkit import (
+    get_rdkit_mol,
+    draw_rdkit_mol_with_highlighted_bonds,
+)
+from mispr.gaussian.utilities.metadata import get_chem_schema
+from mispr.gaussian.utilities.db_utilities import get_db
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+DEFAULT_KEY = "gout_key"
+HARTREE_TO_EV = 27.2114
+HARTREE_TO_KJ = 2600
+FARAD = 96.5
+R = 8.31446
+
+
+
[docs]@explicit_serialize +class ProcessRun(FiretaskBase): + """ + Process Gaussian output files from a single run. Enters the run to db and/or create + a summary json file. + + Args: + run (GaussianOutput, str, dict): The actual Gaussian run; type depends on the + ``operation_type``. + operation_type (str, optional): Type of operation to be performed; refer to + ``mispr.gaussian.utilities.gout.process_run`` for supported ones. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the db.json file or in the form of a dictionary. + save_to_db (bool, optional): Whether to save the run to db. + save_to_file (bool, optional): Whether to save the run to a json file. + filename (str, optional): Name of the json file to save the run to; uses + "run.json" if not provided. + input_file (str, optional): The input file for the run; used for adding Gaussian + input parameters to the final Gaussian dictionary; if not specified, will get + these parameters from the run itself, but in this case, "input_parameters" + usually specified at the end of the Gaussian input file will not be saved + since they are not easily retrieved from the Gaussian output file. + gout_key (str, optional): The key to use for the run in the mod_spec dict passed + to ``FWAction``; used when contents of the run are needed in other tasks. + format_chk (bool, optional): Whether to create a formatted check file from the + Gaussian checkpoint file. + formchk_cmd (str, optional): The full command to use for formatting the + checkpoint file; if not provided, will attempt to find one in the configuration + files. + """ + + required_params = ["run"] + optional_params = [ + "operation_type", + "db", + "save_to_db", + "save_to_file", + "filename", + "input_file", + "gout_key", + "format_chk", + "formchk_cmd", + ] + +
[docs] def run_task(self, fw_spec): + run = self["run"] + operation_type = self.get("operation_type", "get_from_gout") + input_file = self.get("input_file") + working_dir = os.getcwd() + db = self.get("db") + + if self.get("format_chk"): + found_chk = False + for file in os.listdir(working_dir): + if file.endswith(".chk"): + found_chk = True + chk_file = file.strip(".chk") + cmd = self.get("formchk_cmd") + if not cmd: + cfg = ConfigParser() + cfg.read(CONFIG_FILE_DIR + "/config.ini") + cmd = cfg["RunCalc"]["formchkcmd"] + cmd = cmd.replace("$input_path$", file).replace( + "$output_path$", f"{chk_file}.fchk" + ) + + logger.info("Running command: {}".format(cmd)) + return_code = subprocess.call(cmd, shell=True) + logger.info( + "Finished running with return code: {}".format(return_code) + ) + if found_chk: + break + if not found_chk: + logger.info(f"No checkpoint file found in {working_dir}") + + gout_dict = process_run( + operation_type=operation_type, + run=run, + input_file=input_file, + working_dir=working_dir, + db=db, + ) + + # get initial and final molecule + input_mol = Molecule.from_dict(gout_dict["input"]["molecule"]) + output_mol = Molecule.from_dict(gout_dict["output"]["output"]["molecule"]) + + # Build initial and final molgraphs + input_molgraph = MoleculeGraph.with_local_env_strategy(input_mol, OpenBabelNN()) + output_molgraph = MoleculeGraph.with_local_env_strategy( + output_mol, OpenBabelNN() + ) + + # Detect any structural change that occurred during calculation + if input_molgraph.isomorphic_to(output_molgraph): + change = "no_change" + else: + input_graph = input_molgraph.graph + output_graph = output_molgraph.graph + if nx.is_connected(input_graph.to_undirected()) and not nx.is_connected( + output_graph.to_undirected() + ): + change = "unconnected_fragments" + elif output_graph.number_of_edges() < input_graph.number_of_edges(): + change = "fewer_bonds" + elif output_graph.number_of_edges() > input_graph.number_of_edges(): + change = "more_bonds" + else: + change = "bond_change" + gout_dict["structural_change"] = change + + if "_id" in gout_dict: + gout_dict["_id"] = ObjectId(gout_dict["_id"]) + if "tag" in fw_spec: + gout_dict["tag"] = fw_spec["tag"] + if "run_time" in fw_spec: + gout_dict["wall_time (s)"] = fw_spec["run_time"] + gout_dict["version"] = mispr_version + if gout_dict["output"]["has_gaussian_completed"]: + run_list = {} + if self.get("save_to_db"): + runs_db = get_db(db) + run_id = runs_db.insert_run(gout_dict) + run_list["run_id_list"] = run_id + logger.info("Saved parsed output to db") + + if self.get("save_to_file"): + filename = self.get("filename", "run") + file = os.path.join(working_dir, f"{filename}.json") + with open(file, "w") as f: + f.write(json.dumps(gout_dict, default=DATETIME_HANDLER)) + run_list["run_loc_list"] = file + logger.info("Saved parsed output to json file") + + uid = self.get("gout_key") + set_dict = {f"gaussian_output->{DEFAULT_KEY}": gout_dict} + if uid: + set_dict[f"gaussian_output->{uid}"] = gout_dict + # fw_spec = {'gaussian_output: {DEFAULT_KEY: gout_dict, uid: gout_dict}} + mod_dict = {"_set": set_dict} + if run_list: + mod_dict.update({"_push": run_list}) + return FWAction(mod_spec=mod_dict, propagate=True) + else: + raise ValueError(f"Gaussian did not complete normally, Terminating")
+ + +
[docs]@explicit_serialize +class RetrieveGaussianOutput(FiretaskBase): + """ + Get a Gaussian output dict from ``fw_spec`` or the database, convert it to a + GaussianInput object, and add it to ``fw_spec``. + + Args: + db (str or dict, optional): Database credentials; could be provided as the path + to the db.json file or in the form of a dictionary. + gaussian_input_params (dict, optional): Parameters to use in creating the + ``GaussianInput`` object; if not provided, will use the ones in the passed + or retrieved Gaussian output dict. + run_id (str, optional): ID of the run to retrieve from the database; e.g. + "5e3737d9da0b1cbbd5d556f7". + inchi (str, optional): InChI of the molecule; used as a query criteria to + retrieve the run from the db. + functional (str, optional): Density functional of the run in the db; used as a + query criteria. + basis (str, optional): Basis set of the run in the db; used as a query criteria. + type (str, optional): Type of the Gaussian job run in the db; e.g. "opt" or + "freq"; used as a query criteria. + phase (str, optional): Phase of the run in the db; e.g. "gas" or "solution"; + used as a query criteria. + tag (str, optional): Tag of the run in the db; used as a query criteria. + """ + + required_params = [] + optional_params = [ + "db", + "gaussian_input_params", + "run_id", + "inchi", + "functional", + "basis", + "type", + "phase", + "tag", + ] + +
[docs] def run_task(self, fw_spec): + # if a Gaussian output dict is passed through fw_spec + if fw_spec.get("gaussian_output"): + run = pass_gout_dict(fw_spec, DEFAULT_KEY) + # run = fw_spec['gaussian_output'][DEFAULT_KEY] + + elif self.get("run_id"): + run = process_run( + operation_type="get_from_run_id", + run=self.get("run_id"), + db=self.get("db"), + ) + + # otherwise, try to retrieve gaussian output from db + else: + try: + query = { + "inchi": self.get("inchi"), + "smiles": self.get("smiles"), + "type": self.get("type"), + "functional": self.get("functional"), + "basis": self.get("basis"), + "phase": self.get("phase"), + } + if "tag" in self: + query["tag"] = self["tag"] + run = process_run( + operation_type="get_from_run_query", run=query, db=self.get("db") + ) + except pymongo.errors.ConnectionFailure as e: + print("Could not connect to server: %s" % e) + except Exception as e: + raise ValueError(e) + + # create a gaussian input object from run + if self.get("gaussian_input_params") is None: + logger.info( + "No gaussian input parameters provided; will use " "run parameters" + ) + inputs = {} + for k, v in run["input"].items(): + # use gaussian_input_params if defined, otherwise use run parameters + inputs[f"{k}"] = self.get("gaussian_input_params", {}).get( + f"{k}", run["input"].get(f"{k}") + ) + inputs["molecule"] = run["output"]["output"]["molecule"] + # TODO: check if this works in all cases + # (if we are saving to db and removing the class) + # inputs['molecule'] = process_mol('get_from_run_dict', run) + gaussin = GaussianInput.from_dict(inputs) + fw_spec["gaussian_input"] = gaussin
+ + +
[docs]@explicit_serialize +class ESPtoDB(FiretaskBase): + """ + Enter an ESP run into the database. + + Args: + keys (list): List of keys of Gaussian runs in fw_spec to use in building the + ESP document; e.g. these keys could correspond to optimization, frequency, + and ESP jobs leading to the final result. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the "db.json" file or in the form of a dictionary. + save_to_db (bool, optional): Whether to insert the ESP dict to the ESP + collection in the db. + save_to_file (bool, optional): Whether to save the ESP dict to a json file; if + True, will save to a file named "esp.json". + additional_prop_doc_fields (dict, optional): Additional fields to add to + the final ESP dict. + solvent_gaussian_inputs (str, optional): Gaussian inputs for the implicit + solvent model to add to the final ESP dict, if any. + solvent_properties (dict, optional): Implicit solvent properties to add to the + final ESP dict, if any. + """ + + required_params = ["keys"] + optional_params = [ + "db", + "save_to_db", + "save_to_file", + "additional_prop_doc_fields", + "solvent_gaussian_inputs", + "solvent_properties", + ] + +
[docs] def run_task(self, fw_spec): + keys = self["keys"] + db = self.get("db") + gout_dict = [pass_gout_dict(fw_spec, i) for i in keys] + # include opt fireworks in the list of gout_dict to calculate run time + full_gout_dict = gout_dict + [pass_gout_dict(fw_spec, i + "_opt") for i in keys] + full_gout_dict = [i for i in full_gout_dict if i is not None] + molecule = process_mol( + "get_from_run_dict", gout_dict[-1], charge=gout_dict[-1]["input"]["charge"] + ) + + mol_schema = get_chem_schema(molecule) + phase = gout_dict[-1]["phase"] + + # if one calculation is skipped, wall time is considered zero + run_time = sum([gout.get("wall_time (s)", 0) for gout in full_gout_dict]) + + esp_dict = { + "molecule": molecule.as_dict(), + "smiles": mol_schema["smiles"], + "inchi": mol_schema["inchi"], + "formula_alphabetical": mol_schema["formula_alphabetical"], + "chemsys": mol_schema["chemsys"], + "energy": gout_dict[-1]["output"]["output"]["final_energy"], + "esp": gout_dict[-1]["output"]["output"]["ESP_charges"], + "dipole_moment": gout_dict[-1]["output"]["output"]["dipole_moment"], + "functional": gout_dict[-1]["functional"], + "basis": gout_dict[-1]["basis"], + "phase": phase, + "tag": gout_dict[-1]["tag"], + "state": "successful", + "wall_time (s)": run_time, + "version": mispr_version, + "gauss_version": gout_dict[-1]["gauss_version"], + "last_updated": datetime.datetime.utcnow(), + } + + if phase == "solution": + solvent_gaussian_inputs = self.get("solvent_gaussian_inputs") + solvent_properties = self.get("solvent_properties", {}) + esp_dict = add_solvent_to_prop_dict( + esp_dict, solvent_gaussian_inputs, solvent_properties + ) + + # check if polarizability is available (from freq calc of esp workflow) + if "polarizability" in gout_dict[-2]["output"]["output"]: + esp_dict["polarizability"] = gout_dict[-2]["output"]["output"][ + "polarizability" + ] + + if self.get("additional_prop_doc_fields"): + esp_dict.update(self.get("additional_prop_doc_fields")) + + if fw_spec.get("run_id_list"): + esp_dict["run_ids"] = fw_spec["run_id_list"] + + if self.get("save_to_db"): + db = get_db(db) + db.insert_property( + "esp", + esp_dict, + [ + ("formula_alphabetical", 1), + ("smiles", 1), + ("inchi", 1), + ("chemsys", 1), + ("functional", 1), + ("basis", 1), + ("tag", 1), + ], + ) + + if fw_spec.get("run_loc_list"): + esp_dict["run_locs"] = fw_spec["run_loc_list"] + if self.get("save_to_file"): + if "run_ids" in esp_dict: + del esp_dict["run_ids"] + with open("esp.json", "w") as f: + f.write(json.dumps(esp_dict, default=DATETIME_HANDLER)) + + logger.info("esp calculation complete") + return FWAction()
+ + +
[docs]@explicit_serialize +class NMRtoDB(FiretaskBase): + """ + Enter an NMR run into the database. + + Args: + keys (list): List of keys of Gaussian runs in fw_spec to use in building the + NMR document; e.g. these keys could correspond to optimization, frequency, + and NMR jobs leading to the final result. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the db.json file or in the form of a dictionary. + save_to_db (bool, optional): Whether to insert the NMR dict to the NMR + collection in the db. + save_to_file (bool, optional): Whether to save the NMR dict to a json file; if + True, will save to a file named "nmr.json". + additional_prop_doc_fields (dict, optional): Additional fields to add to the final + NMR dict. + solvent_gaussian_inputs (str, optional): Gaussian inputs for the implicit + solvent model to add to the final NMR dict, if any. + solvent_properties (dict, optional): Implicit solvent properties to add to the + final NMR dict, if any. + """ + + required_params = ["keys"] + optional_params = [ + "db", + "save_to_db", + "save_to_file", + "additional_prop_doc_fields", + "solvent_gaussian_inputs", + "solvent_properties", + ] + +
[docs] def run_task(self, fw_spec): + keys = self["keys"] + db = self.get("db") + gout_dict = [pass_gout_dict(fw_spec, i) for i in keys] + # include opt fireworks in the list of gout_dict to calculate run time + full_gout_dict = gout_dict + [pass_gout_dict(fw_spec, i + "_opt") for i in keys] + full_gout_dict = [i for i in full_gout_dict if i is not None] + molecule = process_mol( + "get_from_run_dict", gout_dict[-1], charge=gout_dict[-1]["input"]["charge"] + ) + + mol_schema = get_chem_schema(molecule) + phase = gout_dict[-1]["phase"] + + # if one calculation is skipped, wall time is considered zero + run_time = sum([gout.get("wall_time (s)", 0) for gout in full_gout_dict]) + + nmr_dict = { + "molecule": molecule.as_dict(), + "smiles": mol_schema["smiles"], + "inchi": mol_schema["inchi"], + "formula_alphabetical": mol_schema["formula_alphabetical"], + "chemsys": mol_schema["chemsys"], + "energy": gout_dict[-1]["output"]["output"]["final_energy"], + "tensor": gout_dict[-1]["output"]["output"]["tensor"], + "functional": gout_dict[-1]["functional"], + "basis": gout_dict[-1]["basis"], + "phase": phase, + "tag": gout_dict[-1]["tag"], + "state": "successful", + "wall_time (s)": run_time, + "version": mispr_version, + "gauss_version": gout_dict[-1]["gauss_version"], + "last_updated": datetime.datetime.utcnow(), + } + + if phase == "solution": + solvent_gaussian_inputs = self.get("solvent_gaussian_inputs") + solvent_properties = self.get("solvent_properties", {}) + nmr_dict = add_solvent_to_prop_dict( + nmr_dict, solvent_gaussian_inputs, solvent_properties + ) + + if self.get("additional_prop_doc_fields"): + nmr_dict.update(self.get("additional_prop_doc_fields")) + + if fw_spec.get("run_id_list"): + nmr_dict["run_ids"] = fw_spec["run_id_list"] + + if self.get("save_to_db"): + db = get_db(db) + db.insert_property( + "nmr", + nmr_dict, + [ + ("formula_alphabetical", 1), + ("smiles", 1), + ("inchi", 1), + ("chemsys", 1), + ("functional", 1), + ("basis", 1), + ("tag", 1), + ], + ) + + if fw_spec.get("run_loc_list"): + nmr_dict["run_locs"] = fw_spec["run_loc_list"] + if self.get("save_to_file"): + if "run_ids" in nmr_dict: + del nmr_dict["run_ids"] + with open("nmr.json", "w") as f: + f.write(json.dumps(nmr_dict, default=DATETIME_HANDLER)) + + logger.info("nmr calculation complete") + return FWAction()
+ + +
[docs]@explicit_serialize +class BindingEnergytoDB(FiretaskBase): + """ + Enter a binding energy run into the database. The binding energy value is in eV. + + Args: + index (list): List of indices of the two sites in the molecules at which they + are expected to bind. + keys (list): List of keys of Gaussian runs in fw_spec to use in building the + binding energy document; e.g. these keys could correspond to set of + optimization and frequency jobs leading to the final result. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the "db.json" file or in the form of a dictionary. + save_to_db (bool, optional): Whether to insert the binding energy dict to the + binding energy collection in the db. + save_to_file (bool, optional): Whether to save the binding energy dict to a json + file; if True, will save to a file named "binding_energy.json". + additional_prop_doc_fields (dict, optional): Additional fields to add to the final + binding energy dict. + solvent_gaussian_inputs (str, optional): Gaussian inputs for the implicit + solvent model to add to the final binding energy dict, if any. + solvent_properties (dict, optional): Implicit solvent properties to add to the + final binding energy dict, if any. + """ + + required_params = ["index", "keys"] + optional_params = [ + "db", + "save_to_db", + "save_to_file", + "additional_prop_doc_fields", + "solvent_gaussian_inputs", + "solvent_properties", + ] + +
[docs] def run_task(self, fw_spec): + index = self["index"] + keys = self["keys"] + db = self.get("db") + gout_dict = [pass_gout_dict(fw_spec, i) for i in keys] + # include opt fireworks in the list of gout_dict to calculate run time + full_gout_dict = gout_dict + [pass_gout_dict(fw_spec, i + "_opt") for i in keys] + full_gout_dict = [i for i in full_gout_dict if i is not None] + molecules = [ + process_mol("get_from_run_dict", gout, charge=gout["input"]["charge"]) + for gout in gout_dict + ] + final_energies = [ + gout["output"]["output"]["final_energy"] for gout in gout_dict + ] + # be_key = 'binding_energy_{}_{}_eV'.format( + # str(molecules[0].species[index[0]]) + str(index[0]), + # str(molecules[1].species[index[1]]) + str(len(molecules[0]) + + # index[1])) + + be_value = ( + final_energies[2] - (final_energies[0] + final_energies[1]) + ) * HARTREE_TO_EV + + be = { + "sites": (index[0], len(molecules[0]) + index[1]), + "atoms": ( + str(molecules[0].species[index[0]]), + str(molecules[1].species[index[1]]), + ), + "value": be_value, + } + mol_schema = get_chem_schema(molecules[2]) + phase = gout_dict[-1]["phase"] + # if one calculation is skipped, wall time is considered zero + run_time = sum([gout.get("wall_time (s)", 0) for gout in full_gout_dict]) + + be_dict = { + "molecule": molecules[2].as_dict(), + "smiles": mol_schema["smiles"], + "inchi": mol_schema["inchi"], + "formula_alphabetical": mol_schema["formula_alphabetical"], + "chemsys": mol_schema["chemsys"], + "energy": final_energies[2], + "be_eV": be, + "functional": gout_dict[-1]["functional"], + "basis": gout_dict[-1]["basis"], + "phase": gout_dict[-1]["phase"], + "tag": gout_dict[-1]["tag"], + "state": "successful", + "wall_time (s)": run_time, + "version": mispr_version, + "gauss_version": gout_dict[-1]["gauss_version"], + "last_updated": datetime.datetime.utcnow(), + } + + if phase == "solution": + solvent_gaussian_inputs = self.get("solvent_gaussian_inputs") + solvent_properties = self.get("solvent_properties", {}) + be_dict = add_solvent_to_prop_dict( + be_dict, solvent_gaussian_inputs, solvent_properties + ) + + if self.get("additional_prop_doc_fields"): + be_dict.update(self.get("additional_prop_doc_fields")) + + if fw_spec.get("run_id_list"): + be_dict["run_ids"] = fw_spec["run_id_list"] + + if self.get("save_to_db"): + db = get_db(db) + db.insert_property( + "binding_energy", + be_dict, + [ + ("formula_alphabetical", 1), + ("smiles", 1), + ("inchi", 1), + ("chemsys", 1), + ("functional", 1), + ("basis", 1), + ("tag", 1), + ], + ) + + if fw_spec.get("run_loc_list"): + be_dict["run_locs"] = fw_spec["run_loc_list"] + if self.get("save_to_file"): + if "run_ids" in be_dict: + del be_dict["run_ids"] + with open("binding_energy.json", "w") as f: + f.write(json.dumps(be_dict, default=DATETIME_HANDLER)) + + logger.info("binding energy calculation complete") + return FWAction()
+ + +
[docs]@explicit_serialize +class IPEAtoDB(FiretaskBase): + """ + Insert a redox potential run into the database. Save both Gibbs free energies and + redox potentials. If a calculation is performed in multiple steps, will save all + intermediate energies. + + Args: + num_electrons (int): Number of electrons transferred. + states (list): List of states used in the calculation; e.g. ["cation"] for + oxidation, ["anion"] for reduction, or ["cation", "anion"] for oxidation + and reduction calculations. + phases (list): List of phases to involved in the calculations; e.g. ["solution"] + for liquid phase, ["gas"] for gas phase, or ["gas", "solution"] for the + full thermodynamic cycle. + steps (str): Whether the redox potential calculation is performed in a single + or multi step electron transfer process. + root_node_key (str): Key of the Gaussian run corresponding to the root node in + ``fw_spec``. + keys (list): List of keys of Gaussian runs in fw_spec to use in building the + redox potential document; e.g. these keys could correspond to set of + optimization and frequency jobs leading to the final result. + pcet (bool): Whether a PCET calculation is performed. + vertical (bool): Whether a vertical IP/EA calculation is performed. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the "db.json" file or in the form of a dictionary. + save_to_db (bool, optional): Whether to insert the redox potential dict to the + redox potential collection in the db. + save_to_file (bool, optional): Whether to save the redox potential dict to a json + file; if True, will save to a file named "ip_ea.json". + solvent_gaussian_inputs (str, optional): Gaussian inputs for the implicit + solvent model to add to the redox potential dict, if any. + solvent_properties (dict, optional): Implicit solvent properties to add to the + final redox potential dict, if any. + electrode_potentials (dict, optional): Dictionary of additional electrode + potentials to be used in converting the absolute oxidation and reduction + potentials to commonly used potential scales; note that the hydrogen, + lithium, and magnesium scales are already included; the dictionary should + be in the form: + + .. code-block:: python + + { + "<metal>": { + "potential": <float>, + "ref": bibtex_parser("<ref_bib_file>", dir), + } + } + + .. note:: + bibtexparser needs to be imported from mispr.gaussian.utilities.files. + + additional_prop_doc_fields (dict, optional): Additional fields to add to the final + redox potential dict. + gibbs_elec (float, optional): The electron gibbs free energy in Hartree. + gibbs_h (float, optional): The hydrogen gibbs free energy in Hartree. + """ + + required_params = [ + "num_electrons", + "states", + "phases", + "steps", + "root_node_key", + "keys", + "pcet", + "vertical", + ] + optional_params = [ + "db", + "save_to_db", + "save_to_file", + "solvent_gaussian_inputs", + "solvent_properties", + "electrode_potentials", + "additional_prop_doc_fields", + "gibbs_elec", + "gibbs_h", + ] + +
[docs] def run_task(self, fw_spec): + db = self.get("db") + num_electrons = self["num_electrons"] + states = self["states"] + phases = self["phases"] + steps = self["steps"] + root_node_key = self["root_node_key"] + pcet = self["pcet"] + keys = self["keys"] + vertical = self["vertical"] + gibbs_elec = self.get("gibbs_elec") + gibbs_h = self.get("gibbs_h") + + data_dir = os.path.join(os.path.dirname(__file__), "../data") + ref_potentials = { + "hydrogen": { + "potential": 4.43, + "ref": bibtex_parser("h_pot.bib", data_dir), + }, + "magnesium": { + "potential": 2.375, + "ref": bibtex_parser("mg_pot.bib", data_dir), + }, + "lithium": { + "potential": 1.40, + "ref": bibtex_parser("li_pot.bib", data_dir), + }, + } + electrode_potentials = self.get("electrode_potentials") or {} + electrode_potentials = {**ref_potentials, **electrode_potentials} + gout_dict = {i: pass_gout_dict(fw_spec, i) for i in keys} + # include opt fireworks in the list of gout_dict to calculate run time + full_gout_dict = list(gout_dict.values()) + [ + pass_gout_dict(fw_spec, i + "_opt") for i in keys + ] + full_gout_dict = [i for i in full_gout_dict if i is not None] + molecule = process_mol( + "get_from_run_dict", + gout_dict[root_node_key], + charge=gout_dict[root_node_key]["input"]["charge"], + ) + final_energies = { + i: j["output"]["output"]["final_energy"] for i, j in gout_dict.items() + } + free_energy_corrections = { + i: j["output"]["output"]["corrections"]["Gibbs Free Energy"] + for i, j in gout_dict.items() + } + free_energies = { + key: final_energies[key] + free_energy_corrections[key] + for key in gout_dict.keys() + } + + # if one calculation is skipped, wall time is considered zero + run_time = sum([gout.get("wall_time (s)", 0) for gout in full_gout_dict]) + + def _name_(e1, e2, h1, h2): + if pcet: + return f"{e1}e{h1}h_{e2}e{h2}h" + else: + return f"{e1}e_{e2}e" + + def _gibbs_to_redox(s, g, e_count): + redox_result = -s * g / ((1 / HARTREE_TO_KJ) * e_count * FARAD) + return redox_result + + def _gibbs_to_pka(g): + pka_result = ( + g * HARTREE_TO_KJ / (-1 / np.log10(np.exp(1)) * R / 1000 * 298.15) + ) + return pka_result + + # TODO: PCET --> what to save (IP, EA, pKA, intermediate results)? + # TODO: possible to have multiple H transfer in single step? same pka + # calc, divide by 2? + # TODO: gibbs_h in gas vs sol or same? + gibbs_dict = {} + redox_dict = {} + for state in states: + process = "oxidation" if state == "cation" else "reduction" + gibbs_dict[process] = {} + redox_dict[process] = {} + sign = 1 if state == "anion" else -1 + for phase in phases: + gibbs_dict[process][phase] = {} + redox_dict[process][phase] = {} + # steps not involving h transfer + if not pcet or sign > 0: + for h in range((num_electrons + 1) * pcet + (1 - pcet)): + n1 = f"{phase.lower()}_0_{h}" + n2 = f"{phase.lower()}_{sign * num_electrons}_{h}" + name = _name_(0, sign * num_electrons, h, h) + gibbs = ( + free_energies[n2] + - free_energies[n1] + - sign * gibbs_elec * num_electrons + ) + gibbs_dict[process][phase][name] = gibbs * HARTREE_TO_EV + redox = _gibbs_to_redox(sign, gibbs, num_electrons) + redox_dict[process][phase][name] = {} + redox_dict[process][phase][name]["raw"] = redox + for key, value in electrode_potentials.items(): + redox_dict[process][phase][name][key] = ( + redox - value["potential"] + ) + if steps == "multi": + for i in range(num_electrons): + n1 = f"{phase.lower()}_{sign * i}_{h}" + n2 = f"{phase.lower()}_{sign * (i + 1)}_{h}" + name = _name_(sign * i, sign * (i + 1), h, h) + gibbs = ( + free_energies[n2] + - free_energies[n1] + - sign * gibbs_elec + ) + gibbs_dict[process][phase][name] = gibbs * HARTREE_TO_EV + redox = _gibbs_to_redox(sign, gibbs, 1) + redox_dict[process][phase][name] = {} + redox_dict[process][phase][name]["raw"] = redox + for key, value in electrode_potentials.items(): + redox_dict[process][phase][name][key] = ( + redox - value["potential"] + ) + # steps involving h transfer + else: + # 1st ind --> elec, 2nd ind --> hydrogen + n1 = f"{phase.lower()}_0_0" + n2 = f"{phase.lower()}_{num_electrons}_{num_electrons}" + name = _name_(0, num_electrons, 0, num_electrons) + gibbs = ( + free_energies[n2] - free_energies[n1] - gibbs_h * num_electrons + ) + gibbs_dict[process][phase][name] = gibbs * HARTREE_TO_EV + for e in range(num_electrons + 1): + n1 = f"{phase.lower()}_{e}_0" + n2 = f"{phase.lower()}_{e}_{num_electrons}" + name = _name_(e, e, 0, num_electrons) + gibbs = ( + free_energies[n2] + - free_energies[n1] + - gibbs_h * num_electrons + ) + pka = _gibbs_to_pka(gibbs) + gibbs_dict[process][phase][name] = gibbs * HARTREE_TO_EV + redox_dict[process][phase][name] = pka + if steps == "multi": + for i in range(num_electrons): + n1 = f"{phase.lower()}_{e}_{i}" + n2 = f"{phase.lower()}_{e}_{i + 1}" + name = _name_(e, e, i, i + 1) + gibbs = free_energies[n2] - free_energies[n1] - gibbs_h + pka = _gibbs_to_pka(gibbs) + gibbs_dict[process][phase][name] = gibbs * HARTREE_TO_EV + redox_dict[process][phase][name] = pka + + mol_schema = get_chem_schema(molecule) + ip_ea_dict = { + "molecule": molecule.as_dict(), + "smiles": mol_schema["smiles"], + "inchi": mol_schema["inchi"], + "formula_alphabetical": mol_schema["formula_alphabetical"], + "chemsys": mol_schema["chemsys"], + "num_electrons": num_electrons, + "functional": gout_dict[root_node_key]["functional"], + "basis": gout_dict[root_node_key]["basis"], + "phase": phases, + "steps": steps, + "vertical": vertical, + "pcet": pcet, + "gibbs_elec": gibbs_elec * HARTREE_TO_EV, + "gibbs_h": gibbs_h * HARTREE_TO_EV, + "gibbs": gibbs_dict, + "potentials": redox_dict, + "standard_potentials": electrode_potentials, + "tag": gout_dict[root_node_key]["tag"], + "state": "successful", + "wall_time (s)": run_time, + "version": mispr_version, + "gauss_version": gout_dict[root_node_key]["gauss_version"], + "last_updated": datetime.datetime.utcnow(), + } + + if "solution" in phases: + solvent_gaussian_inputs = self.get("solvent_gaussian_inputs") + solvent_properties = self.get("solvent_properties", {}) + ip_ea_dict = add_solvent_to_prop_dict( + ip_ea_dict, solvent_gaussian_inputs, solvent_properties + ) + + if self.get("additional_prop_doc_fields"): + ip_ea_dict.update(self.get("additional_prop_doc_fields")) + + if fw_spec.get("run_id_list"): + ip_ea_dict["run_ids"] = fw_spec["run_id_list"] + + if self.get("save_to_db"): + db = get_db(db) + db.insert_property( + "ip_ea", + ip_ea_dict, + [ + ("formula_alphabetical", 1), + ("smiles", 1), + ("inchi", 1), + ("chemsys", 1), + ("functional", 1), + ("basis", 1), + ("tag", 1), + ], + ) + + if fw_spec.get("run_loc_list"): + ip_ea_dict["run_locs"] = fw_spec["run_loc_list"] + if self.get("save_to_file"): + if "run_ids" in ip_ea_dict: + del ip_ea_dict["run_ids"] + with open("ip_ea.json", "w") as f: + f.write(json.dumps(ip_ea_dict, default=DATETIME_HANDLER)) + + logger.info("ip/ea calculation complete") + return FWAction()
+ + +
[docs]@explicit_serialize +class BDEtoDB(FiretaskBase): + """ + Enter a bond dissociation energy calculation into the database. The calculation can + correspond to one or more bonds in the same molecule. + + Args: + principle_mol_key (str, optional): Key of the Gaussian run corresponding to the + principle molecule in the ``fw_spec``. + db (str or dict, optional): Database credentials to store the run; could be + provided as the path to the "db.json" file or in the form of a dictionary. + save_to_db (bool, optional): Whether to insert the BDE dict to the BDE + collection in the db. + save_to_file (bool, optional): Whether to save the BDE dict to a json file; if + True, will save to a file named "bde.json". + solvent_gaussian_inputs (str, optional): Gaussian inputs for the implicit + solvent model to add to the BDE dict, if any. + solvent_properties (dict, optional): Implicit solvent properties to add to the + final BDE dict, if any. + additional_prop_doc_fields (dict, optional): Additional fields to add to the final + BDE dict. + visualize (bool, optional): Whether to create a bar plot of the BDE results + along with the 2D structure of the principle molecule with highlighted + broken bonds. + color (tuple, optional): RGB color to use for highlighting the broken bonds in + the molecule; e.g. (0.0, 0.0, 0.0) for black; if not provided, will use + (197 / 255, 237 / 255, 223 / 255, 1). + """ + + required_params = [] + optional_params = [ + "principle_mol_key", + "db", + "save_to_db", + "save_to_file", + "solvent_gaussian_inputs", + "solvent_properties", + "additional_prop_doc_fields", + "visualize", + "color", + ] + +
[docs] def run_task(self, fw_spec): + db = self.get("db") + principle_mol_key = self.get("principle_mol_key", "ref_mol") + keys = [principle_mol_key] + fw_spec["frag_keys"] + bonds = fw_spec["bonds"] + molecule_indices = fw_spec["molecule_indices"] + gout_dict = {i: pass_gout_dict(fw_spec, i) for i in keys} + # include opt fireworks in the list of gout_dict to calculate run time + full_gout_dict = list(gout_dict.values()) + [ + pass_gout_dict(fw_spec, i + "_opt") for i in keys + ] + full_gout_dict = [i for i in full_gout_dict if i is not None] + molecule = process_mol( + "get_from_run_dict", + gout_dict[principle_mol_key], + charge=gout_dict[principle_mol_key]["input"]["charge"], + ) + phase = gout_dict[principle_mol_key]["phase"] + final_energies = { + i: j["output"]["output"]["final_energy"] for i, j in gout_dict.items() + } + enthalpy_corrections = { + i: j["output"]["output"]["corrections"]["Enthalpy"] + for i, j in gout_dict.items() + } + enthalpies = { + key: final_energies[key] + enthalpy_corrections[key] + for key in gout_dict.keys() + } + + run_time = sum([gout.get("wall_time (s)", 0) for gout in full_gout_dict]) + + fragments = {} + for gout_key, gout in gout_dict.items(): + if gout_key != principle_mol_key: + frag = process_mol( + "get_from_run_dict", gout, charge=gout["input"]["charge"] + ) + frag_schema = get_chem_schema(frag) + fragments.update( + { + gout_key: { + "fragment": frag.as_dict(), + "smiles": frag_schema["smiles"], + "inchi": frag_schema["inchi"], + "formula_alphabetical": frag_schema["formula_alphabetical"], + "chemsys": frag_schema["chemsys"], + "energy": final_energies[gout_key], + } + } + ) + + bde_results = {} + for ind, [bond, mol_ind] in enumerate(zip(bonds, molecule_indices)): + frag_pairs = {} + for i, j in enumerate(mol_ind): + frag_ind = [j[count] for count in range(len(j))] + frag_tuple = tuple([f"frag_{ind}" for ind in frag_ind]) + # try to calculate BDE from fragment pair results; + # if the fragment is not found because the calculation failed, + # move to the next pair and throw a warning + try: + fragment_energies_sum = sum( + [enthalpies[frag] for frag in frag_tuple] + ) + frag_pairs.update( + { + str(frag_ind): ( + fragment_energies_sum - enthalpies[principle_mol_key] + ) + * HARTREE_TO_EV + } + ) + except KeyError: + logger.warning("Results not found for pairs: {}".format(frag_tuple)) + bde_results.update({str(bond): frag_pairs}) + + # if at least one BDE is calculated, continue with creating final dict + if any(bde_results.values()): + mol_schema = get_chem_schema(molecule) + bde_dict = { + "molecule": molecule.as_dict(), + "smiles": mol_schema["smiles"], + "inchi": mol_schema["inchi"], + "formula_alphabetical": mol_schema["formula_alphabetical"], + "chemsys": mol_schema["chemsys"], + "energy": final_energies[principle_mol_key], + "functional": gout_dict[principle_mol_key]["functional"], + "basis": gout_dict[principle_mol_key]["basis"], + "phase": phase, + "fragments": fragments, + "bde_eV": bde_results, + "tag": gout_dict[principle_mol_key]["tag"], + "state": "successful", + "wall_time (s)": run_time, + "version": mispr_version, + "gauss_version": gout_dict[principle_mol_key]["gauss_version"], + "last_updated": datetime.datetime.utcnow(), + } + + if phase == "solution": + solvent_gaussian_inputs = self.get("solvent_gaussian_inputs") + solvent_properties = self.get("solvent_properties", {}) + bde_dict = add_solvent_to_prop_dict( + bde_dict, solvent_gaussian_inputs, solvent_properties + ) + + if self.get("visualize"): + # if RDKit is not installed, throw a warning message and proceed + # normally; visualization will not be done + try: + num_bonds = len(bonds) + rdkit_mol = get_rdkit_mol(molecule) + color = tuple( + self.get("color", (197 / 255, 237 / 255, 223 / 255, 1)) + ) + max_bond = 10 # max # of bonds above which to change sizes + fig_size = tuple( + [int(num_bonds / max_bond) * 4 + i for i in (8, 6)] + ) + _ = draw_rdkit_mol_with_highlighted_bonds( + rdkit_mol, + bonds, + colors=[color] * num_bonds, + filename="mol_bonds.png", + ) + fig, (ax, picture) = plt.subplots( + ncols=2, + figsize=fig_size, + gridspec_kw={"width_ratios": [2, 1.2]}, + ) + + mol_image = img.imread("mol_bonds.png") + picture.imshow(mol_image) + picture.axis("off") + os.remove("mol_bonds.png") + + margin = 0.2 + width = 1 - 2 * margin / num_bonds + gap = num_bonds + margin + width + x_ticks = [] + xtick_labels = [] + for ind, bond in enumerate(bonds): + data = [ + gap + (1 + i) * width + for i in range(len(bde_results[str(bond)])) + ] + gap = data[-1] + width + int(num_bonds / max_bond) + x_ticks.append(sum(data) / len(data)) + # xtick_labels.append( + # '{}:{}-{}'.format(str(ind), + # (str(molecule.species[bond[0]])), + # (str(molecule.species[bond[1]])))) + xtick_labels.append("{}".format(str(ind))) + ax.bar( + data, + list(bde_results[str(bond)].values()), + width, + color=color, + edgecolor="black", + align="center", + ) + ax.set_aspect(1.0 / ax.get_data_ratio(), adjustable="box") + ax.set_xticks(np.array(x_ticks)) + # ax.set_xticklabels(xtick_labels, rotation=45) + ax.set_xticklabels(xtick_labels) + ax.tick_params(axis="x", length=0, labelsize=16) + ax.tick_params(axis="y", direction="in", length=8, labelsize=16) + ax.set_xlabel("Bond number", fontsize=16) + ax.set_ylabel("BDE (eV)", fontsize=16) + plt.savefig("bde.png", bbox_inches="tight", pad_inches=0.2) + except Exception as e: + logger.warning(e) + + if self.get("additional_prop_doc_fields"): + bde_dict.update(self.get("additional_prop_doc_fields")) + + if fw_spec.get("run_id_list"): + bde_dict["run_ids"] = fw_spec["run_id_list"] + + if self.get("save_to_db"): + db = get_db(db) + db.insert_property( + "bde", + bde_dict, + [ + ("formula_alphabetical", 1), + ("smiles", 1), + ("inchi", 1), + ("chemsys", 1), + ("functional", 1), + ("basis", 1), + ("tag", 1), + ], + ) + + if fw_spec.get("run_loc_list"): + bde_dict["run_locs"] = fw_spec["run_loc_list"] + if self.get("save_to_file"): + if "run_ids" in bde_dict: + del bde_dict["run_ids"] + with open("bde.json", "w") as f: + f.write(json.dumps(bde_dict, default=DATETIME_HANDLER)) + + logger.info("bde calculation complete") + + else: + logger.error("No BDE was calculated. Exiting ...") + sys.exit() + return FWAction()
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/firetasks/run_calc.html b/html/_modules/mispr/gaussian/firetasks/run_calc.html new file mode 100644 index 00000000..2b5c29ff --- /dev/null +++ b/html/_modules/mispr/gaussian/firetasks/run_calc.html @@ -0,0 +1,1103 @@ + + + + + + + + + + + + + + + + mispr.gaussian.firetasks.run_calc - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.firetasks.run_calc

+"""Define firetasks for running Gaussian calculations."""
+
+import os
+import shutil
+import logging
+import subprocess
+
+from timeit import default_timer as timer
+from configparser import ConfigParser
+
+import numpy as np
+
+from monty.os.path import zpath
+from monty.serialization import loadfn
+
+from pymatgen.io.gaussian import GaussianInput
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+from fireworks.core.firework import Firework, FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+
+from custodian import Custodian
+from custodian.gaussian.jobs import GaussianJob
+from custodian.gaussian.handlers import WallTimeErrorHandler, GaussianErrorHandler
+
+from mispr.gaussian.defaults import CUSTODIAN_MAX_ERRORS
+from mispr.gaussian.utilities.misc import recursive_compare_dicts
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]@explicit_serialize +class RunGaussianDirect(FiretaskBase): + """ + Execute a command directly for running Gaussian (no custodian). + + Args: + input_file (str, optional): Name of the Gaussian input file. + output_file (str, optional): Name of the Gaussian output file. + gaussian_cmd (str, optional): Name of the full executable to run; if not + provided, will attempt to find the command in the config file. + """ + + required_params = [] + optional_params = ["input_file", "output_file", "gaussian_cmd"] + +
[docs] def run_task(self, fw_spec): + working_dir = os.getcwd() + + input_file = self.get("input_file", "mol.com") + input_path = os.path.join(working_dir, input_file) + + output_file = self.get("output_file", "mol.out") + output_path = os.path.join(working_dir, output_file) + + cmd = self.get("gaussian_cmd") + if not cmd: + cfg = ConfigParser() + cfg.read(CONFIG_FILE_DIR + "/config.ini") + cmd = cfg["RunCalc"]["gcmd"] + cmd = cmd.replace("$input_path$", input_path).replace( + "$output_path$", output_path + ) + + logger.info("Running command: {}".format(cmd)) + st = timer() + return_code = subprocess.call(cmd, shell=True) + run_time = timer() - st + logger.info("Finished running with return code: {}".format(return_code)) + fw_spec["run_time"] = run_time
+ + +
[docs]@explicit_serialize +class RunGaussianCustodian(FiretaskBase): + """ + Run Gaussian using custodian. + + Args: + input_file (str, optional): Name of the Gaussian input file. + output_file (str, optional): Name of the Gaussian output file. + gaussian_cmd (str, optional): Name of the full executable to run; if not + provided, will attempt to find the command in the config file. + stderr_file (str, optional): Name of the file to direct standard error to. + job_type (str, optional): Type of job to run; supported options are (1) normal + and (2) better_guess. Defaults to "normal". + backup (bool, optional): Whether to backup the initial input file; if True, + the input will be copied with a ".orig" appended. Defaults to True. + scf_max_cycles (int, optional): Maximum number of SCF cycles to run; + defaults to 100. + opt_max_cycles (int, optional): Maximum number of optimization cycles to run; + defaults to 100. + cart_coords (bool, optional): Whether to use cartesian coordinates; + defaults to True. + max_errors (int, optional): Maximum number of errors to handle before giving + up. Defaults to the number specified in ``mispr.gaussian.defaults.py``. + lower_functional (str, optional): Lower level of theory to use if the + optimization fails and job_type is set to "better_guess; this will attempt + to generate a better initial guess of the geometry before running the + job again at the higher level of theory. + lower_basis_set (str, optional): Less expensive basis set to use if the + optimization fails and job_type is set to "better_guess; this will attempt + to generate a better initial guess of the geometry before running the job + again at the higher level of theory. + prefix (str, optional): Prefix to the files. Defaults to error, which means a + series of error.1.tar.gz, error.2.tar.gz, ... will be generated. + suffix (str, optional): A suffix to be appended to the final output; + e.g., to rename all Gaussian output from mol.out to mol.out.1, provide ".1" + as the suffix. + check_convergence (bool, optional): Whether to check convergence in an + optimization job; this will also generate a plot with the convergence + criteria as a function of the number of iterations. Defaults to True. + wall_time (int, optional): Wall time set to the job in seconds; if provided, + will add the ``WallTimeErrorHandler``, which will restart the job if it hits + the wall time limit. + buffer_time (int, optional): Buffer time set to the job in seconds; if + provided; if the remaining time for the job = buffer_time, the + ``WallTimeErrorHandler`` will cancel the job and restart it; this is done + because if the job hits wall time on its own and is cancelled, it will no + longer be possible to restart it. Defaults to 300 seconds. + max_wall_time_corrections (int, optional): Maximum number of wall time + corrections to make. Defaults to 3. + """ + + required_params = [] + optional_params = [ + "input_file", + "output_file", + "gaussian_cmd", + "stderr_file", + "job_type", + "backup", + "scf_max_cycles", + "opt_max_cycles", + "cart_coords", + "max_errors", + "lower_functional", + "lower_basis_set", + "prefix", + "suffix", + "check_convergence", + "wall_time", + "buffer_time", + "max_wall_time_corrections", + "additional_fw", + ] + +
[docs] def run_task(self, fw_spec): + # working_dir = os.getcwd() + + input_file = self.get("input_file", "mol.com") + wt_input_file = fw_spec.get("overwrite_input_file", input_file) + + # input_path = os.path.join(working_dir, input_file) + + output_file = self.get("output_file", "mol.out") + # output_path = os.path.join(working_dir, output_file) + + backup = self.get("backup", True) + prefix = self.get("prefix", "error") + stderr_file = self.get("stderr_file", "stderr.txt") + scf_max_cycles = self.get("scf_max_cycles", 100) + opt_max_cycles = self.get("opt_max_cycles", 100) + max_errors = self.get("max_errors", CUSTODIAN_MAX_ERRORS) + + job_type = self.get("job_type", "normal") + lower_functional = self.get("lower_functional", None) + lower_basis_set = self.get("lower_basis_set", None) + cart_coords = self.get("cart_coords", True) + check_convergence = self.get("check_convergence", True) + wall_time = self.get("wall_time", None) + buffer_time = self.get("buffer_time", 300) + + cmd = self.get("gaussian_cmd") + if not cmd: + cfg = ConfigParser() + cfg.read(CONFIG_FILE_DIR + "/config.ini") + cmd = cfg["RunCalc"]["gcmd"] + cmd = cmd.replace("$input_path$", wt_input_file).replace( + "$output_path$", output_file + ) + + if job_type == "normal": + jobs = [ + GaussianJob( + gaussian_cmd=cmd, + input_file=input_file, + output_file=output_file, + stderr_file=stderr_file, + suffix=self.get("suffix", ""), + backup=backup, + ) + ] + + elif job_type == "better_guess": + if not lower_functional or not lower_basis_set: + raise Exception( + f"{job_type} is requested but the functional " + f"and/or basis set to use for the SCF " + f"calculation are not provided! Exiting..." + ) + jobs = GaussianJob.generate_better_guess( + gaussian_cmd=cmd, + input_file=input_file, + output_file=output_file, + stderr_file=stderr_file, + backup=backup, + cart_coords=cart_coords, + directory=os.getcwd(), + ) + else: + raise ValueError(f"Unsupported job type: {job_type}") + + handlers = [ + GaussianErrorHandler( + input_file=input_file, + output_file=output_file, + stderr_file=stderr_file, + cart_coords=cart_coords, + scf_max_cycles=scf_max_cycles, + opt_max_cycles=opt_max_cycles, + job_type=job_type, + lower_functional=lower_functional, + lower_basis_set=lower_basis_set, + prefix=prefix, + check_convergence=check_convergence, + ) + ] + if wall_time: + handlers.append( + WallTimeErrorHandler( + wall_time=wall_time, + buffer_time=buffer_time, + input_file=input_file, + output_file=output_file, + stderr_file=stderr_file, + prefix=prefix, + ) + ) + + c = Custodian(handlers, jobs, max_errors=max_errors) + + st = timer() + try: + return_code = c.run() + except Exception as e: + # TODO: add a checkpoint here that fw_id is accessible + # (only if _add_launchpad_and_fw_id is True in the fw_spec) + if ( + os.path.exists(zpath("custodian.json")) + and os.path.getsize("custodian.json") > 0 + ): + custodian_data = loadfn(zpath("custodian.json")) + for entry in custodian_data: + for correction in entry.get("corrections"): + if "wall_time_limit" in correction.get("errors"): + if fw_spec.get( + "number_of_wall_time_corrections", 0 + ) <= self.get("max_wall_time_corrections", 3): + print( + "correction number:", + fw_spec.get("number_of_wall_time_corrections", 0), + ) + fw = self.launchpad.get_fw_by_id(self.fw_id) + fw.spec.update( + { + "_recovery": self.launchpad.get_recovery( + self.fw_id + ), + "number_of_wall_time_corrections": fw_spec.get( + "number_of_wall_time_corrections", 0 + ) + + 1, + "overwrite_input_file": input_file + ".wt", + } + ) + new_fw = Firework(fw.tasks, fw.spec, fw.name) + return FWAction(detours=[new_fw]) + raise e + run_time = timer() - st + logger.info("Finished running with return code: {}".format(return_code)) + fw_spec["run_time"] = run_time
+ + +
[docs]@explicit_serialize +class RunGaussianFake(FiretaskBase): + """ + Run a fake Gaussian calculation. + + Args: + ref_dir (str): Path to reference Gaussian run directory with input and output + files in the folder. + working_dir (str, optional): Directory where the fake calculation will be run. + input_file (str, optional): Name of the input file (both reference input and new + input). Defaults to mol.com. + tolerance (float, optional): Tolerance for the comparison of the reference and + user input file. Defaults to 0.0001. + """ + + required_params = ["ref_dir"] + optional_params = ["working_dir", "input_file", "tolerance"] + +
[docs] def run_task(self, fw_spec): + self._verify_inputs() + self._clear_inputs() + self._generate_outputs()
+ + @staticmethod + def _recursive_lowercase(obj): + if isinstance(obj, dict): + updated_obj = {} + for k, v in obj.items(): + updated_obj[k.lower()] = RunGaussianFake._recursive_lowercase(v) + return updated_obj + elif isinstance(obj, str): + return obj.lower() + elif hasattr(obj, "__iter__"): + updated_obj = [] + for i in obj: + updated_obj.append(RunGaussianFake._recursive_lowercase(i)) + return updated_obj + else: + return obj + + def _verify_inputs(self): + ref_dir = self["ref_dir"] + working_dir = self.get("working_dir", os.getcwd()) + gin_file = self.get("input_file", "mol.com") + + user_gin = GaussianInput.from_file(f"{working_dir}/{gin_file}") + ref_gin = GaussianInput.from_file(f"{ref_dir}/{gin_file}") + tol = self.get("tolerance") or 0.0001 + + np.testing.assert_equal(ref_gin.molecule.species, user_gin.molecule.species) + np.testing.assert_allclose( + ref_gin.molecule.cart_coords, user_gin.molecule.cart_coords, atol=tol + ) + + ref_dict = self._recursive_lowercase(ref_gin.as_dict()) + del ref_dict["molecule"] + user_dict = self._recursive_lowercase(user_gin.as_dict()) + del user_dict["molecule"] + diff = recursive_compare_dicts(ref_dict, user_dict, "ref_dict", "user_dict") + + if diff: + raise ValueError( + f"Gaussian input is inconsistent with reference input!\n{diff}!" + ) + logger.info("RunGausianFake: verified input successfully") + + def _clear_inputs(self): + working_dir = self.get("working_dir", os.getcwd()) + gin_file = self.get("input_file", "mol.com") + gin_file = f"{working_dir}/{gin_file}" + if os.path.exists(gin_file): + os.remove(gin_file) + + def _generate_outputs(self): + ref_dir = self["ref_dir"] + working_dir = self.get("working_dir", os.getcwd()) + for file in os.listdir(ref_dir): + full_path = f"{ref_dir}/{file}" + if os.path.isfile(full_path): + shutil.copy(full_path, working_dir) + logger.info("RunGaussianFake: ran fake Gaussian, generated outputs")
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/firetasks/write_inputs.html b/html/_modules/mispr/gaussian/firetasks/write_inputs.html new file mode 100644 index 00000000..ca7d448e --- /dev/null +++ b/html/_modules/mispr/gaussian/firetasks/write_inputs.html @@ -0,0 +1,864 @@ + + + + + + + + + + + + + + + + mispr.gaussian.firetasks.write_inputs - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.firetasks.write_inputs

+"""Define firetasks for writing Gaussian input files."""
+
+import os
+
+from copy import deepcopy
+
+from pymatgen.io.gaussian import GaussianInput
+from pymatgen.core.structure import IMolecule
+from pymatgen.analysis.graphs import MoleculeGraph
+from pymatgen.analysis.local_env import OpenBabelNN
+
+from fireworks.core.firework import FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+
+
[docs]@explicit_serialize +class WriteInput(FiretaskBase): + """ + Write Gaussian input file for a molecule/cluster in the current working directory. + + Args: + gaussian_input (GaussianInput, optional): A ``GaussianInput`` object to be + written to a file; can either be provided directly or passed through + ``fw_spec``; if both are provided, will take the one provided directly. + molecule (Molecule, optional): A ``Molecule`` object to be used in creating + Gaussian input file; can be provided as an optional parameter or passed + through ``fw_spec``; if both are provided, will check if their graphs are + isomorphic; if they are isomorphic, will use the molecule passed through + ``fw_spec``, otherwise will take the user input; note that molecule is + ignored if a ``gaussian_input`` is available. + gaussian_input_params (dict, optional): A dictionary of parameters to be used + in creating the Gaussian input file; ignored if a ``gaussian_input`` is + provided. + input_file (str, optional): Name of the input file to be written; default is + "mol.com". + cart_coords (bool, optional): Whether to write cartesian coordinates or not; + default is True. + oxidation_states (dict, optional): A dictionary of element symbols and their + oxidation states used in setting the charge on the molecule. + """ + + _fw_name = "Write Gaussian Input File" + + required_params = [] + optional_params = [ + "gaussian_input", + "molecule", + "gaussian_input_params", + "input_file", + "cart_coords", + "oxidation_states", + ] + + def _update_charge(self, mol): + """ + Calculates the charge of a molecule/cluster using the oxidation state + of individual elements. + """ + if self.get("oxidation_states"): + mol_copy = deepcopy(mol) + mol_copy.add_oxidation_state_by_element(self.get("oxidation_states")) + mol_copy.set_charge_and_spin(super(IMolecule, mol_copy).charge) + self["gaussian_input_params"] = { + **self.get("gaussian_input_params", {}), + "charge": int(mol_copy.charge), + } + +
[docs] def run_task(self, fw_spec): + working_dir = os.getcwd() + + input_file = self.get("input_file", "mol.com") + input_path = os.path.join(working_dir, input_file) + + # if a full Gaussian object is provided + if self.get("gaussian_input") and isinstance( + self.get("gaussian_input"), GaussianInput + ): + gaussin = self["gaussian_input"] + + # if a full Gaussian object is being passed through fw_spec + elif fw_spec.get("gaussian_input") and isinstance( + fw_spec.get("gaussian_input"), GaussianInput + ): + gaussin = fw_spec.get("gaussian_input") + + # if a molecule is being passed through fw_spec + elif fw_spec.get("prev_calc_molecule"): + prev_calc_mol = fw_spec.get("prev_calc_molecule") + # if a molecule is also passed as an optional parameter + if self.get("molecule"): + mol = self.get("molecule") + mol_graph = MoleculeGraph.with_local_env_strategy( + mol, OpenBabelNN(), reorder=False, extend_structure=False + ) + prev_mol_graph = MoleculeGraph.with_local_env_strategy( + prev_calc_mol, OpenBabelNN(), reorder=False, extend_structure=False + ) + if mol_graph.isomorphic_to(prev_mol_graph): + mol = prev_calc_mol + else: + print( + "Not using prev_calc_mol as it is not isomorphic to passed molecule!" + ) + else: + mol = prev_calc_mol + self._update_charge(mol) + gaussin = GaussianInput(mol, **self.get("gaussian_input_params", {})) + # if a molecule is only included as an optional parameter + elif self.get("molecule"): + self._update_charge(self.get("molecule")) + gaussin = GaussianInput( + self.get("molecule"), **self.get("gaussian_input_params", {}) + ) + # if no molecule is present raise an error + else: + raise KeyError( + "No molecule present, add as an optional param or check fw_spec" + ) + gaussin.write_file(input_path, self.get("cart_coords", True)) + # delete fw_spec to avoid pymatgen import errors in the next task + # (running gaussian on a different partition) + if "prev_calc_molecule" in fw_spec: + del fw_spec["prev_calc_molecule"] + if "gaussian_input" in fw_spec: + del fw_spec["gaussian_input"]
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/fireworks/break_mol.html b/html/_modules/mispr/gaussian/fireworks/break_mol.html new file mode 100644 index 00000000..d827bcd7 --- /dev/null +++ b/html/_modules/mispr/gaussian/fireworks/break_mol.html @@ -0,0 +1,860 @@ + + + + + + + + + + + + + + + + mispr.gaussian.fireworks.break_mol - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.fireworks.break_mol

+"""Define firework used to break a molecule and run its fragments."""
+
+import os
+import logging
+
+from fireworks import Firework
+
+from mispr.gaussian.firetasks.geo_transformation import (
+    BreakMolecule,
+    ProcessMoleculeInput,
+)
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+FIREWORK_KWARGS = Firework.__init__.__code__.co_varnames
+
+
+
[docs]class BreakMolFW(Firework): + """ + Process a molecule input, break it into unique fragments, and generate a set of + optimization and frequency calculations for each fragment (optional). + """ + + def __init__( + self, + mol, + mol_operation_type="get_from_mol", + bonds=None, + open_rings=False, + ref_charge=0, + fragment_charges=None, + calc_frags=True, + db=None, + name="break_mol", + parents=None, + working_dir=None, + tag="unknown", + **kwargs + ): + """ + Args: + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + mol_operation_type (str, optional): The type of molecule operation. + See ``process_mol`` defined in ``mispr/gaussian/utilities/mol.py`` for + supported operations. Defaults to ``get_from_mol``. + bonds (list, optional): List of tuples of the bonds to break; e.g. + [(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between + atoms 1 and 2; if none is specified, will attempt to break all bonds. + open_rings (bool, optional): Whether to open rings; if set to True, will + perform local optimization to get a good initial guess for the + structure. Defaults to False. + ref_charge (int, optional): Charge on the principle molecule. Defaults to 0. + fragment_charges (list, optional): List of charges to assign to the + fragments in addition to the ones already assigned; refer to + ``mispr.gaussian.firetasks.geo_transformation.BreakMolecule`` for more + details. + calc_frags (bool, optional): Whether to create optimization and frequency + Fireworks for the generated fragments. Defaults to True. + db (str or dict, optional): Database credentials. + name (str, optional): Name of the Firework. Defaults to ``break_mol``. + parents (Firework or [Firework]), optional: List of parent FWs this FW + depends on. + working_dir (str, optional): Working directory for the calculation; will + use the current working directory if not specified. + tag (str, optional): Tag for the calculation; the provided tag will be + stored in the db documents for easy retrieval. Defaults to "unknown". + kwargs: Other kwargs that are passed to: + + 1. Firework.__init__. + 2. ``mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput`` + 3. ``mispr.gaussian.firetasks.geo_transformation.BreakMolecule`` + """ + + t = [] + working_dir = working_dir or os.getcwd() + if not os.path.exists(working_dir): + os.makedirs(working_dir) + + t.append( + ProcessMoleculeInput( + mol=mol, + operation_type=mol_operation_type, + db=db, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessMoleculeInput.required_params + + ProcessMoleculeInput.optional_params + } + ) + ) + + t.append( + BreakMolecule( + bonds=bonds, + open_rings=open_rings, + ref_charge=ref_charge, + fragment_charges=fragment_charges, + calc_frags=calc_frags, + db=db, + additional_kwargs=kwargs, + **{ + i: j + for i, j in kwargs.items() + if i + in BreakMolecule.required_params + BreakMolecule.optional_params + } + ) + ) + + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + super(BreakMolFW, self).__init__( + t, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/fireworks/core.html b/html/_modules/mispr/gaussian/fireworks/core.html new file mode 100644 index 00000000..e47ad85b --- /dev/null +++ b/html/_modules/mispr/gaussian/fireworks/core.html @@ -0,0 +1,1015 @@ + + + + + + + + + + + + + + + + mispr.gaussian.fireworks.core - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.fireworks.core

+"""Define common fireworks used in Gaussian workflows."""
+
+import os
+import logging
+
+from fireworks import Firework
+
+from mispr.gaussian.firetasks.run_calc import RunGaussianCustodian
+from mispr.gaussian.firetasks.write_inputs import WriteInput
+from mispr.gaussian.firetasks.parse_outputs import ProcessRun, RetrieveGaussianOutput
+from mispr.gaussian.firetasks.geo_transformation import ProcessMoleculeInput
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+FIREWORK_KWARGS = Firework.__init__.__code__.co_varnames
+
+
+
[docs]def common_tasks( + db, + input_file, + output_file, + gaussian_input_params, + cart_coords, + oxidation_states, + **kwargs +): + """ + Define a list of common tasks for Gaussian fireworks, i.e. writing an input file, + running the calculation, and parsing the output. + + Args: + db (str or dict): Database credentials to store the run; could be provided as + the path to the db.json file or in the form of a dictionary. + input_file (str): Name of the input file to be written. + output_file (str): name of the Gaussian output file + gaussian_input_params (dict): A dictionary of parameters to be used in creating + the Gaussian input file. + cart_coords (bool): Whether to write cartesian coordinates or not; default + is True. + oxidation_states (dict): A dictionary of element symbols and their oxidation + states used in setting the charge on the molecule. + kwargs: other kwargs that are passed to: + + 1. ``mispr.gaussian.firetasks.write_inputs.WriteInput`` + 2. ``mispr.gaussian.firetasks.run_calc.RunGaussianCustodian`` + 3. ``mispr.gaussian.firetasks.parse_outputs.ProcessRun`` + + Returns: + List of Firetasks. + """ + return [ + WriteInput( + input_file=input_file, + gaussian_input_params=gaussian_input_params, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + **{ + i: j + for i, j in kwargs.items() + if i in WriteInput.required_params + WriteInput.optional_params + } + ), + RunGaussianCustodian( + input_file=input_file, + output_file=output_file, + **{ + i: j + for i, j in kwargs.items() + if i + in RunGaussianCustodian.required_params + + RunGaussianCustodian.optional_params + } + ), + ProcessRun( + run=output_file, + operation_type="get_from_gout_file", + db=db, + input_file=input_file, + **{ + i: j + for i, j in kwargs.items() + if i in ProcessRun.required_params + ProcessRun.optional_params + } + ), + ]
+ + +
[docs]class CalcFromMolFW(Firework): + """ + Run a Gaussian calculation from a molecule. + """ + + def __init__( + self, + mol, + mol_operation_type="get_from_mol", + db=None, + name="calc_from_mol", + parents=None, + working_dir=None, + input_file="mol.com", + output_file="mol.out", + gaussian_input_params={}, + cart_coords=True, + oxidation_states=None, + tag="unknown", + **kwargs + ): + """ + Args: + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + mol_operation_type (str, optional): The type of molecule operation. See + process_mol defined in ``mispr/gaussian/utilities/mol.py`` for supported + operations. Defaults to ``get_from_mol``. + db (str or dict, optional): Database credentials; could be provided as the + path to the db.json file or in the form of a dictionary; if none is + provided, attempts to get it from the configuration files. + name (str, optional): Name of the Firework. Defaults to ``calc_from_mol``. + parents (Firework or [Firework], optional): List of parent FWs this FW + depends on. + working_dir (str, optional): Working directory for the calculation; defaults + to the current directory. + input_file (str, optional): Name of the Gaussian input file to be created; + defaults to "mol.com". + output_file (str, optional): Name of the Gaussian output file to be output; + defaults to "mol.out". + gaussian_input_params (dict, optional): Dictionary of parameters to be + used in the Gaussian input file. + cart_coords (bool, optional): Whether the coordinates are cartesian or + z-matrix. Defaults to True. + oxidation_states (list, optional): List of oxidation states for each atom; + defaults to None. + tag (str, optional): Tag for the calculation; the provided tag will be + stored in the db documents for easy retrieval. Defaults to "unknown". + kwargs: other kwargs that are passed to: + + 1. Firework.__init__. + 2. ``mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput`` + 3. ``mispr.gaussian.fireworks.common_tasks`` + """ + + t = [] + working_dir = working_dir or os.getcwd() + if not os.path.exists(working_dir): + os.makedirs(working_dir) + + t.append( + ProcessMoleculeInput( + mol=mol, + operation_type=mol_operation_type, + db=db, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessMoleculeInput.required_params + + ProcessMoleculeInput.optional_params + } + ) + ) + t += common_tasks( + db, + input_file, + output_file, + gaussian_input_params, + cart_coords, + oxidation_states, + # additional_fw=CalcFromMolFW(mol=mol, + # mol_operation_type=mol_operation_type, + # db=db, + # name=name, + # parents=parents, + # working_dir=working_dir, + # input_file=input_file, + # output_file=output_file, + # gaussian_input_params=gaussian_input_params, + # cart_coords=cart_coords, + # oxidation_states=oxidation_states, + # tag=tag, + # **kwargs), + **kwargs + ) + spec = kwargs.pop("spec", {}) + spec.update( + {"tag": tag, "_launch_dir": working_dir, "_add_launchpad_and_fw_id": True} + ) + super(CalcFromMolFW, self).__init__( + t, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+ + +
[docs]class CalcFromRunsDBFW(Firework): + """ + Run a Gaussian calculation from a previous calculation or the runs database. + """ + + def __init__( + self, + db=None, + name="calc_from_runs_db", + parents=None, + gaussian_input_params=None, + working_dir=None, + input_file="mol.com", + output_file="mol.out", + cart_coords=True, + tag="unknown", + **kwargs + ): + """ + Args: + db (str or dict, optional): Database credentials; could be provided as the + path to the db.json file or in the form of a dictionary; if none is + provided, attempts to get it from the configuration files. + name (str, optional): Name of the Firework. Defaults to ``calc_from_runs_db``. + parents (Firework or [Firework], optional): List of parent FWs this FW + depends on. + gaussian_input_params (dict, optional): Dictionary of parameters to be used + in the Gaussian input file. + working_dir (str, optional): Working directory for the calculation; + defaults to the current directory. + input_file (str, optional): Name of the Gaussian input file to be created; + defaults to "mol.com". + output_file (str, optional): Name of the Gaussian output file to be output; + defaults to "mol.out". + cart_coords (bool, optional): Whether the coordinates are cartesian or + z-matrix. Defaults to True. + tag (str, optional): Tag for the calculation; the provided tag will be + stored in the db documents for easy retrieval. Defaults to "unknown". + kwargs: other kwargs that are passed to: + + 1. Firework.__init__. + 2. ``mispr.gaussian.firetasks.parse_outputs.RetrieveGaussianOutput`` + 3. ``mispr.gaussian.fireworks.common_tasks`` + """ + t = [] + working_dir = working_dir or os.getcwd() + if not os.path.exists(working_dir): + os.makedirs(working_dir) + + t.append( + RetrieveGaussianOutput( + db=db, + gaussian_input_params=gaussian_input_params, + **{ + i: j + for i, j in kwargs.items() + if i + in RetrieveGaussianOutput.required_params + + RetrieveGaussianOutput.optional_params + } + ) + ) + t += common_tasks( + db, + input_file, + output_file, + gaussian_input_params, + cart_coords, + oxidation_states=None, + **kwargs + ) + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + super(CalcFromRunsDBFW, self).__init__( + t, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/db_utilities.html b/html/_modules/mispr/gaussian/utilities/db_utilities.html new file mode 100644 index 00000000..cc186a5a --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/db_utilities.html @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.db_utilities - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.db_utilities

+"""Define db utility functions."""
+
+import os
+import logging
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+
+from mispr.gaussian.database import GaussianCalcDb
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_db(input_db=None): + """ + Helper function to create a GaussianCalcDb instance from a file or a dict. + + Args: + input_db (str or dict, optional): Path to db file or a dict containing db info. + + Returns: + GaussianCalcDb. + """ + if not input_db: + input_db = f"{CONFIG_FILE_DIR}/db.json" + if not os.path.isfile(input_db): + raise FileNotFoundError("Please provide the database configurations") + if isinstance(input_db, dict): + db = GaussianCalcDb(**input_db) + else: + db = GaussianCalcDb.from_db_file(input_db) + + return db
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/dbdoc.html b/html/_modules/mispr/gaussian/utilities/dbdoc.html new file mode 100644 index 00000000..d035e5da --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/dbdoc.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.dbdoc - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.dbdoc

+"""Define functions for cleaning up JSON documents."""
+
+import os
+import logging
+
+from pymatgen.io.gaussian import GaussianInput
+from pymatgen.core.structure import Molecule
+
+from mispr.gaussian.defaults import JOB_TYPES, SCRF_MODELS
+from mispr.gaussian.utilities.metadata import get_chem_schema
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+def _job_types(gin):
+    """
+    Determine the type of the Gaussian job (e.g. opt, freq, etc.) from a Gaussian input
+    dictionary.
+
+    Args:
+        gin (dict): Gaussian input dictionary.
+
+    Returns:
+        list: List of Gaussian job types.
+    """
+    return sorted(
+        list(
+            filter(
+                lambda x: x
+                in {k.lower(): v for k, v in gin["route_parameters"].items()},
+                JOB_TYPES,
+            )
+        )
+    )
+
+
+def _modify_gout(gout):
+    """
+    Modify the Gaussian output dictionary by removing unnecessary keys and restructuring
+    its format to match the schema of the db.
+
+    Args:
+        gout (dict): Gaussian output dictionary.
+
+    Returns:
+        dict: Modified Gaussian output dictionary.
+    """
+    gout["input"]["charge"] = gout["charge"]
+    gout["input"]["spin_multiplicity"] = gout["spin_multiplicity"]
+    del_keys_out = (
+        "nsites",
+        "unit_cell_formula",
+        "reduced_cell_formula",
+        "pretty_formula",
+        "elements",
+        "nelements",
+        "charge",
+        "spin_multiplicity",
+    )
+    [gout.pop(k, None) for k in del_keys_out]
+    return gout
+
+
+def _create_gin(gout, working_dir, input_file):
+    """
+    Create a Gaussian input dictionary to be used for creating Gaussian documents in
+    the db; if an input_file is provided, content of the dictionary is mostly taken from
+    it; otherwise, uses the gout to create the dictionary.
+
+    Args:
+        gout (dict): Gaussian output dictionary.
+        working_dir (str): Working directory of the Gaussian input_file.
+        input_file (str): Relative or absolute path to the input_file.
+
+    Returns:
+        dict: Gaussian input dictionary.
+    """
+    if input_file:
+        if not os.path.isabs(input_file):
+            input_path = os.path.join(working_dir, input_file)
+        else:
+            input_path = input_file
+        gin = GaussianInput.from_file(input_path).as_dict()
+        gin["nbasisfunctions"] = gout["input"]["nbasisfunctions"]
+        gin["pcm_parameters"] = gout["input"]["pcm_parameters"]
+        return gin
+    else:
+        gin = gout["input"]
+        gin["input_parameters"] = None
+        gin["@class"] = "GaussianInput"
+        gin["@module"] = "pymatgen.io.gaussian"
+        logger.info(
+            "input parameters at the end of the Gaussian input "
+            "section will not be saved to the database due to "
+            "a missing input file"
+        )
+        return gin
+
+
+def _cleanup_gout(gout, working_dir, input_file):
+    """
+    Clean up the Gaussian dictionary to be saved in the database.
+
+    Args:
+        gout (dict): Gaussian output dictionary.
+        working_dir (str): Working directory of the Gaussian input_file.
+        input_file (str): Relative or absolute path to the input_file.
+
+    Returns:
+        dict: Cleaned up Gaussian dictionary.
+    """
+    gout = _modify_gout(gout)
+    gin = _create_gin(gout, working_dir, input_file)
+    del gout["input"]
+    gauss_version = gout["output"]["gauss_version"]
+    del gout["output"]["gauss_version"]
+    job_types = _job_types(gin)
+    mol = Molecule.from_dict(gout["output"]["molecule"])
+    gout_dict = {
+        "input": gin,
+        "output": gout,
+        "functional": gin["functional"],
+        "basis": gin["basis_set"],
+        "phase": "solution" if gout["is_pcm"] else "gas",
+        "type": ";".join(job_types),
+        **get_chem_schema(mol),
+        "gauss_version": gauss_version,
+    }
+    gout_dict = {
+        i: j
+        for i, j in gout_dict.items()
+        if i not in ["sites", "@module", "@class", "charge", "spin_multiplicity"]
+    }
+    return gout_dict
+
+
+
[docs]def add_solvent_to_prop_dict(prop_dict, solvent_gaussian_inputs, solvent_properties): + """ + Add solvent properties to a property dictionary (e.g. BDE, BE, etc.). + + Args: + prop_dict (dict): Property dictionary. + solvent_gaussian_inputs (str): Gaussian input parameters corresponding to the + implicit solvent model used in the Gaussian calculations, e.g. + "(Solvent=TetraHydroFuran)". + solvent_properties (dict): Additional solvent input parameters used in the + Gaussian calculations; e.g., {"EPS":12}. + + Returns: + dict: Property dictionary with solvent properties added. + """ + if not solvent_gaussian_inputs: + solvent = "water" + solvent_model = "pcm" + else: + solvent_inputs = [ + i.lower() for i in solvent_gaussian_inputs.strip("()").split(",") + ] + solvent = [ + string.split("=")[1] for string in solvent_inputs if "solvent" in string + ] or ["water"] + solvent_model = list( + filter(lambda x: x in {i for i in solvent_inputs}, SCRF_MODELS) + ) or ["pcm"] + prop_dict["solvent"] = "".join(solvent) + prop_dict["solvent_model"] = "".join(solvent_model) + prop_dict["solvent_properties"] = solvent_properties + return prop_dict
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/files.html b/html/_modules/mispr/gaussian/utilities/files.html new file mode 100644 index 00000000..18812dcc --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/files.html @@ -0,0 +1,809 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.files - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.files

+"""Define utility functions for handling files and paths."""
+
+import os
+import logging
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def bibtex_parser(bib_file, working_dir): + """ + Parse a bibtex file and returns a dictionary of the entries. + + Args: + bib_file (str): Relative or absolute path to the bibtex file. + working_dir (str): Name of the working directory where the bibtex file is + located if bib_file path is relative; else None. + + Returns: + dict: Dictionary of the entries in the bibtex file. + """ + try: + import bibtexparser + except ModuleNotFoundError: + raise ImportError( + "Defining standard electrode potential " + "references requires bibtexparser to be " + "installed." + ) + bib_file = recursive_relative_to_absolute_path(bib_file, working_dir) + print(bib_file) + with open(bib_file) as bibfile: + bp = bibtexparser.load(bibfile) + entry = bp.entries[0] + return entry
+ + +
[docs]def recursive_relative_to_absolute_path(operand, working_dir): + """ + Convert recursively relative paths to absolute paths. + + Args: + operand (str, list, dict): File, list of files, or a dictionary where the values + are the files; the file(s) path can be relative or absolute. + working_dir (str): Name of the working directory where the file(s) is/are + located if operand path is relative; else None. + + Returns: + str or list or dict: File, list of files, or dict where the values are the + absolute paths. + """ + if isinstance(operand, str): + if os.path.isabs(operand): + return operand + elif os.path.exists(operand): + return os.path.join(os.getcwd(), operand) + else: + full_path = os.path.join(working_dir, operand) + if os.path.exists(full_path): + return full_path + else: + return operand + elif isinstance(operand, dict): + return { + i: recursive_relative_to_absolute_path(j, working_dir) + for i, j in operand.items() + } + elif isinstance(operand, list): + return [recursive_relative_to_absolute_path(i, working_dir) for i in operand] + else: + return operand
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/fw_utilities.html b/html/_modules/mispr/gaussian/utilities/fw_utilities.html new file mode 100644 index 00000000..41bea9e6 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/fw_utilities.html @@ -0,0 +1,979 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.fw_utilities - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.fw_utilities

+"""Define utility functions for modifying workflow settings. Based on atomate powerups."""
+
+import logging
+
+from mispr.gaussian.firetasks.run_calc import (
+    RunGaussianFake,
+    RunGaussianDirect,
+    RunGaussianCustodian,
+)
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+__credits__ = "Anubhav Jain, Kiran Mathew"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_list_fireworks_and_tasks( + workflow, firework_substring=None, task_substring=None +): + """ + Return a list of (firework_index, task_index) tuples for all fireworks and tasks in + a workflow. + + Args: + workflow (Workflow): The workflow to search. + firework_substring (str, optional): A substring to search for in the Firework + names to exclude certain fireworks. + task_substring (str, optional): A substring to search for in the Firetask + names to exclude certain Firetasks. + + Returns: + list: A list of (firework_index, task_index) tuples. + """ + list_fireworks_and_tasks = [] + for i_firework, firework in enumerate(workflow.fws): + if not firework_substring or any( + n in firework.name for n in firework_substring + ): + for i_task, task in enumerate(firework.tasks): + if not task_substring or any(n in str(task) for n in task_substring): + list_fireworks_and_tasks.append((i_firework, i_task)) + return list_fireworks_and_tasks
+ + +
[docs]def control_worker( + workflow, firework_substring=None, task_substring=None, fworker=None, category=None +): + """ + Modify the Firework's fworker name and category in a workflow. Can be used when + running workflows on multiple workers at the same time to specify which + worker/machine to use. + + Args: + workflow (Workflow): The workflow to control. + firework_substring (str, optional): A substring to search for in the Firework + names to exclude certain fireworks. + task_substring (str, optional): A substring to search for in the Firetask + names to exclude certain Firetasks. + fworker (str, optional): The name of the fworker to use for the Firework; + should be consistent with the one specified in the FireWorker + (my_fworker.yaml file). + category (str, optional): The category to be assigned for the Firework; should + be consistent with the one specified in the FireWorker (my_fworker.yaml file). + + Returns: + Workflow: The modified workflow with the specified fworker and/or category. + """ + list_fireworks_and_tasks = get_list_fireworks_and_tasks( + workflow, firework_substring=firework_substring, task_substring=task_substring + ) + for i_firework, i_task in list_fireworks_and_tasks: + if fworker: + workflow.fws[i_firework].spec["_fworker"] = fworker + if category: + workflow.fws[i_firework].spec["_category"] = category + return workflow
+ + +
[docs]def modify_queue_parameters( + workflow, + ntasks_per_node=None, + walltime=None, + queue=None, + pre_rocket=None, + other_parameters=None, + firework_substring=None, + task_substring=None, +): + """ + Modify the default Firework's queue parameters in a workflow. Default ones are + specified in the my_qadapter.yaml file. Helpful when different workflows requires + different computational resources (e.g. number of CPUs, memory, etc.). + + Args: + workflow (Workflow): The workflow to modify. + ntasks_per_node (int, optional): The number of tasks to run on each node. + walltime (str, optional): The walltime for the job. + queue (str, optional): The queue/partition to run the job on. + pre_rocket (str, optional): The pre-rocket command to run before the job. + other_parameters (dict, optional): Other parameters to be added to the + queueadapter. + firework_substring (str, optional): A substring to search for in the Firework + names to exclude certain fireworks. + task_substring (str, optional): A substring to search for in the Firetask + names to exclude certain Firetasks. + + Returns: + Workflow: The modified workflow with the specified queue parameters. + """ + queue_parameters = {} + if ntasks_per_node: + queue_parameters.update({"ntasks_per_node": ntasks_per_node}) + if walltime: + queue_parameters.update({"walltime": walltime}) + if queue: + queue_parameters.update({"queue": queue}) + if pre_rocket: + queue_parameters.update({"pre_rocket": pre_rocket}) + if other_parameters: + queue_parameters.update(other_parameters) + + list_fireworks_and_tasks = get_list_fireworks_and_tasks( + workflow, firework_substring=firework_substring, task_substring=task_substring + ) + for i_firework, i_task in list_fireworks_and_tasks: + workflow.fws[i_firework].spec.update({"_queueadapter": queue_parameters}) + return workflow
+ + +
[docs]def replace_runtask( + workflow, + firework_substring=None, + operation="remove_custodian", + additional_params=None, +): + """ + Replace all tasks with ``RunGaussian`` (e.g. RunGaussianDirect) with + RunGaussianCustodian or vice versa. + + Args: + workflow (Workflow): The workflow to modify. + firework_substring (str, optional): A substring to search for in the Firework + names to exclude certain fireworks. + operation (str, optional): The operation to perform on the Firetask; supported + ones are ``remove_custodian`` and ``use_custodian``. + additional_params (dict, optional): Additional parameters to be added to the + new Firetask that are not included in the original Firetask; refer to the + corresponding Firetask documentation for supported parameters. + + Returns: + Workflow: The workflow with the replaced run Firetasks. + """ + if additional_params is None: + additional_params = {} + list_fireworks_and_tasks = get_list_fireworks_and_tasks( + workflow, firework_substring, task_substring=["RunGaussian"] + ) + + for i_firework, i_task in list_fireworks_and_tasks: + params = workflow.fws[i_firework].tasks[i_task].as_dict() + task_params = {**params, **additional_params} + if operation == "remove_custodian": + firetask = RunGaussianDirect + elif operation == "use_custodian": + firetask = RunGaussianCustodian + else: + raise ValueError(f"Unsupported operation type: {operation}") + workflow.fws[i_firework].tasks[i_task] = firetask( + **{ + i: j + for i, j in task_params.items() + if i in firetask.required_params + firetask.optional_params + } + ) + return workflow
+ + +
[docs]def run_fake_gaussian(workflow, ref_dirs, input_files=None, tolerance=None): + """ + Replace all tasks with ``RunGaussian`` (i.e. RunGaussianDirect, RunGaussianCustodian) + with RunGaussianFake that runs a fake Gaussian job. We do not actually run Gaussian + but copy existing inputs and outputs. Useful for testing purposes. + + Args: + workflow (Workflow): The workflow to modify. + ref_dirs (list): A list of directories containing the reference calculations + for the fake Gaussian job (e.g. ['home/opt', 'home/freq']). + input_files (list, optional): A list of input files for the fake Gaussian job; + order should match that in ref_dirs; e.g. ["opt.com", "freq.com"]. + tolerance (float, optional): The tolerance for the comparison of the provided + input file with the existing one. + + Returns: + Workflow: The workflow with the replaced run Firetasks. + """ + list_fireworks_and_tasks = get_list_fireworks_and_tasks( + workflow, task_substring=["RunGaussian"] + ) + if not input_files: + input_files = ["mol.com"] * len(ref_dirs) + + for ind, (i_firework, i_task) in enumerate(list_fireworks_and_tasks): + workflow.fws[i_firework].tasks[i_task] = RunGaussianFake( + ref_dir=ref_dirs[ind], + input_file=input_files[ind], + tolerance=tolerance, + ) + return workflow
+ + +
[docs]def add_common_mods(workflow, fw_mods=None): + """ + Wrapper function to add common modifications to a workflow. + + Args: + workflow (Workflow): The workflow to modify. + fw_mods (dict, optional): A dictionary of modifications to be applied to the + workflow; supported ones are ``CONTROL_WORKER``, ``MODIFY_QUEUE_PARAMETERS``, + ``REPLACE_RUNTASK``, and ``RUN_FAKE_GAUSSIAN`` (see the docstring of each + function for more details); values of the dictionary are the inputs to the + corresponding function. + + Returns: + Workflow: The modified workflow. + """ + fw_mods = fw_mods or {} + + if fw_mods.get("CONTROL_WORKER"): + workflow = control_worker(workflow, **fw_mods.get("CONTROL_WORKER", {})) + + if fw_mods.get("MODIFY_QUEUE_PARAMETERS"): + workflow = modify_queue_parameters( + workflow, **fw_mods.get("MODIFY_QUEUE_PARAMETERS", {}) + ) + + if fw_mods.get("REPLACE_RUNTASK"): + workflow = replace_runtask(workflow, **fw_mods.get("REPLACE_RUNTASK", {})) + + if fw_mods.get("RUN_FAKE_GAUSSIAN"): + workflow = run_fake_gaussian(workflow, **fw_mods.get("RUN_FAKE_GAUSSIAN", {})) + + return workflow
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/gout.html b/html/_modules/mispr/gaussian/utilities/gout.html new file mode 100644 index 00000000..680b4504 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/gout.html @@ -0,0 +1,873 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.gout - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.gout

+"""Define functions for processing different gaussian output formats."""
+
+import os
+import json
+import logging
+
+from bson import ObjectId
+
+from pymatgen.io.gaussian import GaussianOutput
+
+from mispr.gaussian.utilities.misc import recursive_signature_remove
+from mispr.gaussian.utilities.dbdoc import _cleanup_gout
+from mispr.gaussian.utilities.db_utilities import get_db
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def process_run(operation_type, run, input_file=None, **kwargs): + """ + Process a Gaussian run and returns a dictionary of the results. Used for creating + db documents and/or json files. + + Args: + operation_type (str): Type of operation to be performed; supported ones are: + + 1. ``get_from_gout``: Get data from a GaussianOutput object as defined in + ``pymatgen.io.gaussian``. + 2. ``get_from_gout_file``: Get data from a Gaussian output file. + 3. ``get_from_run_dict``: Get data from a Gaussian output dictionary. + 4. ``get_from_run_id``: Retrieve data from dtabase using a run id, + e.g. "5e3737d9da0b1cbbd5d556f7". + 5. ``get_from_run_query``: Retrieve data from dtabase using query criteria, + e.g. + + .. code-block:: python + + {"smiles": "COCCOC", "type": "freq", "functional": "B3LYP", + "basis": "6-31+G*", "phase": "gas", ...} + + run (GaussianOutput, str, dict): The actual Gaussian run; type depends on the + ``operation_type``. + input_file (str, optional): The input file for the run; used for adding Gaussian + input parameters to the final Gaussian dictionary; if not specified, will + get these parameters from the run itself, but in this case, + ``input_parameters`` usually specified at the end of the Gaussian input file + will not be saved since they are not easily retrieved from the Gaussian + output file. + kwargs (keyword arguments): Additional keyword arguments for the operation: + namely, ``working_dir`` and ``db``. + + Returns: + dict: Cleaned up Gaussian output dictionary. + """ + working_dir = kwargs.get("working_dir", os.getcwd()) + + def get_db_(): + return get_db(kwargs["db"]) if "db" in kwargs else get_db() + + if operation_type == "get_from_gout": + if not isinstance(run, GaussianOutput): + raise Exception( + "run is not a GaussianOutput object; either " + "provide a GaussianOutput object or use another " + "operation type with its corresponding inputs" + ) + gout = run.as_dict() + gout_dict = _cleanup_gout(gout, working_dir, input_file) + + elif operation_type == "get_from_gout_file": + if not os.path.isabs(run): + file_path = os.path.join(working_dir, run) + else: + file_path = run + if not os.path.exists(file_path): + raise Exception( + "run is not a valid path; either provide a valid " + "path or use another operation type with its " + "corresponding inputs" + ) + try: + gout = GaussianOutput(file_path).as_dict() + gout_dict = _cleanup_gout(gout, working_dir, input_file) + except IndexError: + raise ValueError( + "run is not a Gaussian output file; either " + "provide a valid Gaussian output file or use " + "another operation type with its corresponding " + "inputs" + ) + + elif operation_type == "get_from_run_dict": + if not isinstance(run, dict) and "output" not in run: + raise Exception( + "run is not a GaussianOutput dictionary; either" + "provide a GaussianOutput dictionary or use another" + "operation type with its corresponding inputs" + ) + gout_dict = run + + elif operation_type == "get_from_run_id": + # run = run_id + db = get_db_() + run = db.runs.find_one({"_id": ObjectId(run)}) + if not run: + raise Exception("Gaussian run is not in the database") + gout_dict = run + + elif operation_type == "get_from_run_query": + # run = {'inchi': inchi, 'smiles': smiles, 'type': type, + # 'functional': func, 'basis': basis, 'phase': phase, ...} + logger.info( + "If the query criteria satisfy more than " + "one document, the last updated one will " + "be used. To perform a more specific " + "search, provide the document id using " + "gout_id" + ) + db = get_db_() + run = db.retrieve_run(**run) + if not run: + raise Exception("Gaussian run is not in the database") + run = max(run, key=lambda i: i["last_updated"]) + gout_dict = run + + else: + raise ValueError(f"operation type {operation_type} is not supported") + if "_id" in gout_dict: + gout_dict["_id"] = str(gout_dict["_id"]) + if "last_updated" in gout_dict: + del gout_dict["last_updated"] + gout_dict = json.loads(json.dumps(gout_dict)) + gout_dict = recursive_signature_remove(gout_dict) + + return gout_dict
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/inputs.html b/html/_modules/mispr/gaussian/utilities/inputs.html new file mode 100644 index 00000000..7621f141 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/inputs.html @@ -0,0 +1,956 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.inputs - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.inputs

+"""Define functions for handling gaussian inputs."""
+
+import logging
+
+from copy import deepcopy
+
+from mispr.gaussian.defaults import STANDARD_OPT_GUASSIAN_INPUT
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+def _add_solvent_inputs(
+    gaussian_inputs, solvent_gaussian_inputs, solvent_properties=None
+):
+    """
+    Add solvent inputs to the gaussian_inputs dict. The input parameters relevant to
+    implicit solvation are required to be provided separate from the gaussian_inputs
+    dict to the Gaussian workflows. This is done in order to easily save the solvent
+    properties to the database or to the json files generated from the workflows.
+
+    Args:
+        gaussian_inputs (dict): Dictionary of dictionaries of Gaussian inputs for one
+            or more Gaussian job type, e.g.
+
+            .. code-block:: python
+
+                {"opt": {
+                    "functional": "B3LYP",
+                    "basis_set": "6-31G",
+                    "route_parameters": {
+                        "Opt": "(calcfc, tight)",
+                        "test": None},
+                        }
+                }
+
+        solvent_gaussian_inputs (str): String of Gaussian inputs for the solvent, e.g.
+            "(Solvent=Generic, Read)".
+        solvent_properties (dict, optional): Dictionary of solvent properties, e.g.
+            {"Eps": 4.33, "EpsInf": 1.69}.
+
+    Returns:
+        dict: Dictionary of dictionaries of Gaussian inputs with solvent inputs added.
+    """
+    if "generic" in solvent_gaussian_inputs.lower() and not solvent_properties:
+        raise Exception(
+            "A generic solvent is provided as an input without "
+            "specifying its parameters."
+        )
+    for key, value in gaussian_inputs.items():
+        if "route_parameters" not in value:
+            gaussian_inputs[key]["route_parameters"] = {}
+        gaussian_inputs[key]["route_parameters"]["SCRF"] = solvent_gaussian_inputs
+        if solvent_properties:
+            if "input_parameters" not in gaussian_inputs[key]:
+                gaussian_inputs[key]["input_parameters"] = {}
+            gaussian_inputs[key]["input_parameters"].update(solvent_properties)
+    return gaussian_inputs
+
+
+def _check_solvent_inputs(gaussian_inputs):
+    """
+    Ensure that implicit solvent parameters are not included in the Gaussian input
+    dictionaries, since those should be provided separately.
+
+    Args:
+        gaussian_inputs (dict): Dictionary of dictionaries of Gaussian inputs for one
+            or more Gaussian job type, e.g.
+
+            .. code-block:: python
+                {"opt": {
+                    "functional": "B3LYP",
+                    "basis_set": "6-31G",
+                    "route_parameters": {
+                        "Opt": "(calcfc, tight)",
+                        "test": None},
+                        }
+                }
+    """
+    route_params = {}
+    for key, value in gaussian_inputs.items():
+        if value:
+            route_params.update(value.get("route_parameters", {}))
+    assert "scrf" not in [i.lower() for i in route_params], (
+        "solvent inputs should be provided as separate inputs via "
+        "solvent_gaussian_inputs and solvent_properties"
+    )
+
+
+def _get_gaussian_inputs(gaussian_inputs, supported_jobs=None):
+    """
+    This function is meant to be used in workflows in which multiple Gaussian jobs are
+    performed and the jobs share similar Gaussian keywords; used to handle situations
+    in which the user is not explicitly defining every single job input dictionary.
+
+    Args:
+        gaussian_inputs (dict): Dictionary of dictionaries of Gaussian input parameters
+            for different job types in a given workflow, e.g.
+
+            .. code-block:: python
+                {"opt": {}, "freq": {}, "nmr": {}, "esp": {}, "sp": {}}
+
+        supported_jobs (dict, optional): Dictionary of dictionaries of supported job
+            types and their main inputs, e.g.
+
+            .. code-block:: python
+                {"opt": {"Opt": None}, "nmr": {"NMR": "GIAO"}}
+
+    Returns:
+        dict: Dictionary of dictionaries of Gaussian input parameters.
+    """
+    supported_jobs = supported_jobs or {}
+    supported_jobs = {
+        **{
+            "freq": {"Freq": None},
+            "nmr": {"NMR": "GIAO"},
+            "esp": {"pop": "MK", "iop(6/50=1)": None},
+            "sp": {"SP": None},
+        },
+        **{k.lower(): v for k, v in supported_jobs.items()},
+    }
+
+    gaussian_inputs = {
+        k.lower(): v if v is not None else {} for k, v in gaussian_inputs.items()
+    }
+
+    if "opt" not in gaussian_inputs:
+        gaussian_inputs["opt"] = {}
+    gaussian_inputs["opt"] = {**STANDARD_OPT_GUASSIAN_INPUT, **gaussian_inputs["opt"]}
+    if "opt" not in [i.lower() for i in gaussian_inputs["opt"]["route_parameters"]]:
+        gaussian_inputs["opt"]["route_parameters"].update({"Opt": None})
+
+    for job in gaussian_inputs:
+        if job in supported_jobs and job != "opt":
+            gaussian_inputs[job] = _update_gaussian_inputs(
+                deepcopy(gaussian_inputs["opt"]),
+                gaussian_inputs[job],
+                supported_jobs[job],
+            )
+        elif job == "opt":
+            pass
+        else:
+            logger.error(
+                "keyword for {} is not known. Please add keyword to "
+                "the supported_jobs dict.".format(job)
+            )
+    return gaussian_inputs
+
+
+def _update_gaussian_inputs(opt_gaussian_inputs, other_gaussian_inputs, main_keyword):
+    """
+    Use the fully defined optimization input parameters to fill in the input parameters
+    for other job types in a given workflow. Done to avoid having to define every single
+    job input dictionary.
+
+    Args:
+        opt_gaussian_inputs (dict): Dictionary of Gaussian input parameters for the
+            optimization step of a given workflow.
+        other_gaussian_inputs (dict): Dictionary of Gaussian inputs other than the
+            route_parameters (e.g. input_parameters) for a job other than optimization
+            in a given workflow.
+        main_keyword (dict): Simple dictionary containing the main Gaussian
+            route_parameters for the job type, e.g. {"Freq": None} for a frequency
+            analysis.
+
+    Returns:
+        dict: Dictionary of Gaussian input parameters for a job other than optimization.
+    """
+    gaussian_inputs = {**opt_gaussian_inputs, **other_gaussian_inputs}
+    if list(main_keyword.keys())[0].lower() not in [
+        i.lower() for i in gaussian_inputs["route_parameters"]
+    ]:
+        gaussian_inputs["route_parameters"].update(main_keyword)
+    for i in gaussian_inputs["route_parameters"]:
+        if i.lower() == "opt":
+            del gaussian_inputs["route_parameters"][i]
+            break
+    return gaussian_inputs
+
+
+
[docs]def handle_gaussian_inputs( + gaussian_inputs, solvent_gaussian_inputs=None, solvent_properties=None +): + """ + Wrapper function to cleanup/modify the Gaussian input parameters for one or more + job in a workflow. Checks for implicit solvent parameters and adds missing keywords + for a given job. + + Args: + gaussian_inputs (dict): Dictionary of dictionaries of Gaussian inputs, e.g. + + .. code-block:: python + + {"opt": {opt_gaussian_inputs}, "freq": {freq_gaussian_inputs}} + + solvent_gaussian_inputs (str, optional): String of Gaussian inputs for the + solvent, e.g. + + .. code-block:: python + + "(Solvent=Generic, Read)" + + solvent_properties (dict, optional): Dictionary of solvent properties, e.g. + + .. code-block:: python + + {"Eps": 4.33, "EpsInf": 1.69} + + Returns: + dict: Dictionary of dictionaries of reformatted Gaussian inputs. + """ + gaussian_inputs = _get_gaussian_inputs(gaussian_inputs) + _check_solvent_inputs(gaussian_inputs) + if solvent_gaussian_inputs: + gaussian_inputs = _add_solvent_inputs( + gaussian_inputs, solvent_gaussian_inputs, solvent_properties + ) + return gaussian_inputs
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/metadata.html b/html/_modules/mispr/gaussian/utilities/metadata.html new file mode 100644 index 00000000..749d0bf3 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/metadata.html @@ -0,0 +1,818 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.metadata - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.metadata

+"""Define functions for creating db schema."""
+
+import logging
+
+from openbabel import pybel as pb
+
+from pymatgen.io.babel import BabelMolAdaptor
+from pymatgen.core.structure import Molecule
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_chem_schema(mol): + """ + Return a dictionary of chemical schema for a given molecule to use in building db + documents or json file. + + Args: + mol (Molecule): Molecule object. + + Returns: + dict: Chemical schema. + """ + mol_dict = mol.as_dict() + comp = mol.composition + a = BabelMolAdaptor(mol) + pm = pb.Molecule(a.openbabel_mol) + # svg = pm.write('svg') + mol_dict.update( + { + "smiles": pm.write("smi").strip(), + "inchi": pm.write("inchi").strip("\n"), + "formula": comp.formula, + "formula_pretty": comp.reduced_formula, + "formula_anonymous": comp.anonymized_formula, + "formula_alphabetical": comp.alphabetical_formula, + "chemsys": comp.chemical_system, + "nsites": mol.num_sites, + "nelements": len(comp.chemical_system.replace("-", " ").split(" ")), + "is_ordered": mol.is_ordered, + "is_valid": mol.is_valid(), + } + ) + return mol_dict
+ + +
[docs]def get_mol_formula(mol): + """ + Get the alphabetical molecular formula for a molecule. + + Args: + mol (Molecule): Molecule object + + Returns: + str: Alphabetical molecular formula. + """ + mol_schema = get_chem_schema(mol) + return mol_schema["formula_alphabetical"].replace(" ", "")
+ + +
[docs]def get_job_name(mol, name): + """ + Append a molecule label to the name of a workflow for easy monitoring and + identification. + + Args: + mol (Molecule or str): If a Molecule is provided, the appended label will be + the molecular formula; otherwise the label will be the provided string. + name (str): Original name of the workflow. + + Returns: + str: Job name with molecule label. + """ + if not isinstance(mol, Molecule): + job_name = "{}_{}".format(mol, name) + else: + mol_formula = get_mol_formula(mol) + job_name = "{}_{}".format(mol_formula, name) + return job_name
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/misc.html b/html/_modules/mispr/gaussian/utilities/misc.html new file mode 100644 index 00000000..7a6d59eb --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/misc.html @@ -0,0 +1,828 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.misc - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.misc

+"""Define miscellaneous functions useful in many of the mispr levels."""
+
+import logging
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def pass_gout_dict(fw_spec, key): + """ + Helper function used in the Gaussian Fireworks to pass Gaussian output dictionaries + from one task to the other, while checking that the criteria for starting the + following task are met (e.g. normal termination of the previous job, lack of + imaginary frequencies, etc.). + + Args: + fw_spec (dict): Firework spec dictionary. + key (str): Unique key for the Gaussian output dictionary in fw_spec. + + Returns: + dict: Gaussian output dictionary. + """ + gout_dict = fw_spec.get("gaussian_output", {}).get(key) + proceed_keys = fw_spec.get("proceed", {}) + for k, v in proceed_keys.items(): + if gout_dict["output"].get(k, gout_dict["output"]["output"].get(k)) != v: + raise ValueError(f"The condition for {k} is not met, Terminating") + return gout_dict
+ + +
[docs]def recursive_signature_remove(d): + """ + Remove Recursively the signature "@" from a dictionary (e.g. those in the name of + a module). Used when processing Gaussian runs before saving them to the db. + + Args: + d (dict): Dictionary to remove the signature from. + + Returns: + dict: Dictionary with the signature removed. + """ + # TODO: check if this is no longer an issue with MongoDB 5.0 + if isinstance(d, dict): + return { + i: recursive_signature_remove(j) + for i, j in d.items() + if not i.startswith("@") + } + else: + return d
+ + +
[docs]def recursive_compare_dicts(dict1, dict2, dict1_name, dict2_name, path=""): + """ + Compare recursively two dictionaries and returns the differences. + + Args: + dict1 (dict): First dictionary to compare. + dict2 (dict): Second dictionary to compare. + dict1_name (str): Name of the first dictionary (for messages on the differences). + dict2_name (str): Name of the second dictionary (for messages on the differences). + path (str, optional): Used internally to keep track of the keys in nested dicts, + meant to be "" for the top level + + Returns: + str: Differences between the two dictionaries (if any). + """ + error = "" + old_path = path + for key in dict1.keys(): + path = f"{old_path}[{key}]" + if key not in dict2.keys(): + error += f"Key {dict1_name}{path} not in {dict2_name}\n" + else: + if isinstance(dict1[key], dict) and isinstance(dict2[key], dict): + error += recursive_compare_dicts( + dict1[key], dict2[key], "d1", "d2", path + ) + else: + if dict1[key] != dict2[key]: + error += ( + f"Value of {dict1_name}{path} ({dict1[key]}) " + f"not same as {dict2_name}{path} ({dict2[key]})\n" + ) + + for key in dict2.keys(): + path = f"{old_path}[{key}]" + if key not in dict1.keys(): + error += f"Key {dict2_name}{path} not in {dict1_name}\n" + return error
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/mol.html b/html/_modules/mispr/gaussian/utilities/mol.html new file mode 100644 index 00000000..ef7e3df7 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/mol.html @@ -0,0 +1,1118 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.mol - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.mol

+"""Define functions for processing molecules."""
+
+import os
+import logging
+
+from bson import ObjectId
+
+from openbabel import pybel as pb
+from openbabel import OBMolBondIter
+
+from pymatgen.io.babel import BabelMolAdaptor
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.core.structure import Molecule
+
+from mispr.common.pubchem import PubChemRunner
+from mispr.gaussian.utilities.db_utilities import get_db
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def process_mol(operation_type, mol, local_opt=False, **kwargs): + """ + Process a molecule. Used for handling different molecule formats provided to + Gaussian workflows. + + Args: + operation_type (str): Operation to perform for the molecule to process the input + structure format. Supported commands: + + 1. ``get_from_mol``: If the input is a pymatgen Molecule object. + 2. ``get_from_file``: If the input is any file format supported by Openabel + and pymatgen. + 3. ``get_from_gout_file``: If the input is a Gaussian output file. + 4. ``get_from_str``: If the input is a string. + 5. ``get_from_mol_db``: If the input is an InChI representation of the + molecule to be used to query the database. + 6. ``get_from_gout``: If the input is a pymatgen GaussianOutput object. + 7. ``get_from_run_dict``: If the input is a GaussianOutput dictionary. + 8. ``get_from_run_id``: If the input is a MongoDB document ID to be used + to query the database. + 9. ``get_from_run_query``: If the input is a dictionary with criteria to + search the database: e.g. + + .. code-block:: python + + {'inchi': inchi, + 'type': type, + 'functional': func, ...} + + 10. ``get_from_pubchem``: If the input is a common name for the molecule + to be used in searching the PubChem database. + 11. ``derive_molecule``: Used for deriving a molecule by attaching a + functional group at a site and the corresponding mol input should be a + dictionary, e.g. + + .. code-block:: python + + {'operation_type': <mol_operation_type for the base structure>, + 'mol': <base_mol>, + 'func_grp': func_group_name, ...} + + 12. ``link_molecules``: Used for linking two structures by forming a bond + at specific sites and the corresponding mol input should be a dictionary, + e.g. + + .. code-block:: python + + {'operation_type': ['get_from_file', 'get_from_mol_db'], + 'mol': ['mol1.xyz', 'mol_inchi'], + 'index': [3, 5], + 'bond_order': 1} + + mol (Molecule, str, GaussianOutput, dict): Sources of structure, e.g. file path + if mol_operation_type is specified as ``get_from_file``, InChI string if + mol_operation_type is specified as ``get_from_mol_db``, etc. + local_opt (bool, optional): Whether to perform local optimization on the input + structure using OpenBabel; defaults to False. + kwargs: Keyword arguments: + + 1. ``working_dir``. + 2. ``db``. + 3. ``str_type`` (format of string if operation_type = ``get_from_str``, + e.g. ``smi`` or any other format supported by OpenBabel). + 4. ``force_field`` (force field to use for local optimization if + local_opt is True): ``gaff``, ``ghemical``, ``mmff94``, ``mmff94s``, + and ``uff``. + 5. ``steps`` (number of steps for local optimization if local_opt is True). + 6. ``charge``. + 7. ``abbreviation`` (abbreviation to be used for the molecule when + downloading it from the PubChem database; defaults to mol). + + Returns: + Molecule: pymatgen Molecule object. + """ + working_dir = kwargs.get("working_dir", os.getcwd()) + + def get_db_(): + return get_db(kwargs["db"]) if "db" in kwargs else get_db() + + if operation_type == "get_from_mol": + if not isinstance(mol, Molecule): + raise Exception( + "mol is not a Molecule object; either " + "provide a Molecule object or use another " + "operation type with its corresponding inputs" + ) + output_mol = mol + + elif operation_type == "get_from_file" or operation_type == "get_from_gout_file": + if not os.path.isabs(mol): + file_path = os.path.join(working_dir, mol) + else: + file_path = mol + if not os.path.exists(file_path): + raise Exception( + "mol is not a valid path; either provide a valid " + "path or use another operation type with its " + "corresponding inputs" + ) + + output_mol = Molecule.from_file(file_path) + + elif operation_type == "get_from_str": + str_type = kwargs.get("str_type") + if str_type is None: + raise ValueError( + "a mol string format must be specified to process " "the input string" + ) + output_mol = Molecule.from_str(mol, str_type) + + elif operation_type == "get_from_mol_db": + # mol = mol_inchi + db = get_db_() + mol_dict = db.retrieve_molecule(mol) + if not mol_dict: + raise Exception("mol is not found in the database") + output_mol = Molecule.from_dict(mol_dict) + + elif operation_type == "get_from_gout": + if not isinstance(mol, GaussianOutput): + raise Exception( + "mol is not a GaussianOutput object; either " + "provide a GaussianOutput object or use another " + "operation type with its corresponding inputs" + ) + output_run = mol.as_dict() + output_mol = Molecule.from_dict(output_run["output"]["molecule"]) + + elif operation_type == "get_from_run_dict": + if not isinstance(mol, dict) and "output" not in mol: + raise Exception( + "mol is not a GaussianOutput dictionary; either " + "provide a GaussianOutput dictionary or use " + "another operation type with its corresponding " + "inputs" + ) + output_mol = Molecule.from_dict(mol["output"]["output"]["molecule"]) + + elif operation_type == "get_from_run_id": + # mol = run_id + db = get_db_() + run = db.runs.find_one({"_id": ObjectId(mol)}) + if not run: + raise Exception("Gaussian run is not in the database") + mol_dict = run["output"]["output"]["molecule"] + output_mol = Molecule.from_dict(mol_dict) + + elif operation_type == "get_from_run_query": + # mol = {'inchi': inchi, 'type': type, 'functional': func, + # 'basis': basis, 'phase': phase, ...} + logger.info( + "If the query criteria satisfy more than " + "one document, the last updated one will " + "be used. To perform a more specific " + "search, provide the document id using " + "gout_id" + ) + db = get_db_() + run = db.retrieve_run(**mol) + if not run: + raise Exception("Gaussian run is not in the database") + run = max(run, key=lambda i: i["last_updated"]) + mol_dict = run["output"]["output"]["molecule"] + output_mol = Molecule.from_dict(mol_dict) + + elif operation_type == "get_from_pubchem": + pb = PubChemRunner( + abbreviation=kwargs.get("abbreviation", "mol"), working_dir=working_dir + ) + output_mol = pb.get_mol(mol) + + elif operation_type == "derive_molecule": + # mol = {'operation_type': 'get_from_file', 'mol': file_path, + # 'func_grp': func_group_name, ....} + + func_grp_name = mol.get("func_grp") + if not func_grp_name: + raise Exception( + "No FG provided; Provide the name of the FG " + "to be retrieved from the database" + ) + db = get_db_() + fg_dict = db.retrieve_fg(func_grp_name) + if not fg_dict: + raise Exception("FG is not found in the database") + fg = Molecule(fg_dict["species"], fg_dict["coords"]) + + output_mol = process_mol( + operation_type=mol["operation_type"], mol=mol["mol"], **kwargs + ) + output_mol.substitute(mol["index"], fg, mol["bond_order"]) + + elif operation_type == "link_molecules": + # TODO: add a checking step in the original molecule to make sure no + # overlapping happens + # mol = {'operation_type': ['get_from_file', 'get_from_mol_db'], + # 'mol': ['mol1.xyz', 'mol_inchi'], + # 'index': [3, 5], + # 'bond_order': 2} + + # mol = {'operation_type': ['get_from_file', 'derive_molecule'], + # 'mol': ['mol2.xyz', {'operation_type': + # 'get_from_mol_db, 'mol': inchi}], + # 'index': [3, 5], + # 'bond_order': 2} + linking_mol = process_mol( + operation_type=mol["operation_type"][0], mol=mol["mol"][0], **kwargs + ) + linked_mol = process_mol( + operation_type=mol["operation_type"][1], mol=mol["mol"][1], **kwargs + ) + output_mol = linking_mol.link( + linked_mol, mol["index"][0], mol["index"][1], mol["bond_order"] + ) + + else: + raise ValueError(f"operation type {operation_type} is not supported") + + if local_opt: + force_field = kwargs.get("force_field", "mmff94") + steps = kwargs.get("steps", 500) + output_mol = perform_local_opt(output_mol, force_field, steps) + + charge = kwargs.get("charge") + charge = charge if charge is not None else output_mol.charge + output_mol.set_charge_and_spin(charge) + return output_mol
+ + +
[docs]def perform_local_opt(mol, force_field="uff", steps=200): + """ + Perform a local optimization on the molecule using OpenBabel. + + Args: + mol (Molecule): The molecule to be optimized. + force_field (str, optional): The force field to be used for the optimization; + options include ``gaff``, ``ghemical``, ``mmff94``, ``mmff94s``, and ``uff``; + defaults to ``uff``. + steps (int): The number of steps to be performed in the local optimization; + defaults to 200. + + Returns: + Molecule: The optimized molecule. + """ + a = BabelMolAdaptor(mol) + a.localopt(forcefield=force_field, steps=steps) + mol_opt = a.pymatgen_mol + return mol_opt
+ + +
[docs]def label_atoms(mol): + """ + Get the SMILES representation of a molecule and label the atoms that appear in the + SMILES string with the atom indexes as they appear in the molecule. + + .. example:: + If a monoglyme molecule is provided, the returned strings are: + O(C)CCOC + 0 1 2345 + + Helpful to know the atom indexes in the molecule without having to visualize it. + + Args: + mol (Molecule): The molecule to be labeled. + + Returns: + str: SMILES string followed by atom indexes. + """ + # supports all atom types and molecules as large as 999 atoms; does not + # support clusters + a = BabelMolAdaptor(mol) + pm = pb.Molecule(a.openbabel_mol) + mol_smiles = pm.write("smi").strip() + mol_smiles_copy = mol_smiles.lower() + counter = 0 + count_1 = "" + count_2 = "" + count_3 = "" + smiles = mol_smiles.lower() + atoms = [str(i).lower() for i in mol.species] + sorted_atoms = sorted(atoms, key=lambda x: len(x), reverse=True) + index_atom_map = {} + h_index = [i for i, j in enumerate(mol_smiles_copy) if j == "h"] + for atom in sorted_atoms: + if atom == "h": + smiles = smiles.replace(atom, "!", 1) + continue + index = smiles.find(atom) + if index != -1: + smiles = smiles.replace(atom, "!", 1) + index_atom_map[index] = atom + existing_atoms = [index_atom_map[i] for i in sorted(index_atom_map)] + for ch in smiles: + if ch == "!": + flag = 0 + if len(count_1) in h_index: + atom = "h" + flag = 1 + else: + atom = atoms[counter] + while atom not in existing_atoms: + counter += 1 + atom = atoms[counter] + if atom.lower() == "h": + i = 0 + else: + i = counter + if i < 10: + count_1 += f"{i: >{len(atom)}}" + count_2 += " " * len(atom) + count_3 += " " * len(atom) + elif i < 100: + count_1 += f"{i // 10: >{len(atom)}}" + count_2 += f"{i % 10: >{len(atom)}}" + count_3 += " " * len(atom) + else: + count_1 += f"{i // 10 // 10: >{len(atom)}}" + count_2 += f"{i % 100 // 10: >{len(atom)}}" + count_3 += f"{i % 10: >{len(atom)}}" + if flag == 0: + counter += 1 + else: + count_1 += " " + count_2 += " " + count_3 += " " + print(f"{mol_smiles}\n{count_1}\n{count_2}\n{count_3}")
+ + +
[docs]def get_bond_order_str(mol): + """ + Find bond order as a string ("U": unspecified, "S", "D": double, "T": triple, + "A": aromatic) by iterating over bonds of a molecule. First convert pymatgen mol + to openbabel mol to use openbabel in finding bond order. + + Args: + mol (Molecule): pymatgen Molecule object. + + Returns: + dict: Dictionary of bond orders with keys as tuples of atom indexes forming the + bond and values as bond order. + """ + bond_order = {} + a = BabelMolAdaptor(mol).openbabel_mol + for bond in OBMolBondIter(a): + atom_indices = tuple(sorted([bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()])) + order = bond.GetBondOrder() + if order == 0: + bond_order[atom_indices] = "U" + elif order == 1: + bond_order[atom_indices] = "S" + elif order == 2: + bond_order[atom_indices] = "D" + elif order == 3: + bond_order[atom_indices] = "T" + elif order == 5: + bond_order[atom_indices] = "A" + else: + raise TypeError("Bond order number {} is not understood".format(order)) + return bond_order
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/utilities/rdkit.html b/html/_modules/mispr/gaussian/utilities/rdkit.html new file mode 100644 index 00000000..3ef57524 --- /dev/null +++ b/html/_modules/mispr/gaussian/utilities/rdkit.html @@ -0,0 +1,915 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities.rdkit - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.utilities.rdkit

+"""Define functions for processing rdkit molecules."""
+
+import os
+import random
+import logging
+
+from mispr.gaussian.utilities.mol import get_bond_order_str
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_rdkit_mol(mol, sanitize=True, remove_h=False): + """ + Convert a pymatgen mol object to RDKit rdmol object. Uses RDKit to perform the + conversion <http://rdkit.org>. Accounts for aromaticity. + + Args: + mol (Molecule): pymatgen Molecule object. + sanitize (bool, optional): Whether to sanitize the molecule. + remove_h (bool, optional): whether to remove hydrogens. + + Returns: + Mol: RDKit Mol object. + """ + try: + import rdkit + + from rdkit import Chem + from rdkit.Geometry import Point3D + except ModuleNotFoundError: + raise ImportError("This function requires RDKit to be installed.") + + mol_species = [str(s) for s in mol.species] + mol_coords = mol.cart_coords + + rdkit_mol = Chem.rdchem.EditableMol(Chem.rdchem.Mol()) + conformer = Chem.Conformer(len(mol_species)) + + for index, (specie, coord) in enumerate(zip(mol_species, mol_coords)): + rdkit_atom = Chem.rdchem.Atom(specie) + rdkit_mol.AddAtom(rdkit_atom) + conformer.SetAtomPosition(index, Point3D(*coord)) + + rdkit_bonds = Chem.rdchem.BondType + bond_order_mapping = { + "U": rdkit_bonds.UNSPECIFIED, + "S": rdkit_bonds.SINGLE, + "D": rdkit_bonds.DOUBLE, + "T": rdkit_bonds.TRIPLE, + "A": rdkit_bonds.AROMATIC, + } + bond_orders = get_bond_order_str(mol) + + for bond, bond_order in bond_orders.items(): + order = bond_order_mapping[bond_order] + rdkit_mol.AddBond(bond[0] - 1, bond[1] - 1, order) + + rdkit_mol = rdkit_mol.GetMol() + if sanitize: + # if sanitization fails, inform the user and proceed normally + try: + Chem.SanitizeMol(rdkit_mol) + except Exception as e: + logger.info("Could not sanitize rdkit mol: {}".format(e)) + rdkit_mol.AddConformer(conformer, assignId=False) + if remove_h: + rdkit_mol = Chem.RemoveHs(rdkit_mol, sanitize=sanitize) + + return rdkit_mol
+ + +
[docs]def calc_energy(rdkit_mol, maxIters=200): + """ + Perform local optimization on rdkit Mol object and calculates its energy using UFF. + + Args: + rdkit_mol (Mol): RDKit Mol object. + maxIters (int, optional): Maximum number of iterations to perform. + + Returns: + float: Energy of the molecule. + """ + from rdkit.Chem import AllChem + + AllChem.UFFOptimizeMolecule(rdkit_mol, maxIters) + ff = AllChem.UFFGetMoleculeForceField(rdkit_mol) + ff.Minimize(maxIts=maxIters) + E = ff.CalcEnergy() + return E
+ + +
[docs]def draw_rdkit_mol(rdkit_mol, filename="mol.png", working_dir=None): + """ + Draw the 2D structure of a molecule and saves it to a file. + + Args: + rdkit_mol (Mol): RDKit Mol object. + filename (str, optional): Name of the file to save the image to; defaults to + "mol.png". + working_dir (str, optional): Directory to save the image to; defaults to + current working directory. + """ + from rdkit.Chem import Draw, AllChem + + working_dir = working_dir or os.getcwd() + AllChem.Compute2DCoords(rdkit_mol) + Draw.MolToFile(rdkit_mol, os.path.join(working_dir, filename))
+ + +
[docs]def draw_rdkit_mol_with_highlighted_bonds( + rdkit_mol, bonds, filename="mol.png", colors=None, working_dir=None +): + """ + Draw the 2D structure of a molecule and highlights the bonds specified by the user. + + Args: + rdkit_mol (Mol): RDKit Mol object. + bonds (list): List of tuples of indexes of atoms forming a bond to highlight; + e.g. [(3, 11), (5, 13)] to highlight the bonds between sites 3 and 11 and + sites 5 and 13. + filename (str, optional): Name of the file to save the image to; defaults to + "mol.png". + colors (list, optional): List of colors to use for highlighting the bonds; + colors should be provided in rgb format, e.g. (0.0, 0.0, 0.0) for black; + if not provided or number of colors provided is less than number of bonds to + highlight, will randomly generate colors. + working_dir (str, optional): Directory to save the image to; defaults to + current working directory. + """ + + def _generate_color(): + bond_color = (random.random(), random.random(), random.random()) + # prevent the generation of a white color + if bond_color == (1.0, 1.0, 1.0): + bond_color = _generate_color() + return bond_color + + from rdkit import Chem + from rdkit.Chem import rdDepictor + from rdkit.Chem.Draw import rdMolDraw2D + + working_dir = working_dir or os.getcwd() + rdDepictor.SetPreferCoordGen(True) + d = rdMolDraw2D.MolDraw2DCairo(500, 500) + rdkit_mol_copy = Chem.Mol(rdkit_mol.ToBinary()) + # optimize 2D depiction + rdDepictor.Compute2DCoords(rdkit_mol_copy, bondLength=1.5) + d.SetFontSize(0.6 * d.FontSize()) # reduce font size of bond number + + highlighted_bonds = [] + for i, bond in enumerate(bonds): + ind = rdkit_mol_copy.GetBondBetweenAtoms(*bond).GetIdx() + rdkit_mol_copy.GetBondWithIdx(ind).SetProp("bondNote", str(i)) + highlighted_bonds.append(ind) + + # use randomly generated colors if no or wrong number of colors are provided + if not colors or len(colors) < len(bonds): + colors = [] + for i in range(len(bonds)): + colors.append(_generate_color()) + + bond_colors = {} + for i, bond in enumerate(highlighted_bonds): + bond_colors[bond] = colors[i] + + rdMolDraw2D.PrepareAndDrawMolecule( + d, + rdkit_mol_copy, + highlightBonds=highlighted_bonds, + highlightBondColors=bond_colors, + ) + + d.DrawMolecule(rdkit_mol_copy) + d.FinishDrawing() + d.WriteDrawingText(os.path.join(working_dir, filename)) + return colors
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/bde.html b/html/_modules/mispr/gaussian/workflows/base/bde.html new file mode 100644 index 00000000..42794cb9 --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/bde.html @@ -0,0 +1,957 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.bde - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.bde

+"""Define the bond dissociation energy workflow."""
+
+import os
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.utilities.metadata import get_job_name
+from mispr.gaussian.fireworks.break_mol import BreakMolFW
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+from mispr.gaussian.firetasks.parse_outputs import BDEtoDB
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+
+
[docs]def get_bde( + mol_operation_type, + mol, + ref_charge=0, + fragment_charges=None, + bonds=None, + open_rings=False, + db=None, + name="bde_calculation", + working_dir=None, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=False, + visualize=True, + **kwargs +): + """ + Define a dynamic workflow for calculating the bond dissociation energy. + + * **Firework 1**: Optimize the principle molecule. + * **Firework 2**: Run a frequency analysis. + * **Firework 3**: Break the bonds in the molecule, find all unique fragments, and + generate new optimization and frequency fireworks for each fragment. + * **Firework N**: Run a BDE calculation for each fragment and create a summary BDE + document/json file. + + .. note:: + Fireworks 1 and 2 are only present if user does not request to skip them. + + .. note:: + + Charges on the fragments in this workflow are assigned as (following the method + in the BDE analysis module in pymatgen): + + 1. **Neutral molecule**: [(0, 0), (1, -1), (-1, 1)] + 2. **Molecule with charge -N**: [(-N, 0), (-N+1, -N+2), (-N+2, -N+1), (0, -N)] + 3. **Molecule with charge +N**: [(N, 0), (N-1, N-2), (N-2, N-1), (0, N)] + + .. note:: + If multiple bonds are being broken but one fragment results in an error, + the workflow will proceed normally and the final document will include all bonds + except for the one involving the failed fragment. + + Args: + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + ref_charge (int, optional): Charge on the principle molecule. Defaults to 0. + fragment_charges (list, optional): List of additional charges to consider on + the fragments besides the default ones. If ``ref_charge`` is -2, by default + all fragments will be calculated with a charge of 0, -1, and -2. If the + user provides ``fragment_charges`` is [-3], -3 and 1 will be additionally + calculated. If the user provides ``fragment_charges`` is [-2], this will not + cause any change since they are already calculated by the workflow; + defaults to None. + bonds (list, optional): List of tuples of the bonds to break; e.g. + [(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 + and between atoms 1 and 2; if none is specified, will attempt to break all + bonds. Defaults to None. + open_rings (bool, optional): If ``True``, will open rings encountered during + fragmentation using OpenBabel's local opt.. Defaults to ``False``. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): Name of the workflow. Defaults to "bde_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. Defaults to the current + working directory. + opt_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the optimization step; e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the frequency step; default parameters will be used if not specified. + solvent_gaussian_inputs (str, optional): Gaussian input parameters corresponding + to the implicit solvent model to be used in the ESP calculations, if any; + e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_gaussian_inputs``). Defaults to None. + solvent_properties (dict, optional): Additional input parameters to be used in + the ESP calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. Defaults to None. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``,otherwise uses z-matrix. Defaults to ``True``. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the molecule; e.g.: + {"Li":1, "O":-2}. Defaults to None. + skips (list, optional): List of jobs to skip; e.g.: ["opt", "freq"]; only + applicable to the principle molecule. Defaults to None. + visualize (bool, optional): If ``True``, will generate a summary plot of the + 2D structure of the principle molecule with broken bonds highlighted in + color, along with a bar plot of the corresponding BDEs; requires RDKit to + be installed for bond highlighting; if RDKit is not found, will throw a + warning and proceed normally. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow. + + Returns: + Workflow + """ + fws = [] + working_dir = working_dir or os.getcwd() + mol = recursive_relative_to_absolute_path(mol, working_dir) + gout_key = "ref_mol" + gaussian_inputs = handle_gaussian_inputs( + {"opt": opt_gaussian_inputs, "freq": freq_gaussian_inputs}, + solvent_gaussian_inputs, + solvent_properties, + ) + opt_gaussian_inputs = gaussian_inputs["opt"] + freq_gaussian_inputs = gaussian_inputs["freq"] + + if skips: + check_result = ["final_energy", "Enthalpy"] + else: + check_result = None + + _, label, opt_freq_fws = common_fw( + mol_operation_type=mol_operation_type, + mol=mol, + charge=ref_charge, + working_dir=working_dir, + dir_structure=["principle_mol"], + db=db, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + skips=skips, + check_result=check_result, + gout_key=gout_key, + **kwargs + ) + fws += opt_freq_fws + + break_fw = BreakMolFW( + mol=gout_key, + mol_operation_type="get_from_run_dict", + from_fw_spec=True, + bonds=bonds, + open_rings=open_rings, + ref_charge=ref_charge, + fragment_charges=fragment_charges, + db=db, + calc_frags=True, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + name=get_job_name(label, "breaking"), + parents=fws[:], + working_dir=os.path.join(working_dir, label, "fragments"), + **kwargs + ) + fws.append(break_fw) + + fw_analysis = Firework( + BDEtoDB( + principle_mol_key=gout_key, + db=db, + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + visualize=visualize, + **{ + i: j + for i, j in kwargs.items() + if i in BDEtoDB.required_params + BDEtoDB.optional_params + } + ), + parents=fws[:], + name="{}-{}".format(label, "bde_analysis"), + spec={ + "_launch_dir": os.path.join(working_dir, label, "analysis"), + "_allow_fizzled_parents": True, + }, + ) + fws.append(fw_analysis) + + return Workflow( + fws, + name="{}_{}".format(label, name), + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/binding_energy.html b/html/_modules/mispr/gaussian/workflows/base/binding_energy.html new file mode 100644 index 00000000..7449acb8 --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/binding_energy.html @@ -0,0 +1,966 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.binding_energy - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.binding_energy

+"""Define the binding energy workflow."""
+
+import os
+import logging
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+from mispr.gaussian.firetasks.parse_outputs import BindingEnergytoDB
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_binding_energies( + mol_operation_type, + mol, + index, + bond_order=1, + db=None, + name="binding_energy_calculation", + working_dir=None, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=None, + **kwargs +): + """ + Define a workflow for calculating the binding energy between two molecules. + + * **Fireworks 1 & 2**: Optimize the two molecules in parallel. + * **Firework 3 & 4**: Run a frequency calculation on each molecule. + * **Firework 5**: Link the two optimized molecules at a binding site and optimize + the geometry of the generated complex. + * **Firework 6**: Run a frequency calculation on the optimized complex. + * **Firework 7**: Calculate the binding energy of the complex and create BE + document/json file. + + Args: + mol_operation_type (list): List of strings of the type of molecule operations. + See process_mol defined in Defines the binding energy + ``workflow.mispr/gaussian/utilities/mol.py`` for supported operations; e.g. + ["get_from_mol", "get_from_file"] to get the first molecule from a + ``Molecule`` object and the second molecule from a file. + mol (list): List of the source of the two molecules to be processed. Should + match the order in ``mol_operation_type``; e.g. if ``mol_operation_type`` is + ["get_from_mol", "get_from_file"], ``mol`` should be + [``Molecule``, path to molecule file]. + index (list): List of indices of the two sites in the molecules at which they + are expected to bind; order should match that in ``mol_operation_type`` + and ``mol``. + bond_order (int, optional): Bond order to calculate the bond length between the + two sites. Defaults to 1. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): name of the workflow; defaults to + "binding_energy_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. Defaults to the current + working directory. + opt_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the optimization step; e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the frequency step; default parameters will be used if not specified. + solvent_gaussian_inputs (str, optional): Gaussian input parameters corresponding + to the implicit solvent model to be used in the ESP calculations, if any; + e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_gaussian_inputs``, etc.). Defaults to None. + solvent_properties (dict, optional): Additional input parameters to be used in + the ESP calculations and relevant to the solvent model, if any; for example, + {"EPS":12}. Defaults to None. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``, otherwise uses z-matrix. Defaults to ``True``. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the molecule; for + example: {"Li":1, "O":-2}. Defaults to None. + skips (list, optional): List of lists of jobs to skip for each molecule; e.g.: + [["opt", "freq"], ["opt"]]; order should be consistent with that in + ``mol_operation_type`` and ``mol``. Defaults to None. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow. + + Returns: + Workflow + """ + # TODO: test with different charges and spin multiplicities when + # deriving molecules + # TODO: include an option to use free energy instead of SCF energy + # mol_operation_type = [], mol = [], index = [], skips = [[], []], + # mol_name = [] + # order of the indices should be consistent with the order of the mols + # process_mol_func applies to both input molecules, so if set to False, + # should give mol_name to each molecule, and if set to True, both will + # take MolFormula even if mol_name is given to either or both + fws = [] + labels = [] + working_dir = working_dir or os.getcwd() + gout_keys = ["mol_1", "mol_2", "mol_linked"] + mol = recursive_relative_to_absolute_path(mol, working_dir) + + gaussian_inputs = handle_gaussian_inputs( + {"opt": opt_gaussian_inputs, "freq": freq_gaussian_inputs}, + solvent_gaussian_inputs, + solvent_properties, + ) + opt_gaussian_inputs = gaussian_inputs["opt"] + freq_gaussian_inputs = gaussian_inputs["freq"] + + if skips is None: + skips = [None, None] + check_result = [] + for i, j in enumerate(skips): + if j: + check_result.append(["final_energy"]) + else: + check_result.append(None) + + parents = [] + for position, [operation, molecule, key, skip, check, molecule_name] in enumerate( + zip( + mol_operation_type, + mol, + gout_keys[:2], + skips, + check_result, + kwargs.pop("mol_name", [None, None]), + ) + ): + _, label, opt_freq_init_fws = common_fw( + mol_operation_type=operation, + mol=molecule, + working_dir=working_dir, + db=db, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=key, + skips=skip, + mol_name=molecule_name, + check_result=check, + **kwargs + ) + fws += opt_freq_init_fws + parents.append(len(fws)) + labels.append(label) + + final_mol_label = "{}_{}".format(labels[0], labels[1]) + + kwargs.pop("process_mol_func", False) + + _, _, opt_freq_final_fws = common_fw( + mol_operation_type="link_molecules", + mol={ + "operation_type": ["get_from_run_dict", "get_from_run_dict"], + "mol": gout_keys[:2], + "index": index, + "bond_order": bond_order, + }, + working_dir=working_dir, + db=db, + filename=final_mol_label, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + process_mol_func=False, + mol_name=final_mol_label, + gout_key=gout_keys[-1], + from_fw_spec=True, + **kwargs + ) + fws += opt_freq_final_fws + links_dict = {fws[i - 1]: fws[-len(opt_freq_final_fws)] for i in parents} + fw_analysis = Firework( + BindingEnergytoDB( + index=index, + db=db, + keys=gout_keys, + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + **{ + i: j + for i, j in kwargs.items() + if i + in BindingEnergytoDB.required_params + BindingEnergytoDB.optional_params + } + ), + parents=fws[:], + name="{}-{}".format(final_mol_label, "binding_energy_analysis"), + spec={"_launch_dir": os.path.join(working_dir, "analysis")}, + ) + fws.append(fw_analysis) + + return Workflow( + fws, + name="{}_{}".format(final_mol_label, name), + links_dict=links_dict, + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/core.html b/html/_modules/mispr/gaussian/workflows/base/core.html new file mode 100644 index 00000000..15588654 --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/core.html @@ -0,0 +1,1111 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.core - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.core

+"""Define a list of common fireworks used in Gaussian workflows."""
+
+import os
+import logging
+
+from copy import deepcopy
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.utilities.mol import process_mol
+from mispr.gaussian.fireworks.core import CalcFromMolFW, CalcFromRunsDBFW
+from mispr.gaussian.utilities.gout import process_run
+from mispr.gaussian.utilities.metadata import get_job_name, get_mol_formula
+from mispr.gaussian.firetasks.parse_outputs import ProcessRun
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+WORKFLOW_KWARGS = Workflow.__init__.__code__.co_varnames
+
+
+
[docs]class GoutTypeError(Exception): + """ + Exception that is thrown when no Gaussian output is provided. + """ + + def __init__(self, msg=None): + if msg is None: + msg = ( + "no Gaussian output provided; to skip optimization, you " + "need to input the molecule in any of the " + "supported Gaussian output formats" + ) + self.msg = msg + super(GoutTypeError, self).__init__(msg) + + def __repr__(self): + return self.msg
+ + +def _recursive_key_check(grun, grun_key): + """ + Check if the key is in the dictionary. If not, it checks recursively if the key is + in the dictionary of the dictionary. + + Args: + grun (GaussianOutput): GaussianOutput object. + grun_key (str): Key to be checked. + + Returns: + bool. + """ + key_exists = grun_key in grun + if not key_exists: + for key, value in grun.items(): + if isinstance(value, dict): + key_exists = key_exists or _recursive_key_check(value, grun_key) + return key_exists + + +def _process_mol_check( + working_dir, + process_mol_func=True, + mol_operation_type=None, + mol=None, + dir_head=None, + mol_name=None, + db=None, + dir_structure=None, + charge=None, +): + """ + Process molecule input to generate a label used in naming the workflow for easy + monitoring when the corresponding job is running. + + Args: + working_dir (str): Path to the working directory of the job. + process_mol_func (bool, optional): Whether to process the molecule; if ``True``, + will use the molecular formula as the label. + mol_operation_type (str, optional): The type of molecule operation. See + ``process_mol`` defined in ``mispr/gaussian/utilities/mol.py`` for supported + operations; required when ``process_mol`` is ``True``. + mol (Molecule, GaussianOutput, str, dict, optional): Source of the molecule to + be processed; required when ``process_mol`` is ``True`` and should match + the ``mol_operation_type``. + dir_head (str, optional): The name of the head of the directory where the + workflow corresponding to the molecule will be run. + mol_name (str, optional): The name of the molecule. Defaults to None. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files; used when + ``process_mol_func``is ``True``. + dir_structure (list, optional): List of strings corresponding to the name + of the subfolders that will be created inside the ``dir_head`` where the + workflow will be running. + charge (int, optional): Charge of the molecule; only used when + ``process_mol_func`` is ``True``. + """ + if process_mol_func: + mol = process_mol( + mol_operation_type, mol, db=db, charge=charge, working_dir=working_dir + ) + mol_operation_type = "get_from_mol" + mol_formula = get_mol_formula(mol) + opt_job_name = get_job_name(mol, "optimization") + freq_job_name = get_job_name(mol, "frequency") + label = mol_formula + elif mol_name: + opt_job_name = "{}_optimization".format(mol_name) + freq_job_name = "{}_frequency".format(mol_name) + label = mol_name + else: + opt_job_name = "optimization" + freq_job_name = "frequency" + label = "mol" + if not dir_head: + dir_head = label + # dir_struct = [dir_head] + kwargs.get('dir_structure', []) + if dir_structure is None: + dir_structure = [] + dir_struct = [dir_head] + dir_structure + working_dir = os.path.join(working_dir, *dir_struct) + return mol_operation_type, mol, label, opt_job_name, freq_job_name, working_dir + + +# TODO: avoid overwriting a directory if it exists (happens when molecules have +# same mol formula) +
[docs]def common_fw( + mol_operation_type, + mol, + working_dir, + opt_gaussian_inputs, + freq_gaussian_inputs, + cart_coords, + oxidation_states, + gout_key=None, + db=None, + process_mol_func=True, + mol_name=None, + dir_head=None, + skips=None, + check_result=None, + **kwargs, +): + """ + Define a list of Fireworks commonly used in Gaussian workflows. + + * **Firework 1**: Optimize the molecule. + * **Firework 2**: Run a frequency analysis. + + Args: + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + working_dir (str): Path of the working directory where any required input files + can be found and output will be created. + opt_gaussian_inputs (dict): Dictionary of Gaussian input parameters for the + optimization step. + freq_gaussian_inputs (dict): Dictionary of Gaussian input parameters for the + frequency step. + cart_coords (bool): Whether to use cartesian coordinates in writing Gaussian + input files. + oxidation_states (dict): Dictionary of oxidation states that can be used in + setting the charge and spin multiplicity of the molecule; e.g.: + {"Li":1, "O":-2}. + gout_key (str, optional): Unique key for the Gaussian output dict; used to + differentiate Gaussian output dictionaries generated in the same workflow; + if None is provided, the key will be set "mol". + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if None is provided, + attempts to get it from the configuration files. + process_mol_func (bool, optional): Whether to process the molecule; if ``True``, + will use the molecular formula as the label. Defaults to ``True``. + mol_name (str, optional): The name of the molecule; ignored if + ``process_mol_func`` is set to ``True``. + dir_head (str, optional): The name of the head of the directory where the + workflow corresponding to the molecule will be run. + skips (list, optional): List of jobs to skip; e.g.: ["opt", "freq"]; defaults + to None. + check_result (list, optional): List of properties to check for in the output + file when skipping jobs; ensures that properties required by the workflow are + available via the molecule format provided as an input (e.g. Gaussian + output dictionary). + kwargs (keyword arguments): Additional kwargs to be passed to the Fireworks and + Firetasks. + + Returns: + Molecule, GaussianOutput, str, dict: Type varies based on the input mol and the + operations performed inside the function. + str: Molecule label. + list: List of Fireworks. + """ + fws = [] + if not gout_key: + gout_key = "mol" + + original_mol_operation_type = deepcopy(mol_operation_type) + original_mol = deepcopy(mol) + + ( + mol_operation_type, + mol, + label, + opt_job_name, + freq_job_name, + working_dir, + ) = _process_mol_check( + working_dir, + process_mol_func, + mol_operation_type, + mol, + dir_head, + mol_name, + db, + kwargs.get("dir_structure", []), + kwargs.get("charge", None), + ) + + if skips is None: + skips = [] + if not skips: + # if user chooses to perform both opt and freq calc + opt_fw = CalcFromMolFW( + mol=mol, + mol_operation_type=mol_operation_type, + db=db, + name=opt_job_name, + working_dir=os.path.join(working_dir, "Optimization"), + input_file=f"{label}_opt.com", + output_file=f"{label}_opt.out", + gaussian_input_params=opt_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_key + "_opt", + **kwargs, + ) + fws.append(opt_fw) + + spec = kwargs.pop("spec", {}) + spec.update({"proceed": {"has_gaussian_completed": True}}) + freq_fw = CalcFromRunsDBFW( + db=db, + name=freq_job_name, + parents=opt_fw, + gaussian_input_params=freq_gaussian_inputs, + working_dir=os.path.join(working_dir, "Frequency"), + input_file=f"{label}_freq.com", + output_file=f"{label}_freq.out", + cart_coords=cart_coords, + gout_key=gout_key, + spec=spec, + **kwargs, + ) + fws.append(freq_fw) + + elif len(skips) == 1: + if skips[0].lower() == "opt": + # if user chooses to skip opt, only perform freq calc and + # restrict the mol input to any gaussian output format + if mol_operation_type == "get_from_mol" and len(mol) == 1: + freq_fw = CalcFromMolFW( + mol=mol, + mol_operation_type=mol_operation_type, + db=db, + name=freq_job_name, + working_dir=os.path.join(working_dir, "Frequency"), + input_file=f"{label}_freq.com", + output_file=f"{label}_freq.out", + gaussian_input_params=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_key, + **kwargs, + ) + fws.append(freq_fw) + elif original_mol_operation_type not in [ + "get_from_gout", + "get_from_gout_file", + "get_from_run_dict", + "get_from_run_id", + "get_from_run_query", + ]: + raise GoutTypeError() + else: + freq_fw = CalcFromMolFW( + mol=mol, + mol_operation_type=mol_operation_type, + db=db, + name=freq_job_name, + working_dir=os.path.join(working_dir, "Frequency"), + input_file=f"{label}_freq.com", + output_file=f"{label}_freq.out", + gaussian_input_params=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_key, + **kwargs, + ) + fws.append(freq_fw) + + elif skips[0].lower() == "freq": + # if user chooses to skip freq, only perform opt + opt_fw = CalcFromMolFW( + mol=mol, + mol_operation_type=mol_operation_type, + db=db, + name=opt_job_name, + working_dir=os.path.join(working_dir, "Optimization"), + input_file=f"{label}_opt.com", + output_file=f"{label}_opt.out", + gaussian_input_params=opt_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_key + "_opt", + **kwargs, + ) + fws.append(opt_fw) + + else: + # if user chooses to skip both opt and freq, only process the mol and + # restrict the mol input to any gaussian output format + if original_mol_operation_type not in [ + "get_from_gout", + "get_from_gout_file", + "get_from_run_dict", + "get_from_run_id", + "get_from_run_query", + ]: + raise GoutTypeError() + else: + run = process_run( + original_mol_operation_type, + original_mol, + db=db, + working_dir=working_dir, + ) + if check_result: + keys_exist = [] + for grun_key in check_result: + keys_exist.append(_recursive_key_check(run, grun_key)) + not_found_ind = [ + ind for ind, boolean in enumerate(keys_exist) if not boolean + ] + if not_found_ind: + not_found_keys = [check_result[ind] for ind in not_found_ind] + raise ValueError( + "Gaussian output does not include {}. " + "Stopping.".format(not_found_keys) + ) + + spec = kwargs.pop("spec", {}) + spec.update({"tag": kwargs.get("tag", "unknown")}) + spec.update({"_launch_dir": working_dir}) + fws.append( + Firework( + ProcessRun( + run=run, + operation_type="get_from_run_dict", + db=db, + gout_key=gout_key, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessRun.required_params + ProcessRun.optional_params + }, + ), + name=get_job_name(label, "process_run"), + spec=spec, + ) + ) + return mol, label, fws
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/esp.html b/html/_modules/mispr/gaussian/workflows/base/esp.html new file mode 100644 index 00000000..4b11f14f --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/esp.html @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.esp - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.esp

+"""Define the electrostatic partial charges workflow."""
+
+import os
+import logging
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.fireworks.core import CalcFromRunsDBFW
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.utilities.metadata import get_job_name
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+from mispr.gaussian.firetasks.parse_outputs import ESPtoDB
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_esp_charges( + mol_operation_type, + mol, + db=None, + name="esp_charges_calculation", + working_dir=None, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + esp_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=None, + **kwargs, +): + """ + Define a workflow for calculating the electrostatic partial charges. + + * **Firework 1**: Optimize the molecule. + * **Firework 2**: Run a frequency analysis. + * **Firework 3**: Run an ESP calculation. + * **Firework 4**: Create ESP document/json file. + + Args: + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): Name of the workflow. Defaults to "esp_charges_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. Defaults to the current + working directory. + opt_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the optimization step; e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the frequency step; default parameters will be used if not specified. + esp_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the ESP step; default parameters will be used if not specified. + solvent_gaussian_inputs (str, optional): Gaussian input parameters corresponding + to the implicit solvent model to be used in the ESP calculations, if any; + e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_gaussian_inputs``, etc.). Defaults to None. + solvent_properties (dict, optional): Additional input parameters to be used in + the ESP calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. Defaults to None. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``, otherwise uses z-matrix. Defaults to ``True``. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the molecule; e.g.: + {"Li":1, "O":-2}. Defaults to None. + skips (list, optional): List of jobs to skip; e.g.: ["opt", "freq"]; defaults + to None. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow. + + Returns: + Workflow + str: Label of the molecule (e.g. "H2O", "water", etc.). + """ + fws = [] + working_dir = working_dir or os.getcwd() + mol = recursive_relative_to_absolute_path(mol, working_dir) + gout_keys = kwargs.pop("gout_keys", ["mol", "mol_esp"]) + + gaussian_inputs = handle_gaussian_inputs( + { + "opt": opt_gaussian_inputs, + "freq": freq_gaussian_inputs, + "esp": esp_gaussian_inputs, + }, + solvent_gaussian_inputs, + solvent_properties, + ) + opt_gaussian_inputs = gaussian_inputs["opt"] + freq_gaussian_inputs = gaussian_inputs["freq"] + esp_gaussian_inputs = gaussian_inputs["esp"] + + _, label, opt_freq_fws = common_fw( + mol_operation_type=mol_operation_type, + mol=mol, + working_dir=working_dir, + db=db, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_keys[0], + skips=skips, + **kwargs, + ) + fws += opt_freq_fws + + # add to doc: user should not add esp path to input parameters + if "input_parameters" not in esp_gaussian_inputs: + esp_gaussian_inputs["input_parameters"] = {} + # mol_esp = "{}_esp".format(os.path.join(working_dir, label, "ESP", label)) + esp_gaussian_inputs["input_parameters"].update({f"{label}_esp": None}) + + spec = kwargs.pop("spec", {}) + if not skips or len(skips) == 1 and skips[0].lower() == "opt": + spec.update( + {"proceed": {"has_gaussian_completed": True, "stationary_type": "Minimum"}} + ) + else: + spec.update({"proceed": {"has_gaussian_completed": True}}) + + esp_fw = CalcFromRunsDBFW( + db, + input_file="{}_esp.com".format(label), + output_file="{}_esp.out".format(label), + name=get_job_name(label, "esp"), + parents=fws[:], + gaussian_input_params=esp_gaussian_inputs, + working_dir=os.path.join(working_dir, label, "ESP"), + cart_coords=cart_coords, + gout_key=gout_keys[1], + spec=spec, + **kwargs, + ) + fws.append(esp_fw) + + fw_analysis = Firework( + ESPtoDB( + db=db, + keys=gout_keys, + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + **{ + i: j + for i, j in kwargs.items() + if i in ESPtoDB.required_params + ESPtoDB.optional_params + }, + ), + parents=fws[:], + name="{}-{}".format(label, "esp_analysis"), + spec={"_launch_dir": os.path.join(working_dir, label, "analysis")}, + ) + fws.append(fw_analysis) + + return ( + Workflow( + fws, + name=get_job_name(label, name), + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS}, + ), + label, + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/ip_ea.html b/html/_modules/mispr/gaussian/workflows/base/ip_ea.html new file mode 100644 index 00000000..f737fc86 --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/ip_ea.html @@ -0,0 +1,1327 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.ip_ea - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.ip_ea

+"""Define the redox potentials workflow."""
+
+import os
+import logging
+
+from copy import deepcopy
+from queue import Queue
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.utilities.files import (
+    bibtex_parser,
+    recursive_relative_to_absolute_path,
+)
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+from mispr.gaussian.firetasks.parse_outputs import IPEAtoDB
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]class Node: + """ + Generate the fireworks corresponding to different molecule states in the IP/EA + workflow. Each molecule state corresponds to a node in the tree. The node is a leaf + if it is the last node in the tree, otherwise it is a branch. Not meant to be + instantiated directly. + """ + + def __init__( + self, + state: str, + phase: str, + num_electrons: int, + mol_operation_type=None, + mol=None, + skips=None, + check_result=None, + parent: "Node" = None, + ref_charge=None, + branch_cation_from_anion: bool = False, + h_index: list = None, + ): + """ + Args: + state (str): Current state of the molecule: cation or anion. + phase (str): Current phase of the molecule: gas or solution. + num_electrons (int): Number of electrons to transfer. + mol_operation_type (str, optional): Type of molecule operation; required + for the parent node, i.e. initial molecule state, but not for the child + nodes. + mol (Molecule, GaussianOutput, str, dict, optional): Molecule to be + processed; required for the parent node, i.e. initial molecule state, + but not for the child nodes since these are generated from the parent + node. + skips (list, optional): List of jobs to skip; only relevant to the parent + node, i.e. initial molecule state. Defaults to None. + check_result (list, optional): List of properties to check for in the + output file; only relevant when skipping jobs at the parent node; + currently checks for "final_energy" and "Gibbs Free Energy", since + these are used in calculating the redox potential. + parent (str, optional): Parent node of the current node; None if the node + corresponds to the initial molecule state. + ref_charge (int, optional): The initial charge on the molecule; only + relevant to the parent node. + branch_cation_from_anion (bool, optional): Whether to add a hydrogen atom + at the current node; relevant for PCET calculations. + h_index (int, optional): The site index in the molecule at which to attach + the hydrogen atoms in the PCET calculations. + """ + self.phase = phase + self.state = state + self.parent = parent + + add_charge = ( + 1 if state.lower() == "cation" else -1 if state.lower() == "anion" else 0 + ) + add_charge *= num_electrons + if parent is None: + self.added_e = 0 + self.added_h = 0 + self.charge = ref_charge + else: + if add_charge < 0 or not branch_cation_from_anion: + self.added_e = self.parent.added_e - add_charge + self.added_h = self.parent.added_h + else: + self.added_e = self.parent.added_e + self.added_h = self.parent.added_h + add_charge + self.charge = self.parent.charge + add_charge + + self.gout_key = f"{self.phase.lower()}_{self.added_e}_{self.added_h}" + + self.fireworks = None + self.children_nodes = [] + + self.mol = None + if parent is None: + assert ( + mol_operation_type is not None + ), "if parent is None, a mol_operation type should be given" + assert mol is not None, "if parent is None, mol should be given" + self.mol_operation_type = mol_operation_type + self.mol = mol + self.check = check_result + self.process_mol_func = True + self.from_fw_spec = False + self.dir_head = None + else: + if branch_cation_from_anion and add_charge > 0: + h_atom = "[H]" + self.mol_operation_type = "link_molecules" + self.mol = { + "operation_type": ["get_from_run_dict", "get_from_str"], + "mol": [self.parent.gout_key, h_atom], + "index": [h_index[self.parent.added_h], 0], + "bond_order": 1, + } + if num_electrons > 1: + for i in range(1, num_electrons): + self.mol = { + "operation_type": ["link_molecules", "get_from_str"], + "mol": [self.mol, h_atom], + "index": [h_index[self.parent.added_h + i], 0], + "bond_order": 1, + } + else: + self.mol_operation_type = "get_from_run_dict" + self.mol = self.parent.gout_key + self.process_mol_func = False + self.check = [] + self.from_fw_spec = True + self.dir_head = self.parent.dir_head + self.skip = skips + self.mol_name = None + +
[docs] def create_fireworks( + self, + opt_gaussian_inputs, + freq_gaussian_inputs, + solvent_gaussian_inputs, + solvent_properties, + working_dir, + db, + cart_coords, + branch_cation_from_anion, + **kwargs, + ): + """ + Generate the optimization and/or frequency fireworks corresponding to the + current node. + """ + if "mol_name" in kwargs: + self.mol_name = kwargs["mol_name"] + self.dir_head = kwargs["mol_name"] + kwargs.pop("mol_name") + if self.mol_name: + self.mol_name = self.mol_name + f"_{self.phase.lower()}" + if self.parent is None: + if "process_mol_func" in kwargs: + self.process_mol_func = kwargs["process_mol_func"] + kwargs.pop("process_mol_func") + else: + if "process_mol_func" in kwargs: + kwargs.pop("process_mol_func") + if not self.mol_name: + self.mol_name = "{}_{}".format(self.dir_head, self.phase.lower()) + + opt_gins = deepcopy(opt_gaussian_inputs) + freq_gins = deepcopy(freq_gaussian_inputs) + solvent_gins = deepcopy(solvent_gaussian_inputs) + solvent_props = deepcopy(solvent_properties) + + if self.phase.lower() != "solution": + solvent_gins = None + solvent_props = None + + gaussian_inputs = handle_gaussian_inputs( + {"opt": opt_gins, "freq": freq_gins}, solvent_gins, solvent_props + ) + opt_gins = gaussian_inputs["opt"] + freq_gins = gaussian_inputs["freq"] + + dir_structure = [self.phase] + sec_dir_name = f"{self.added_e}e" + if branch_cation_from_anion: + sec_dir_name = f"{sec_dir_name}{self.added_h}h" + dir_structure.append(sec_dir_name) + + local_mol, label, local_fws = common_fw( + mol_operation_type=self.mol_operation_type, + mol=self.mol, + working_dir=working_dir, + db=db, + opt_gaussian_inputs=opt_gins, + freq_gaussian_inputs=freq_gins, + cart_coords=cart_coords, + oxidation_states=None, + process_mol_func=self.process_mol_func, + mol_name=self.mol_name, + dir_head=self.dir_head, + gout_key=self.gout_key, + skips=self.skip, + check_result=self.check, + dir_structure=dir_structure, + from_fw_spec=self.from_fw_spec, + charge=self.charge, + str_type="smi", + **kwargs, + ) + if self.parent is None and self.dir_head is None: + self.dir_head = label + self.fireworks = local_fws + return
+ +
[docs] def branch( + self, + branching_states, + branching_phases, + num_of_electrons, + branch_cation_from_anion, + h_index, + vertical, + ): + """ + Generate the children nodes of the current node in the tree representing the + IP/EA workflow. + """ + if self.state == "cation": + branching_states = [i for i in branching_states if i != "anion"] + if self.state == "anion": + if not branch_cation_from_anion: + branching_states = [i for i in branching_states if i != "cation"] + for state in branching_states: + if vertical: + if state == "reference": + skips = None + else: + skips = ["opt"] + else: + skips = None + self.children_nodes.append( + Node( + state, + self.phase, + num_of_electrons, + parent=self, + branch_cation_from_anion=branch_cation_from_anion, + h_index=h_index, + skips=skips, + ) + ) + if self.phase in branching_phases: + branching_phases.remove(self.phase) + for phase in branching_phases: + if vertical: + if self.state == "reference": + skips = None + else: + skips = ["opt"] + else: + skips = None + self.children_nodes.append( + Node( + self.state, + phase, + 0, + parent=self, + branch_cation_from_anion=branch_cation_from_anion, + skips=skips, + ) + ) + return self.children_nodes
+ + +
[docs]def get_ip_ea( + mol_operation_type, + mol, + ref_charge, + single_step=False, + vertical=False, + pcet=False, + h_index=None, + num_electrons=1, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + states=None, + phases=None, + electrode_potentials=None, + gibbs_elec=-0.001378786, + gibbs_h=-0.41816, + db=None, + name="ip_ea_calculation", + working_dir=None, + cart_coords=True, + ref_skips=None, + **kwargs, +): + """ + Define a workflow for calculating the ionization potential (IP) and electron affinity + (EA) in eV. Supports multiple methods for calculating redox potentials in gas + and/or solution: + + * **Direct electron transfer** + * **Vertical calculation of IP and EA** + * **Adiabatic IP/EA** + * **Sequential PCET** + + Uses a tree structure to dynamically define the dependencies of the fireworks. The + structure of the tree varies based on the inputs to the workflow. + + Args: + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + ref_charge (int): The initial charge on the molecule. + single_step (bool, optional): Whether to run the electron transfer in a single + or multiple steps; e.g. if ``num_electrons`` is set to 2 and ``single_step`` + is ``False``, the workflow will run the electron transfer in two steps; + defaults to ``False``. + vertical (bool, optional): Whether to run the vertical IP/EA calculations, + in which optimization is performed only at the reference state at each + phase specified, thereby skipping the optimization step at the charge states; + defaults to ``False``. + pcet (bool, optional): Whether to run sequential proton-coupled electron + transfer calculations; number of hydrogen transfer steps is assumed to be + equal to the number of electron transfers. Defaults to ``False``. + h_index (int, optional): The site index in the molecule at which to attach the + hydrogen atoms in the PCET calculations. Defaults to None. + num_electrons (int, optional): The number of electrons to be transferred; + defaults to 1. + opt_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the optimization step; e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the frequency step; default parameters will be used if not specified. + solvent_gaussian_inputs (str, optional): Gaussian input parameters corresponding + to the implicit solvent model to be used in the redox potential calculations, + if any; e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_gaussian_inputs``). Defaults to None. + solvent_properties (dict, optional): Additional input parameters to be used in + the ESP calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. Defaults to None. + states (list, optional): List of states to be calculated; e.g. ["cation"] for + oxidation, ["anion"] for reduction, or ["cation", "anion"] for oxidation + and reduction calculations; runs both if None is specified. + phases (list, optional): List of phases to be calculated; e.g. ["solution"] for + liquid phase, ["gas"] for gas phase, or ["gas", "solution"] for the full + thermodynamic cycle; runs both if None is specified. + electrode_potentials (dict, optional): Dictionary of electrode potentials to be + used in converting the absolute oxidation and reduction potentials to + commonly used potential scales; e.g.: + + .. code-block:: python + + { + lithium": { + "potential": 1.40, + "ref": bibtex_parser("li_pot.bib", data_dir), + } + } + + Uses hydrogen, magnesium, and lithium if None is specified; overwrites the + existing values if any of these are specified; if different potential scales + are specified, computes the potential relative to the three default scales + as well as the new ones specified. + gibbs_elec (float, optional): The electron gibbs free energy in Hartree; + defaults to -0.001378786. + gibbs_h (float, optional): The hydrogen gibbs free energy in Hartree; + defaults to -0.41816. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): Name of the workflow. Defaults to "ip_ea_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. Defaults to the current + working directory. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``, otherwise uses z-matrix. Defaults to ``True``. + ref_skips (list, optional): List of jobs to skip; e.g.: ["opt", "freq"]; only + applies to the molecule in the reference state. Defaults to None. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow. + + Returns: + Workflow + """ + # TODO: HOMO and LUMO of the neutral state as an approximation to IP and EA + fws = [] + fireworks_dict = {} + links_dict = {} + parents_dict = {} + working_dir = working_dir or os.getcwd() + mol = recursive_relative_to_absolute_path(mol, working_dir) + mol_object = deepcopy(mol) + + if ref_charge != opt_gaussian_inputs.get("charge", ref_charge): + raise Exception( + "The provided reference charge is not consistent with " + "the one found in the gaussian input parameters." + ) + + if states is None: + states = ["cation", "anion"] + if phases is None: + phases = ["gas", "solution"] + + for state in states: + assert states, "states list is empty" + if state.lower() not in ["cation", "anion"]: + raise ValueError( + "The provided states are not supported. Supported" + " ones are reference, cation, and/or anion." + ) + for phase in phases: + assert phases, "phases list is empty" + if phase.lower() not in ["gas", "solution"]: + raise ValueError( + "The provided phases are not supported. Supported" + " ones are gas and/or solution." + ) + + if pcet: + assert ( + h_index is not None + ), "index at which to attach hydrogen atom should be provided as input" + assert len(h_index) == num_electrons, ( + "number of indices at which to attach hydrogen atoms should be " + "consistent with number of transfer steps" + ) + + if ref_skips: + check_result = ["final_energy", "Gibbs Free Energy"] + else: + check_result = None + + if "solution" in phases and not solvent_gaussian_inputs: + solvent_gaussian_inputs = "(PCM, Solvent=Water)" + + if electrode_potentials: + electrode_potentials = { + k.lower(): {i.lower(): j for i, j in v.items()} + if isinstance(v, dict) + else v + for k, v in electrode_potentials.items() + } + + for k, v in electrode_potentials.items(): + if type(v) != dict or "potential" and "ref" not in v: + raise KeyError( + "Standard electrode potential dict should " + "contain potential and ref keys." + ) + electrode_potentials[k]["ref"] = bibtex_parser(v["ref"], working_dir) + + root_node = Node( + "reference", + "gas" if "gas" in phases else "solution", + 0, + mol_operation_type, + mol_object, + skips=ref_skips, + check_result=check_result, + ref_charge=ref_charge, + branch_cation_from_anion=pcet, + ) + solved_nodes = [] + active_nodes = Queue() + active_nodes.put(root_node) + while not active_nodes.empty(): + current_node = active_nodes.get() + current_node.create_fireworks( + opt_gaussian_inputs, + freq_gaussian_inputs, + solvent_gaussian_inputs, + solvent_properties, + working_dir, + db, + cart_coords, + pcet, + **kwargs, + ) + fws += current_node.fireworks + fireworks_dict[current_node.gout_key] = current_node.fireworks + if current_node.parent is not None: + links_dict[current_node.parent.fireworks[-1]] = links_dict.get( + current_node.parent.fireworks[-1], [] + ) + [current_node.fireworks[0]] + parents_dict[current_node.gout_key] = current_node.parent.gout_key + + if single_step: + addition_electrons = num_electrons + else: + addition_electrons = 1 + if ( + abs(current_node.added_e) <= num_electrons + or abs(current_node.added_h) <= num_electrons + ): + if "gas" in phases: + if current_node.phase == "solution": + # no branching is done on solution if gas is in the phases + branching_phases = [] + branching_states = [] + else: + branching_phases = ["solution"] + branching_states = deepcopy(states) + else: + branching_phases = [] + branching_states = deepcopy(states) + + if abs(current_node.added_e) == num_electrons: + if pcet and current_node.added_h < num_electrons: + branching_states = [i for i in branching_states if i == "cation"] + else: + branching_states = [] + if abs(current_node.added_h) == num_electrons: + branching_states = [] + + branching_phases = [i for i in branching_phases if i in phases] + children = current_node.branch( + branching_states, + branching_phases, + addition_electrons, + pcet, + h_index, + vertical, + ) + for child in children: + active_nodes.put(child) + solved_nodes.append(current_node) + + gout_keys = [i.gout_key for i in solved_nodes] + fw_analysis = Firework( + IPEAtoDB( + num_electrons=num_electrons, + states=states, + phases=phases, + steps="single" if single_step else "multi", + root_node_key=root_node.gout_key, + keys=gout_keys, + pcet=pcet, + vertical=vertical, + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + electrode_potentials=electrode_potentials, + gibbs_elec=gibbs_elec, + gibbs_h=gibbs_h, + db=db, + **{ + i: j + for i, j in kwargs.items() + if i in IPEAtoDB.required_params + IPEAtoDB.optional_params + }, + ), + parents=fws[:], + name="{}-{}".format(root_node.dir_head, "ip_ea_analysis"), + spec={"_launch_dir": os.path.join(working_dir, root_node.dir_head, "analysis")}, + ) + fws.append(fw_analysis) + + return Workflow( + fws, + name="{}_{}".format(root_node.dir_head, name), + links_dict=links_dict, + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS}, + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/gaussian/workflows/base/nmr.html b/html/_modules/mispr/gaussian/workflows/base/nmr.html new file mode 100644 index 00000000..ecb001f4 --- /dev/null +++ b/html/_modules/mispr/gaussian/workflows/base/nmr.html @@ -0,0 +1,918 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base.nmr - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.gaussian.workflows.base.nmr

+"""Define the nuclear magnetic resonance workflow."""
+
+import os
+import logging
+
+from fireworks import Firework, Workflow
+
+from mispr.gaussian.fireworks.core import CalcFromRunsDBFW
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.utilities.metadata import get_job_name
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+from mispr.gaussian.firetasks.parse_outputs import NMRtoDB
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Jan 2021"
+__version__ = "0.0.4"
+
+
+logger = logging.getLogger(__name__)
+
+
+
[docs]def get_nmr_tensors( + mol_operation_type, + mol, + db=None, + name="nmr_tensor_calculation", + working_dir=None, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + nmr_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=None, + **kwargs +): + """ + Define a workflow for calculating the nuclear magnetic resonance tensors. + + * **Firework 1**: Optimize the molecule. + * **Firework 2**: Calculate the frequencies. + * **Firework 3**: Calculate the NMR tensors. + * **Firework 4**: Create NMR document/json file. + + Args: + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): Name of the workflow. Defaults to "nmr_tensor_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. Defaults to the current + working directory. + opt_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters; + e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the frequency step; default parameters will be used if not specified. + nmr_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the NMR step; default parameters will be used if not specified. + solvent_gaussian_inputs (str, optional): Gaussian input parameters corresponding + to the implicit solvent model to be used in the NMR calculations, if any; + e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_gaussian_inputs``, etc.). Defaults to None. + solvent_properties (dict, optional): Additional input parameters to be used in + the NMR calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. Defaults to None. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``, otherwise uses z-matrix. Defaults to ``True``. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the molecule; e.g.: + {"Li":1, "O":-2}. Defaults to None. + skips (list, optional): List of jobs to skip; e.g.: ["opt", "freq"]; defaults + to None. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow. + + Returns: + Workflow + """ + fws = [] + working_dir = working_dir or os.getcwd() + mol = recursive_relative_to_absolute_path(mol, working_dir) + gout_keys = ["mol", "mol_nmr"] + + gaussian_inputs = handle_gaussian_inputs( + { + "opt": opt_gaussian_inputs, + "freq": freq_gaussian_inputs, + "nmr": nmr_gaussian_inputs, + }, + solvent_gaussian_inputs, + solvent_properties, + ) + opt_gaussian_inputs = gaussian_inputs["opt"] + freq_gaussian_inputs = gaussian_inputs["freq"] + nmr_gaussian_inputs = gaussian_inputs["nmr"] + + _, label, opt_freq_fws = common_fw( + mol_operation_type=mol_operation_type, + mol=mol, + working_dir=working_dir, + db=db, + opt_gaussian_inputs=opt_gaussian_inputs, + freq_gaussian_inputs=freq_gaussian_inputs, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=gout_keys[0], + skips=skips, + **kwargs + ) + fws += opt_freq_fws + + spec = kwargs.pop("spec", {}) + if not skips or len(skips) == 1 and skips[0].lower() == "opt": + spec.update( + {"proceed": {"has_gaussian_completed": True, "stationary_type": "Minimum"}} + ) + else: + spec.update({"proceed": {"has_gaussian_completed": True}}) + + nmr_fw = CalcFromRunsDBFW( + db, + input_file="{}_nmr.com".format(label), + output_file="{}_nmr.out".format(label), + name=get_job_name(label, "nmr"), + parents=fws[:], + gaussian_input_params=nmr_gaussian_inputs, + working_dir=os.path.join(working_dir, label, "NMR"), + cart_coords=cart_coords, + gout_key=gout_keys[1], + spec=spec, + **kwargs + ) + fws.append(nmr_fw) + + fw_analysis = Firework( + NMRtoDB( + db=db, + keys=gout_keys, + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + **{ + i: j + for i, j in kwargs.items() + if i in NMRtoDB.required_params + NMRtoDB.optional_params + } + ), + parents=fws[:], + name="{}-{}".format(label, "nmr_analysis"), + spec={"_launch_dir": os.path.join(working_dir, label, "analysis")}, + ) + fws.append(fw_analysis) + + return Workflow( + fws, + name=get_job_name(label, name), + **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/hybrid/firetasks/nmr_from_md.html b/html/_modules/mispr/hybrid/firetasks/nmr_from_md.html new file mode 100644 index 00000000..1e2a296f --- /dev/null +++ b/html/_modules/mispr/hybrid/firetasks/nmr_from_md.html @@ -0,0 +1,807 @@ + + + + + + + + + + + + + + + + mispr.hybrid.firetasks.nmr_from_md - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.hybrid.firetasks.nmr_from_md

+import os
+import ntpath
+import shutil
+
+from copy import deepcopy
+
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+
+from mispr.gaussian.workflows.base.nmr import get_nmr_tensors
+from mispr.gaussian.utilities.fw_utilities import run_fake_gaussian
+
+
+
[docs]@explicit_serialize +class NMRFromMD(FiretaskBase): + required_params = [] + optional_params = [ + "working_dir", + "db", + "opt_gaussian_inputs", + "freq_gaussian_inputs", + "nmr_gaussian_inputs", + "solvent_gaussian_inputs", + "solvent_properties", + "cart_coords", + "oxidation_states", + "additional_kwargs", + ] + +
[docs] def run_task(self, fw_spec): + nmr_wfs = [] + working_dir = self.get("working_dir", os.getcwd()) + additional_kwargs = self.get("additional_kwargs", {}) + for key in ["mol_name", "skips", "process_mol_func", "charge"]: + additional_kwargs.pop(key, None) + top_config_files = sorted(fw_spec.get("top_config_files")) + + # used only if running fake gaussian calculations + fake_gaussian_kwargs = additional_kwargs.get("fake_gaussian_kwargs", {}) + ref_dirs = fake_gaussian_kwargs.get("ref_dirs", []) + input_files = fake_gaussian_kwargs.get( + "input_files", ["mol.com"] * 3 * len(top_config_files) + ) + + for ind, file in enumerate(top_config_files): + config_file = ntpath.basename(file) + shutil.copy(file, f"{working_dir}/{config_file}") + nmr_wf = get_nmr_tensors( + mol_operation_type="get_from_file", + mol=config_file, + db=self.get("db"), + working_dir=working_dir, + opt_gaussian_inputs=deepcopy(self.get("opt_gaussian_inputs")), + freq_gaussian_inputs=deepcopy(self.get("freq_gaussian_inputs")), + nmr_gaussian_inputs=deepcopy(self.get("nmr_gaussian_inputs")), + solvent_gaussian_inputs=self.get("solvent_gaussian_inputs"), + solvent_properties=self.get("solvent_properties"), + cart_coords=self.get("cart_coords"), + oxidation_states=self.get("oxidation_states"), + skips=None, + process_mol_func=False, + mol_name=config_file.strip(".xyz"), + **additional_kwargs, + ) + + # added just for testing purposes + if fake_gaussian_kwargs: + nmr_wf = run_fake_gaussian( + nmr_wf, + ref_dirs=ref_dirs[ind * 3 : ind * 3 + 3], + input_files=input_files[ind * 3 : ind * 3 + 3], + tolerance=fake_gaussian_kwargs.get("tolerance"), + ) + nmr_wfs.append(nmr_wf) + return FWAction(detours=nmr_wfs)
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/hybrid/workflows/core.html b/html/_modules/mispr/hybrid/workflows/core.html new file mode 100644 index 00000000..553f0ce2 --- /dev/null +++ b/html/_modules/mispr/hybrid/workflows/core.html @@ -0,0 +1,897 @@ + + + + + + + + + + + + + + + + mispr.hybrid.workflows.core - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.hybrid.workflows.core

+"""Define the DFT-MD hybrid workflow."""
+
+import os
+
+from copy import deepcopy
+
+from fireworks import Workflow
+
+from mispr.lammps.workflows.base import lammps_workflow
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.utilities.inputs import handle_gaussian_inputs
+from mispr.gaussian.workflows.base.esp import get_esp_charges
+from mispr.gaussian.workflows.base.core import common_fw, WORKFLOW_KWARGS
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Oct 2021"
+__version__ = "0.0.4"
+
+
+
[docs]def run_hybrid_calcs( + mol_operation_type, + mol, + mol_type, + mol_data, + box_data, + ff_method=None, + ff_params=None, + mixture_type="number of molecules", + db=None, + name="hybrid_calculation", + working_dir=None, + opt_gaussian_inputs=None, + freq_gaussian_inputs=None, + esp_gaussian_inputs=None, + solvent_gaussian_inputs=None, + solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=None, + box_data_type="cubic", + data_file_name="data.mixture", + analysis_list=None, + analysis_settings=None, + **kwargs, +): + fws = [] + labels = [] + working_dir = working_dir or os.getcwd() + num_mols = len(mol) + gout_keys = [f"mol_{i}" for i in range(0, num_mols)] + if skips is None: + skips = [None] * num_mols + if not ff_method: + ff_method = ["get_from_esp"] * num_mols + ff_params = [] * num_mols + + mol = recursive_relative_to_absolute_path(mol, working_dir) + gaussian_inputs = handle_gaussian_inputs( + {"opt": deepcopy(opt_gaussian_inputs), "freq": deepcopy(freq_gaussian_inputs)}, + solvent_gaussian_inputs, + solvent_properties, + ) + opt_gins = gaussian_inputs["opt"] + freq_gins = gaussian_inputs["freq"] + + process_mol_func = kwargs.pop("process_mol_func", True) + kwargs.pop("dir_head", None) + kwargs.pop("dir_structure", None) + charges = kwargs.pop("charge", [0] * num_mols) + + # either perform geometry optimization and frequency calc for each molecule or + # the full esp workflow depending on the ff method for each method + for ind, [operation, molecule, key, skip, molecule_name, charge, ff] in enumerate( + zip( + mol_operation_type, + mol, + gout_keys, + skips, + kwargs.pop("mol_name", [None] * num_mols), + charges, + ff_method, + ) + ): + if ff == "get_from_esp": + esp_wf, label = get_esp_charges( + mol_operation_type=operation, + mol=molecule, + db=db, + working_dir=working_dir, + opt_gaussian_inputs=deepcopy(opt_gaussian_inputs), + freq_gaussian_inputs=deepcopy(freq_gaussian_inputs), + esp_gaussian_inputs=deepcopy(esp_gaussian_inputs), + solvent_gaussian_inputs=solvent_gaussian_inputs, + solvent_properties=solvent_properties, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + skips=skip, + mol_name=molecule_name, + charge=charge, + process_mol_func=process_mol_func, + gout_keys=[key, f"{key}_esp"], + **kwargs, + ) + ff_params[ind] = f"{working_dir}/{label}/ESP/{label}_esp" + fws += esp_wf.fws + else: + _, label, opt_freq_init_fws = common_fw( + mol_operation_type=operation, + mol=molecule, + db=db, + working_dir=working_dir, + opt_gaussian_inputs=opt_gins, + freq_gaussian_inputs=freq_gins, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + gout_key=key, + skips=skip, + mol_name=molecule_name, + charge=charge, + process_mol_func=process_mol_func, + **kwargs, + ) + fws += opt_freq_init_fws + labels.append(label) + + wf = Workflow( + fws, name=name, **{i: j for i, j in kwargs.items() if i in WORKFLOW_KWARGS} + ) + + # prepare the system_species_data dict in the format required by lammps_workflow + system_species_data = {} + for ind, label in enumerate(labels): + system_species_data[label] = { + "molecule": gout_keys[ind], + "molecule_operation_type": "get_from_run_dict", + "ff_param_method": ff_method[ind], + "ff_param_data": ff_params[ind], + "mol_mixture_type": mol_type[ind], + "mixture_data": mol_data[ind], + "save_ff_to_db": kwargs.get("save_ff_to_db", False), + "save_ff_to_file": kwargs.get("save_ff_to_file", True), + "charge": charges[ind], + } + + # add the lammps workflow + md_wf = lammps_workflow( + system_species_data=system_species_data, + system_mixture_type=mixture_type, + box_data=box_data, + box_data_type=box_data_type, + data_file_name=data_file_name, + db=db, + working_dir=working_dir, + analysis_list=analysis_list, + analysis_settings=analysis_settings, + name=name, + process_mol_func=False, + from_fw_spec=True, + **kwargs, + ) + wf.append_wf(md_wf, list(wf.id_fw.keys())) + return wf
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/hybrid/workflows/nmr.html b/html/_modules/mispr/hybrid/workflows/nmr.html new file mode 100644 index 00000000..0229073a --- /dev/null +++ b/html/_modules/mispr/hybrid/workflows/nmr.html @@ -0,0 +1,1049 @@ + + + + + + + + + + + + + + + + mispr.hybrid.workflows.nmr - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.hybrid.workflows.nmr

+"""Define the DFT-MD workflow that extracts solvation structures and computes their
+nuclear magnetic resonances."""
+
+import os
+
+from copy import deepcopy
+
+from fireworks import Firework, Workflow
+
+from mispr.hybrid.defaults import (
+    NMR_GAUSSIAN_INPUTS,
+    OPT_GAUSSIAN_INPUTS,
+    FREQ_GAUSSIAN_INPUTS,
+)
+from mispr.hybrid.workflows.core import run_hybrid_calcs
+from mispr.hybrid.firetasks.nmr_from_md import NMRFromMD
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Oct 2021"
+__version__ = "0.0.4"
+
+
+
[docs]def get_solvation_structures_nmr( + mol_operation_type, + mol, + mol_type, + mol_data, + box_data, + ff_method=None, + ff_params=None, + mixture_type="number of molecules", + db=None, + name="hybrid_calculation", + working_dir=None, + opt_esp_gaussian_inputs=None, + freq_esp_gaussian_inputs=None, + esp_gaussian_inputs=None, + opt_nmr_gaussian_inputs=None, + freq_nmr_gaussian_inputs=None, + nmr_gaussian_inputs=None, + esp_solvent_gaussian_inputs=None, + esp_solvent_properties=None, + nmr_solvent_gaussian_inputs=None, + nmr_solvent_properties=None, + cart_coords=True, + oxidation_states=None, + skips=None, + box_data_type="cubic", + data_file_name="data.mixture", + analysis_list=None, + analysis_settings=None, + **kwargs, +): + """ + Return a workflow to run hybrid DFT/MD calculations, extract categorize atomic + clusters around a particle of interest, and run the NMR calculations for the + clusters that have the highest frequency of occurrence in solution. + + Args: + mol_operation_type (list of str): Operation to perform for each molecule + composing the liquid solution in order to process the input structure + format. Length should correspond to the number of molecules/species + composing the liquid solution. Supported commands: + + 1. ``get_from_mol``: If the input is a pymatgen Molecule object. + 2. ``get_from_file``: If the input is any file format supported by Openabel + and pymatgen. + 3. ``get_from_gout_file``: If the input is a Gaussian output file. + 4. ``get_from_str``: If the input is a string. + 5. ``get_from_mol_db``: If the input is an InChI representation of the + molecule to be used to query the database. + 6. ``get_from_gout``: If the input is a pymatgen ``GaussianOutput`` object. + 7. ``get_from_run_dict``: If the input is a ``GaussianOutput`` dictionary. + 8. ``get_from_run_id``: If the input is a MongoDB document ID to be used to + query the database. + 9. ``get_from_run_query``: If the input is a dictionary with criteria to + search the database: e.g. + + .. code-block:: python + + {'inchi': inchi, + 'type': type, + 'functional': func, ...} + + 10. ``get_from_pubchem``: If the input is a common name for the molecule + to be used in searching the PubChem database. + 11. ``derive_molecule``: Used for deriving a molecule by attaching a + functional group at a site and the corresponding mol input should be a + dictionary, e.g. + + .. code-block:: python + + {'operation_type': <mol_operation_type for the base structure>, + 'mol': <base_mol>, + 'func_grp': func_group_name, ...} + + 12. ``link_molecules``: Used for linking two structures by forming a bond + at specific sites and the corresponding mol input should be a dictionary, + e.g. + + .. code-block:: python + + {'operation_type': ['get_from_file', 'get_from_mol_db'], + 'mol': ['mol1.xyz', 'mol_inchi'], + 'index': [3, 5], + 'bond_order': 1} + + mol (list): Sources of structures making up the liquid solution, e.g. file path + if ``mol_operation_type`` is specified as "get_from_file", InChI string if + ``mol_operation_type`` is specified as "get_from_mol_db", etc. + + .. important:: + + Order should match that in ``mol_operation_type``. + + mol_type (list of str): Type of each structure composing the liquid solution. + Supported types: "Solvents", "Solutes". Used for calculating the number of + molecules of each type if this information is not provided. + mol_data (list of int or list of dict): Format depends on ``mixture_type`` + input. If ``mixture_type`` is "number of molecules", ``mol_data`` should be + a list of the number of molecules of each type. If ``mixture_type`` is + "concentration", ``mol_data`` should be a list of dict, where each + dictionary should follow the format: + + .. code-block:: python + + {'Initial Molarity': molarity_i, + 'Final Molarity': molarity_f, + 'Density': density, + 'Molar Weight': molar_weight + } + + box_data (float, int, list (3,2), array (3,2), or LammpsBox): Definitions for + box size. See ``box_data_type`` for info how to define this parameter. + ff_method (list of str, optional): Operation to perform for each molecule + composing the liquid solution in order to process the force field parameters. + Can be "get_from_esp", "get_from_prmtop", "get_from_dict", "get_from_opls". + Defaults to "get_from_esp" for all molecules. + ff_params (list of str or dict, optional): Sources of the force field parameters + for each molecule type; type depends on what is specified in the + ``ff_method`` input; if "get_from_esp" is used, the corresponding + ``ff_param`` should be an empty dictionary since the path to the ESP file is + automatically detected from the ESP calculations that is performed at the + beginning of the workflow; if "get_from_prmtop" is used, the corresponding + ``ff_param`` should be the path to the prmtop file; if "get_from_dict" is + used, the corresponding ``ff_param`` should be a dictionary, e.g.: + + .. code-block:: python + + { + "Labels": ["mg"], + "Masses": OrderedDict({"mg": 24.305}), + "Nonbond": [[0.8947000005260684, 1.412252647723565]], + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([2.0]), + } + + If "get_from_opls" is used, the corresponding ``ff_param`` should be the + path to the molecule PDB file. + mixture_type (str, optional): "concentration" or "number of molecules"; + defaults to "number of molecules". + db (str or dict, optional): Database credentials; could be provided as the path + to the "db.json" file or in the form of a dictionary; if none is provided, + attempts to get it from the configuration files. + name (str, optional): Name of the workflow. Defaults to "hybrid_calculation". + working_dir (str, optional): Path of the working directory where any required + input files can be found and output will be created. + opt_esp_gaussian_inputs (dict, optional): Dictionary of Gaussian input + parameters for the optimization step of the ESP workflow; e.g.: + + .. code-block:: python + + { + "functional": "B3LYP", + "basis_set": "6-31G(d)", + "route_parameters": {"Opt": None}, + "link0_parameters": { + "%chk": "checkpoint.chk", + "%mem": "45GB", + "%NProcShared": "24"} + } + + The above default parameters will be used if not specified. + freq_esp_gaussian_inputs (dict, optional): Dictionary of Gaussian input + parameters for the frequency step of the ESP workflow; default parameters + will be used if not specified. + esp_gaussian_inputs (dict, optional): Sictionary of Gaussian input parameters + for the ESP step of the ESP workflow; default parameters will be used if not + specified. + opt_nmr_gaussian_inputs (dict, optioanl): Dictionary of Gaussian input + parameters for the optimization step of the NMR workflow; default parameters + will be used if not specified. + freq_nmr_gaussian_inputs (dict, optional): Dictionary of Gaussian input + parameters for the frequency step of the NMR workflow; default parameters + will be used if not specified. + nmr_gaussian_inputs (dict, optional): Dictionary of Gaussian input parameters + for the NMR step of the NMR workflow; default parameters will be used if not + specified. + esp_solvent_gaussian_inputs (str, optional): Gaussian input parameters + corresponding to the implicit solvent model to be used in the ESP + calculations, if any; e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_gaussian_inputs``, + ``freq_esp_gaussian_inputs``, etc.). + esp_solvent_properties (dict, optional): Additional input parameters to be used + in the ESP calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. + nmr_solvent_gaussian_inputs (str, optional): Gaussian input parameters + corresponding to the implicit solvent model to be used in the NMR + calculations, if any; e.g.: + + .. code-block:: python + + "(Solvent=TetraHydroFuran)" + + These parameters should only be specified here and not included in the main + gaussian_inputs dictionary for each job (i.e. ``opt_nmr_gaussian_inputs``, + ``freq_nmr_gaussian_inputs``, etc.). + nmr_solvent_properties (dict, optional): Additional input parameters to be used + in the NMR calculations and relevant to the solvent model, if any; e.g., + {"EPS":12}. + cart_coords (bool, optional): Uses cartesian coordinates in writing Gaussian + input files if set to ``True``, otherwise uses z-matrix. Defaults to ``True``. + oxidation_states (dict, optional): Dictionary of oxidation states that can be + used in setting the charge and spin multiplicity of the clusters extracted + from MD simulations to be used in the NMR workflow. + skips (list of lists, optional): Type of DFT calculation to skip in the ESP + workflow for each molecule; e.g. ["opt", "freq"], ["opt"], ["freq"], or []. + box_data_type (str, optional): Can be one of the following: "cubic", + "rectangular", or "LammpsBox". If "cubic", ``box_data`` must be a float or + int; if "rectangular", ``box_data`` must be an array-like with size (3,2); + if "LammpsBox", ``box_data`` must be a ``pymatgen.io.lammps.data.LammpsBox`` + object. Defaults to "cubic". + data_file_name (str, optional): Name of the LAMMPS data file to create and use; + defaults to "data.mixture". + analysis_list (list of str, optional): Type of MD analysis to perform after the + MD simulations are finished; e.g.: ["diffusion", "rdf", "cn", "clusters"] + if user wants to perform diffusion, RDF, coordination number, and cluster + analysis. + analysis_settings (list of dict, optional): Settings of the MD analysis steps; + please refer to the mdproptools documentation for details of inputs used in + the analysis functions; order of settings should correspond to the order + used in ``analysis_list``. + kwargs (keyword arguments): Additional kwargs to be passed to the workflow; e.g.: + lammps ``recipe`` and ``recipe_settings``; the defaults for these inputs are + specified in the ``mispr/lammps/defaults.py``. + + Returns: + Workflow + """ + if not working_dir: + working_dir = os.getcwd() + if not analysis_list: + analysis_list = [] + # analysis_list += ["diffusion", "rdf", "cn", "clusters"] + # analysis_list = list(set(analysis_list)) + + wf = run_hybrid_calcs( + mol_operation_type, + mol, + mol_type, + mol_data, + box_data, + ff_method, + ff_params, + mixture_type, + db, + name, + working_dir, + opt_esp_gaussian_inputs, + freq_esp_gaussian_inputs, + esp_gaussian_inputs, + esp_solvent_gaussian_inputs, + esp_solvent_properties, + cart_coords, + oxidation_states, + skips, + box_data_type, + data_file_name, + analysis_list, + analysis_settings, + **kwargs, + ) + + dft_md_fw_ids = list(wf.id_fw.keys()) + + nmr_dir = f"{working_dir}/nmr" + nmr_fw = Firework( + NMRFromMD( + db=db, + working_dir=nmr_dir, + opt_gaussian_inputs=opt_nmr_gaussian_inputs or OPT_GAUSSIAN_INPUTS, + freq_gaussian_inputs=freq_nmr_gaussian_inputs or FREQ_GAUSSIAN_INPUTS, + nmr_gaussian_inputs=nmr_gaussian_inputs or NMR_GAUSSIAN_INPUTS, + solvent_gaussian_inputs=nmr_solvent_gaussian_inputs, + solvent_properties=nmr_solvent_properties, + cart_coords=cart_coords, + oxidation_states=oxidation_states, + additional_kwargs=kwargs, + ), + name="nmr_calculation", + spec={"_launch_dir": nmr_dir}, + ) + wf.append_wf(Workflow.from_Firework(nmr_fw), dft_md_fw_ids[:-1]) + return wf
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/database.html b/html/_modules/mispr/lammps/database.html new file mode 100644 index 00000000..e6d783e7 --- /dev/null +++ b/html/_modules/mispr/lammps/database.html @@ -0,0 +1,990 @@ + + + + + + + + + + + + + + + + mispr.lammps.database - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.database

+# coding: utf-8
+
+# Defines classes for handling mongodb interactions.
+
+import sys
+import logging
+import datetime
+
+from abc import abstractmethod
+
+import pandas as pd
+
+from pymongo import ASCENDING, MongoClient
+from monty.serialization import loadfn
+
+from pymatgen.core.structure import Molecule
+from pymatgen.analysis.molecule_matcher import MoleculeMatcher
+
+from mispr.lammps.utilities.utilities import process_ff_doc
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+logger = logging.getLogger()
+ch = logging.StreamHandler(stream=sys.stdout)
+logger.addHandler(ch)
+logger.setLevel(20)
+
+
+
[docs]class LammpsSysDb: + def __init__( + self, + host, + port=None, + name=None, + username=None, + password=None, + uri_mode=False, + **kwargs, + ): + self.host = host + self.db_name = name + self.user = username + self.password = password + self.port = int(port) if port else None + try: + if uri_mode: + self.connection = MongoClient(host) + # parse URI to extract dbname + dbname = host.split("/")[-1].split("?")[0] + self.db = self.connection[dbname] + else: + self.connection = MongoClient( + self.host, + self.port, + ssl=kwargs.get("ssl", False), + ssl_ca_certs=kwargs.get("ssl_ca_certs"), + ssl_certfile=kwargs.get("ssl_certfile"), + ssl_keyfile=kwargs.get("ssl_keyfile"), + ssl_pem_passphrase=kwargs.get("ssl_pem_passphrase"), + username=username, + password=password, + authsource=kwargs.get("authsource"), + ) + self.db = self.connection[self.db_name] + except: + logger.error("Mongodb connection failed") + raise Exception + try: + if self.user: + self.db.authenticate( + self.user, self.password, source=kwargs.get("authsource", None) + ) + except: + logger.error("Mongodb authentication failed") + raise ValueError + self.force_fields = self.db["force_fields"] + self.systems = self.db["systems"] + self.runs = self.db["runs"] + + self.build_indexes() + +
[docs] @abstractmethod + def build_indexes(self, indexes=None, background=True): + self.force_fields.create_index( + [("smiles", ASCENDING), ("method", ASCENDING), ("doi", ASCENDING)], + unique=True, + background=background, + ) + self.systems.create_index( + [("smiles", ASCENDING), ("force_field_types", ASCENDING)], + unique=False, + background=background, + ) + self.runs.create_index( + [ + ("smiles", ASCENDING), + ("mixture_data", ASCENDING), + ("box", ASCENDING), + ("job_type", ASCENDING), + ], + unique=False, + background=background, + )
+ +
[docs] def query_force_fields(self, query): + projection = { + "smiles": 1, + "formula": 1, + "formula_pretty": 1, + "formula_anonymous": 1, + "formula_alphabetical": 1, + "chemsys": 1, + "nsites": 1, + "nelements": 1, + "is_ordered": 1, + "is_valid": 1, + "method": 1, + "doi": 1, + } + return pd.DataFrame(list(self.force_fields.find(query, projection)))
+ +
[docs] def insert_force_field( + self, parameter_dict, method, doi=None, update_duplicates=False, **kwargs + ): + ff_doc = process_ff_doc(parameter_dict, method, doi, **kwargs) + # mol = parameter_dict["Molecule"] + mol = Molecule.from_dict(ff_doc) + # Check if smiles is already in db + result = self.force_fields.find_one( + {"smiles": ff_doc["smiles"], "method": method, "doi": doi} + ) + if result: + logger.info( + f"Parameters for {ff_doc['smiles']} using {method} " + f"according to {doi} are already in database" + ) + # If smile is not in db, checks if the same molecule exists with a + # different smile representation + if result is None: + m = MoleculeMatcher() + result_list = list( + self.force_fields.find( + { + "formula_alphabetical": ff_doc["formula_alphabetical"], + "method": method, + "doi": doi, + } + ) + ) + if result_list: + logger.info( + f"Parameters for {ff_doc['smiles']} using " + f"{method} according to {doi} are already in " + f"{len(result_list)} documents" + ) + for i in result_list: + saved_mol = Molecule.from_dict(i) + if m.fit(saved_mol, mol): + result = i + ff_doc["smiles"] = i["smiles"] + break + # If update_duplicates is set to True, updates existing document with + # new geometry keeping the old smiles representation + if result and update_duplicates: + logger.info( + f"Updating duplicate parameters for " + f"{ff_doc['smiles']} using {method} according to " + f"{doi}" + ) + if result is None or update_duplicates: + ff_doc.update(parameter_dict) + ff_doc["method"] = method + ff_doc["doi"] = doi + ff_doc["last_updated"] = datetime.datetime.utcnow() + self.force_fields.update_one( + {"smiles": ff_doc["smiles"], "method": method, "doi": doi}, + {"$set": ff_doc}, + upsert=True, + ) + return ff_doc["smiles"] + else: + logger.info( + f"Skipping duplicate parameters for " + f"{ff_doc['smiles']} using {method} according to " + f"{doi}" + ) + return ff_doc["smiles"], method, doi
+ +
[docs] def retrieve_force_field(self, smiles, method, doi=None): + return self.force_fields.find_one( + {"smiles": smiles, "method": method, "doi": doi} + )
+ +
[docs] def delete_force_field(self, smiles, method, doi=None): + return self.force_fields.delete_one( + {"smiles": smiles, "method": method, "doi": doi} + )
+ +
[docs] def insert_run(self, lmp_run): + # TODO: perform checks if a similar calculation is already in the db + if "_id" in lmp_run: + stored_run = self.retrieve_run(_id=lmp_run["_id"]) + if stored_run: + return lmp_run["_id"] + lmp_run["last_updated"] = datetime.datetime.utcnow() + result = self.runs.insert_one(lmp_run, bypass_document_validation=True) + return result.inserted_id
+ +
[docs] def retrieve_run(self, _id): + return self.runs.find_one({"_id": _id})
+ +
[docs] def insert_system(self, sys_doc): + sys_doc["last_updated"] = datetime.datetime.utcnow() + result = self.systems.insert_one(sys_doc, bypass_document_validation=True) + return result.inserted_id
+ +
[docs] @classmethod + def from_db_file(cls, db_file, admin=True): + # TODO: move this to a common database module (common with Gaussian) + creds = loadfn(db_file) + + if admin and "admin_user" not in creds and "readonly_user" in creds: + raise ValueError( + "Trying to use admin credentials, " + "but no admin credentials are defined. " + "Use admin=False if only read_only " + "credentials are available." + ) + + if admin: + user = creds.get("admin_user") + password = creds.get("admin_password") + else: + user = creds.get("readonly_user") + password = creds.get("readonly_password") + + kwargs = creds.get( + "mongoclient_kwargs", {} + ) # any other MongoClient kwargs can go here ... + + if "authsource" in creds: + kwargs["authsource"] = creds["authsource"] + else: + kwargs["authsource"] = creds["database"] + + return cls( + creds["host"], + int(creds.get("port", 27017)), + creds["database"], + user, + password, + **kwargs, + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/firetasks/parse_outputs.html b/html/_modules/mispr/lammps/firetasks/parse_outputs.html new file mode 100644 index 00000000..3f0bc4d3 --- /dev/null +++ b/html/_modules/mispr/lammps/firetasks/parse_outputs.html @@ -0,0 +1,1583 @@ + + + + + + + + + + + + + + + + mispr.lammps.firetasks.parse_outputs - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.firetasks.parse_outputs

+# coding: utf-8
+
+
+# Defines firetasks for reading output of Ambertools programs and LAMMPS.
+
+import os
+import json
+import inspect
+import logging
+
+import numpy as np
+import pandas as pd
+
+from scipy.signal import argrelmin, find_peaks
+
+from pymatgen.io.ambertools import PrmtopParser
+from pymatgen.core.structure import Molecule
+
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+from fireworks.utilities.fw_serializers import DATETIME_HANDLER
+
+from mdproptools.structural.rdf_cn import (
+    calc_atomic_cn,
+    calc_atomic_rdf,
+    calc_molecular_cn,
+    calc_molecular_rdf,
+)
+from mdproptools.dynamical.diffusion import Diffusion
+from mdproptools.structural.cluster_analysis import (
+    get_clusters,
+    get_unique_configurations,
+)
+
+from mispr.lammps.defaults import (
+    CN_SETTINGS,
+    MSD_SETTINGS,
+    RDF_SETTINGS,
+    DIFF_SETTINGS,
+    CLUSTERS_SETTINGS,
+)
+from mispr.lammps.utilities.utilities import (
+    get_db,
+    process_ff_doc,
+    add_ff_labels_to_dict,
+)
+from mispr.gaussian.utilities.metadata import get_mol_formula
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+GAFF_DOI = "https://doi.org/10.1002/jcc.20035"
+
+
+
[docs]@explicit_serialize +class ProcessPrmtop(FiretaskBase): + """ + Parse the prmtop file to extract force field parameters and saves them to a file + and/or database in the format required by the ``LammpsDataWrapper`` class in the + ``pymatgen.io.lammps.data`` module. + + Args: + molecule (Molecule, optional): A pymatgen ``Molecule`` object of the molecule. + The order of the atoms in the ``Molecule`` object should match the order + of the atoms used when generating the prmtop file. If not provided, the + molecule will be read from the previous calculation in the ``fw_spec``. + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + db (str, optional): The connection information of the database to save the + force field parameters to. If not provided, the connection information will + be read from the db.json file. + prmtop_path (str, optional): Path to the prmtop file. If not provided, will try + to get the path based on the ``prmtop_filename`` and ``prmtop_dir``. + prmtop_filename (str, optional): Name of the prmtop file. Only read if the + ``prmtop_path`` is not provided. + prmtop_dir (str, optional): Path to the directory containing the prmtop file. + Only read if the ``prmtop_path`` is not provided. Defaults to ``working_dir``. + unique_molecule_name (str, optional): A unique name for the molecule. If not + provided, the formula of the molecule will be used. + system_force_field_dict (dict, optional): A dictionary containing the force + field parameters for the system. Will be used as input for + ``LammpsDataWrapper``. Only read if this dict is not already in the + ``fw_spec``. Will be saved to the ``fw_spec`` after processing the prmtop + file. Defaults to an empty dict. + doi (str, optional): Digital Object Identifier for the force field used. + Defaults to the GAFF DOI. + save_ff_to_db (bool, optional): Whether to save the force field parameters to + the database. Defaults to ``False``. + save_ff_to_file (bool, optional): Whether to save the force field parameters to + a file in the working_dir. Defaults to ``True``. + ff_filename (str, optional): Name of the file to save the force field parameters + to. Defaults to "ff.json". + """ + _fw_name = "Process Prmtop" + required_params = [] + optional_params = [ + "molecule", + "working_dir", + "db", + "prmtop_path", + "prmtop_filename", + "prmtop_dir", + "unique_molecule_name", + "system_force_field_dict", + "doi", + "save_ff_to_db", + "save_ff_to_file", + "ff_filename", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + db = self.get("db", None) + ff_filename = self.get("ff_filename", "ff.json") + save_to_db = self.get("save_ff_to_db", False) + save_to_file = self.get("save_ff_to_file", True) + + if isinstance(self.get("prmtop_path"), str): + prmtop_file_path = self.get("prmtop_path") + + elif isinstance(self.get("prmtop_filename"), str): + prmtop_filename = self.get("prmtop_filename") + prmtop_dir = self.get("prmtop_dir", working_dir) + prmtop_file_path = os.path.join(prmtop_dir, prmtop_filename) + + else: + raise Exception( + 'Neither name nor path to a prmtop file was \ + provided; either provide prmtop file name as \ + "prmtop_filename" or path to prmtop as \ + "prmtop_path".' + ) + + if not os.path.exists(prmtop_file_path): + raise Exception( + '"prmtop_file_path" is not a valid path; check \ + that "prmtop_path" is correct or that \ + "prmtop_filename" exists in "prmtop_dir"' + ) + + molecule = self.get("molecule", fw_spec["prev_calc_molecule"]) + + if not isinstance(molecule, Molecule): + raise Exception('"molecule" is not a pymatgen Molecule object') + + # TODO: decide what unique id for the ff labels. If staying as smiles \ + # string, decide how to get smiles. + unique_mol_name = self.get("unique_molecule_name", get_mol_formula(molecule)) + ff_param_dict_general = PrmtopParser(prmtop_file_path, molecule, "").to_dict() + ff_param_dict_system = add_ff_labels_to_dict( + ff_param_dict_general, unique_mol_name + ) + + gaff_doi = self.get("gaff_doi", GAFF_DOI) + + if save_to_db: + ff_doc = ff_param_dict_general.copy() + ff_db = get_db(input_db=db) + ff_db.insert_force_field(ff_doc, "gaff", doi=gaff_doi) + + if save_to_file: + ff_doc = process_ff_doc(ff_param_dict_general, "gaff", doi=gaff_doi) + with open(os.path.join(working_dir, ff_filename), "w") as file: + json.dump(ff_doc, file) + + sys_ff_dict = fw_spec.get( + "system_force_field_dict", self.get("system_force_field_dict", {}) + ) + sys_ff_dict[unique_mol_name] = ff_param_dict_system + + return FWAction( + stored_data={ + "ff_param_dict_system": ff_param_dict_system, + "ff_param_dict_general": ff_param_dict_general, + }, + update_spec={"system_force_field_dict": sys_ff_dict}, + propagate=True, + )
+ + +
[docs]@explicit_serialize +class CalcDiff(FiretaskBase): + """ + Calculate the diffusion coefficient of a system using the mean squared displacement + (MSD) method. The MSD is either calculated from the trajectory dump files or read + from the log file. The diffusion coefficient is then calculated from the MSD using + the Einstein relation. + + Args: + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + diff_settings (dict, optional): A dictionary containing the settings for the + diffusion calculation based on the ``Diffusion`` object. Refer to the + ``mdproptools.dynamical.diffusion`` module for more information. The + dictionary might contain the following keys: + + * timestep (float): The timestep used in the simulation. + * units (str): The unit type used in the LAMMPS simulations. + * msd_method (str): The method used to calculate the MSD. Supported methods + are "from_dump" and "from_log". + * num_mols (list, optional): A list containing the number of molecules of + each type in the system. Required if the ``msd_method`` is "from_dump". + * num_atoms_per_mol (list, optional): A list containing the number of atoms + in each molecule. Required if the ``msd_method`` is "from_dump". + * mass (list, optional): A list containing the masses of each LAMMPS atom + type in the system. Required if the ``msd_method`` is "from_dump". + * file_pattern (str, optional): The pattern used to match the dump files. + Defaults to "dump.nvt.*.dump" if calculating from dump and "log.lammps*" + if calculating from log. + * avg_interval (bool, optional): Whether to calculate the MSD for individual + particles or not. If False, the MSD will be averaged for each particle + type. Defaults to ``False``. Only used if the ``msd_method`` is "from_dump". + * diff_dist (bool, optional): Whether to calculate the diffusion distribution. + Defaults to ``False``. Only used if the ``msd_method`` is "from_dump". + * outputs_dir (str, optional): Path to the directory containing the dump + files. Defaults to "working_dir/../../nvt". + """ + _fw_name = "Calculate Diffusion" + required_params = [] + optional_params = ["working_dir", "diff_settings"] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.makedirs(working_dir, exist_ok=True) + diff_settings = {**MSD_SETTINGS.copy(), **DIFF_SETTINGS.copy()} + diff_settings.update(self.get("diff_settings", {})) + msd_method = diff_settings["msd_method"] + outputs_dir = diff_settings.get( + "outputs_dir", os.path.abspath(os.path.join(working_dir, "..", "..", "nvt")) + ) + msd_df = None + diff = Diffusion( + timestep=diff_settings["timestep"], + units=diff_settings["units"], + outputs_dir=outputs_dir, + diff_dir=working_dir, + ) + if msd_method == "from_dump": + num_mols = diff_settings.pop("num_mols", fw_spec.get("num_mols_list", [])) + num_atoms_per_mol = diff_settings.pop( + "num_atoms_per_mol", fw_spec.get("num_atoms_per_mol", []) + ) + num_mols = [int(i) for i in num_mols] if num_mols else None + mass = fw_spec.get("default_masses", None) + file_pattern = diff_settings.pop("file_pattern", "dump.nvt.*.dump") + + msd_df = diff.get_msd_from_dump( + file_pattern, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + mass=mass, + **{ + i: j + for i, j in diff_settings.items() + if i in inspect.getfullargspec(diff.get_msd_from_dump).args + }, + ) + elif msd_method == "from_log": + file_pattern = diff_settings.get("file_pattern", "log.lammps*") + msd_df = diff.get_msd_from_log(file_pattern) + + else: + raise ValueError( + f"Unsupported msd calculation method: {msd_method}" + f"Supported methods are from_dump and from_log" + ) + + diffusion = diff.calc_diff( + msd_df[0], + **{ + i: j + for i, j in diff_settings.items() + if i in inspect.getfullargspec(diff.calc_diff).args + }, + ) + + diff_list = diffusion["diffusion (m2/s)"].to_list() + std_list = diffusion["std"].to_list() + r2_list = diffusion["R2"].to_list() + + if ( + msd_method == "from_dump" + and diff_settings["avg_interval"] + and diff_settings["diff_dist"] + ): + diff.get_diff_dist( + msd_df[2], + **{ + i: j + for i, j in diff_settings.items() + if i in inspect.getfullargspec(diff.get_diff_dist).args + }, + ) + + diff_settings.update( + { + "diff_path": working_dir, + "diffusion": diff_list, + "std": std_list, + "r2": r2_list, + } + ) + return FWAction( + update_spec={ + "smiles": fw_spec.get("smiles", []), + "nmols": fw_spec.get("nmols", {}), + "num_mols_list": fw_spec.get("num_mols_list", []), + "box": fw_spec.get("box", None), + "num_atoms_per_mol": fw_spec.get("num_atoms_per_mol", []), + "default_masses": fw_spec.get("default_masses", []), + "recalc_masses": fw_spec.get("recalc_masses", []), + "diffusion": diff_settings, + } + )
+ + +
[docs]@explicit_serialize +class GetRDF(FiretaskBase): + """ + Calculate the radial distribution function (RDF) of a system. The RDF is calculated + for each atom type in the system and saved to a file. The RDF can be calculated for + atomic or molecular systems. + + Args: + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + rdf_settings (dict, optional): A dictionary containing the settings for the + RDF calculation based on the ``calc_atomic_rdf`` and ``calc_molecular_rdf`` + functions. Refer to the ``mdproptools.structural.rdf_cn`` module for more + information. + """ + _fw_name = "Get RDF" + required_params = [] + optional_params = ["rdf_settings", "working_dir"] + +
[docs] def run_task(self, fw_spec): + # Get inputs to rdf function from defaults or from user, which then + # updates the defaults + rdf_settings = RDF_SETTINGS.copy() + rdf_settings.update(self.get("rdf_settings", {})) + + # atomic or molecular (for CoM) + rdf_type = rdf_settings.get("rdf_type", "atomic") + + working_dir = self.get("working_dir", os.getcwd()) + os.makedirs(working_dir, exist_ok=True) + + use_default_atom_ids = rdf_settings.get("use_default_atom_ids", False) + + csv_filename = rdf_settings.get("path_or_buff", "rdf.csv") + csv_file_path = os.path.join(working_dir, csv_filename) + rdf_settings.update({"path_or_buff": csv_file_path}) + + r_cut = rdf_settings.get("r_cut") + + bin_size = rdf_settings.get("bin_size") + if isinstance(bin_size, (float, int)): + bin_size = [bin_size] + elif not isinstance(bin_size, (list, tuple)): + pass + mass = rdf_settings.get("mass", fw_spec.get("default_masses", [])) + if not mass: + raise ValueError("Atomic masses not found") + num_types = len(mass) + num_mols = rdf_settings.get("num_mols", fw_spec.get("num_mols_list", [])) + num_atoms_per_mol = rdf_settings.get( + "num_atoms_per_mol", fw_spec.get("num_atoms_per_mol", []) + ) + partial_relations = rdf_settings.get("partial_relations", None) + filename = rdf_settings.get("filename") + save_mode = rdf_settings.get("save_mode") + + if rdf_type == "atomic": + if use_default_atom_ids: + num_mols = None + num_atoms_per_mol = None + if not partial_relations: + partial_relations = [[], []] + for i in range(1, num_types + 1): + for j in range(1, i + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + else: + mass = fw_spec.get("recalc_masses", []) + if not num_mols or not num_atoms_per_mol: + raise ValueError( + "Number of molecules of each type and number of atoms " + "per molecule are not found" + ) + num_mols = [int(i) for i in num_mols] + if not partial_relations: + partial_relations = [[], []] + for i in range(1, np.sum(num_atoms_per_mol) + 1): + for j in range(1, i + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + atomic_working_dir = os.path.join(working_dir, rdf_type) + os.makedirs(atomic_working_dir, exist_ok=True) + for i, size in enumerate(bin_size): + cur_working_dir = os.path.join(atomic_working_dir, str(size)) + os.makedirs(cur_working_dir, exist_ok=True) + csv_file_path = os.path.join(cur_working_dir, csv_filename) + calc_atomic_rdf( + r_cut, + size, + num_types, + mass, + partial_relations, + filename, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + path_or_buff=csv_file_path, + save_mode=save_mode, + ) + + elif rdf_type == "molecular": + if not num_mols or not num_atoms_per_mol: + raise ValueError( + "Number of molecules of each type and number of atoms " + "per molecule are not found" + ) + num_mols = [int(i) for i in num_mols] + if not partial_relations: + partial_relations = [[], []] + for i in range(1, num_types + 1): + for j in range(1, len(num_atoms_per_mol) + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + molecular_working_dir = os.path.join(working_dir, rdf_type) + os.makedirs(molecular_working_dir, exist_ok=True) + for i, size in enumerate(bin_size): + cur_working_dir = os.path.join(molecular_working_dir, str(size)) + os.makedirs(cur_working_dir, exist_ok=True) + csv_file_path = os.path.join(cur_working_dir, csv_filename) + calc_molecular_rdf( + r_cut, + size, + num_types, + mass, + partial_relations, + filename, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + path_or_buff=csv_file_path, + save_mode=save_mode, + ) + + rdf_settings_spec = { + "r_cut": r_cut, + "bin_size": bin_size, + "num_types": num_types, + "mass": mass, + "partial_relations": partial_relations, + "filename": filename, + "num_mols": num_mols, + "num_atoms_per_mol": num_atoms_per_mol, + "path_or_buff": csv_filename, + "save_mode": save_mode, + "rdf_type": rdf_type, + "rdf_use_default_atom_ids": use_default_atom_ids, + "rdf_path": csv_file_path, + } + + return FWAction( + update_spec={ + "smiles": fw_spec.get("smiles", []), + "nmols": fw_spec.get("nmols", {}), + "num_mols_list": num_mols, + "num_atoms_per_mol": num_atoms_per_mol, + "masses": mass, + "box": fw_spec.get("box", None), + "rdf": rdf_settings_spec, + } + )
+ + +
[docs]@explicit_serialize +class CalcCN(FiretaskBase): + """ + Calculate the coordination number (CN) of a system. The CN is calculated for each + atom type in the system and saved to a file. The CN can be calculated for atomic or + molecular systems. + + Args: + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + cn_settings (dict, optional): A dictionary containing the settings for the CN + calculation based on the ``calc_atomic_cn`` and ``calc_molecular_cn`` + functions. Refer to the ``mdproptools.structural.rdf_cn`` module for more + information. + """ + _fw_name = "Calculate CN" + required_params = [] + optional_params = ["cn_settings", "working_dir"] + +
[docs] def run_task(self, fw_spec): + # Get inputs to cn function from defaults or from user, which then + # updates the defaults + cn = None + cn_settings = CN_SETTINGS.copy() + cn_settings.update(self.get("cn_settings", {})) + + # atomic or molecular (for CoM) + cn_type = cn_settings.get("cn_type", "atomic") + + working_dir = self.get("working_dir", os.getcwd()) + os.makedirs(working_dir, exist_ok=True) + + use_default_atom_ids = cn_settings.get("use_default_atom_ids", False) + + csv_filename = cn_settings.get("path_or_buff", "cn.csv") + csv_file_path = os.path.join(working_dir, csv_filename) + cn_settings.update({"path_or_buff": csv_file_path}) + + # check if user provided the cutoff radius to use in calculating the CN + r_cut = cn_settings.get("r_cut", None) + # if the cutoff radius is not provided, attempt to automatically detect it from + # the rdf + if not r_cut: + rdf_path = fw_spec.get("rdf", {}).get("rdf_path") + rdf_type = fw_spec.get("rdf", {}).get("rdf_type") + rdf_use_default_atom_ids = fw_spec.get("rdf", {}).get( + "rdf_use_default_atom_ids" + ) + if not rdf_path: + raise ValueError( + "Cutoff distance required for calculating the CN is " + "not found and cannot be computed due to a missing " + "RDF file" + ) + else: + if ( + cn_type != rdf_type + or use_default_atom_ids != rdf_use_default_atom_ids + ): + raise ValueError("CN settings do not match those of RDF") + else: + r_cut = [] + rdf_df = pd.read_csv(rdf_path) + for col in rdf_df: + if col != "r ($\AA$)" and col != "g_full(r)": + new_df = rdf_df[["r ($\AA$)", col]] + new_df.columns = ["x", "y"] + peaks = find_peaks(new_df["y"], height=1)[0] + minima = argrelmin(new_df["y"].values)[0] + min_3 = new_df.loc[minima[minima > peaks[0]][0:3]] + r_cut.append(np.mean(min_3["x"].tolist())) + + bin_size = cn_settings.get("bin_size") + if isinstance(bin_size, (float, int)): + bin_size = [bin_size] + elif not isinstance(bin_size, (list, tuple)): + pass + mass = cn_settings.get("mass", fw_spec.get("default_masses", [])) + if not mass: + raise ValueError("Atomic masses not found") + num_types = len(mass) + num_mols = cn_settings.get("num_mols", fw_spec.get("num_mols_list", [])) + num_atoms_per_mol = cn_settings.get( + "num_atoms_per_mol", fw_spec.get("num_atoms_per_mol", []) + ) + partial_relations = cn_settings.get("partial_relations", None) + filename = cn_settings.get("filename") + save_mode = cn_settings.get("save_mode") + + if cn_type == "atomic": + if use_default_atom_ids: + num_mols = None + num_atoms_per_mol = None + if not partial_relations: + partial_relations = [[], []] + for i in range(1, num_types + 1): + for j in range(1, i + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + else: + mass = fw_spec.get("recalc_masses", []) + if not num_mols or not num_atoms_per_mol: + raise ValueError( + "Number of molecules of each type and number of atoms " + "per molecule are not found" + ) + num_mols = [int(i) for i in num_mols] + if not partial_relations: + partial_relations = [[], []] + for i in range(1, np.sum(num_atoms_per_mol) + 1): + for j in range(1, i + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + atomic_working_dir = os.path.join(working_dir, cn_type) + os.makedirs(atomic_working_dir, exist_ok=True) + for i, size in enumerate(bin_size): + cur_working_dir = os.path.join(atomic_working_dir, str(size)) + os.makedirs(cur_working_dir, exist_ok=True) + csv_file_path = os.path.join(cur_working_dir, csv_filename) + cn = calc_atomic_cn( + r_cut, + size, + num_types, + mass, + partial_relations, + filename, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + path_or_buff=csv_file_path, + save_mode=save_mode, + ) + + elif cn_type == "molecular": + if not num_mols or not num_atoms_per_mol: + raise ValueError( + "Number of molecules of each type and number of atoms " + "per molecule are not found" + ) + num_mols = [int(i) for i in num_mols] + if not partial_relations: + partial_relations = [[], []] + for i in range(1, num_types + 1): + for j in range(1, len(num_atoms_per_mol) + 1): + partial_relations[0].append(i) + partial_relations[1].append(j) + molecular_working_dir = os.path.join(working_dir, cn_type) + os.makedirs(molecular_working_dir, exist_ok=True) + for i, size in enumerate(bin_size): + cur_working_dir = os.path.join(molecular_working_dir, str(size)) + os.makedirs(cur_working_dir, exist_ok=True) + csv_file_path = os.path.join(cur_working_dir, csv_filename) + cn = calc_molecular_cn( + r_cut, + size, + num_types, + mass, + partial_relations, + filename, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + path_or_buff=csv_file_path, + save_mode=save_mode, + ) + + cn_settings_spec = { + "r_cut": r_cut, + "bin_size": bin_size, + "num_types": num_types, + "mass": mass, + "partial_relations": partial_relations, + "filename": filename, + "num_mols": num_mols, + "num_atoms_per_mol": num_atoms_per_mol, + "path_or_buff": csv_filename, + "save_mode": save_mode, + "cn_type": cn_type, + "cn_use_default_atom_ids": use_default_atom_ids, + "cn_path": csv_file_path, + "cn": cn.loc[0].to_dict(), + } + + return FWAction( + update_spec={ + "smiles": fw_spec.get("smiles", []), + "nmols": fw_spec.get("nmols", {}), + "num_mols_list": num_mols, + "num_atoms_per_mol": num_atoms_per_mol, + "masses": mass, + "box": fw_spec.get("box", None), + "cn": cn_settings_spec, + } + )
+ + +
[docs]@explicit_serialize +class ExtractClusters(FiretaskBase): + """ + Extract atomic clusters from a trajectory file. The clusters are extracted based + on the cutoff radius and saved to separate files. The clusters can be extracted + from the full trajectory or a single frame. + + Args: + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + cluster_settings (dict, optional): A dictionary containing the settings for the + cluster extraction based on the ``get_clusters`` and + ``get_unique_configurations`` functions. Refer to the + ``mdproptools.structural.cluster_analysis`` module for more information. + """ + _fw_name = "Extract Atomic Clusters" + required_params = [] + optional_params = ["cluster_settings", "working_dir"] + +
[docs] def run_task(self, fw_spec): + cluster_settings = CLUSTERS_SETTINGS.copy() + cluster_settings.update(self.get("cluster_settings", {})) + working_dir = self.get("working_dir", os.getcwd()) + os.makedirs(working_dir, exist_ok=True) + filename = cluster_settings.get("filename") + atom_type = cluster_settings.get("atom_type") + if not atom_type: + raise ValueError("No atom type specified to perform cluster analysis") + num_mols = cluster_settings.get("num_mols", fw_spec.get("num_mols_list", [])) + num_mols = [int(i) for i in num_mols] + num_atoms_per_mol = cluster_settings.get( + "num_atoms_per_mol", fw_spec.get("num_atoms_per_mol", []) + ) + # TODO: get elements from fw_spec + elements = cluster_settings.get("elements", None) + prev_rcut = fw_spec.get("cn", {}).get("r_cut") + cur_rcut = min(prev_rcut) if prev_rcut else None + r_cut = cluster_settings.get("r_cut", cur_rcut) + full_trajectory = cluster_settings.get("full_trajectory", True) + frame = cluster_settings.get("frame", None) + alter_atom_ids = cluster_settings.get("alter_atom_ids", False) + max_force = cluster_settings.get("max_force", 0.75) + cluster_count = get_clusters( + filename=filename, + atom_type=atom_type, + r_cut=r_cut, + full_trajectory=full_trajectory, + frame=frame, + num_mols=num_mols, + num_atoms_per_mol=num_atoms_per_mol, + elements=elements, + alter_atom_ids=alter_atom_ids, + max_force=max_force, + working_dir=working_dir, + ) + + # TODO: if molecules are taken from fw_spec, need to make sure if mol_names + # are provided they match the order in fw_spec (which is sorted by the + # num_atoms/mol) + type_coord_atoms = cluster_settings.get("type_coord_atoms", None) + perc = cluster_settings.get("perc", None) + cum_perc = cluster_settings.get("cum_perc", 90) + clusters, configurations = get_unique_configurations( + cluster_pattern="Cluster_*", + r_cut=r_cut, + molecules=cluster_settings.get("molecules", fw_spec.get("molecules")), + type_coord_atoms=type_coord_atoms, + working_dir=working_dir, + find_top=cluster_settings.get("find_top", True), + perc=perc, + cum_perc=cum_perc, + mol_names=cluster_settings.get("mol_names", None), + zip=cluster_settings.get("zip", True), + ) + top_config_files = [ + f"{working_dir}/{file}" + for file in os.listdir(working_dir) + if file.startswith("conf_") and file.endswith(".xyz") + ] + + cluster_analysis_spec = { + "atom_type": atom_type, + "r_cut": r_cut, + "full_trajectory": full_trajectory, + "frame": frame, + "num_mols": num_mols, + "num_atoms_per_mol": num_atoms_per_mol, + "elements": elements, + "alter_atom_ids": alter_atom_ids, + "max_force": max_force, + "num_clusters": cluster_count, + "num_configurations": len(configurations), + "type_coord_atoms": type_coord_atoms, + "perc": perc, + "cum_perc": cum_perc, + "filename": filename, + "working_dir": working_dir, + } + + return FWAction( + update_spec={ + "clusters": cluster_analysis_spec, + "top_config_files": top_config_files, + } + )
+ + +
[docs]@explicit_serialize +class ProcessAnalysis(FiretaskBase): + """ + Process the analysis calculations and saves the results to the database and/or a file. + + Args: + analysis_list (list): A list of the analysis calculations to process. Supported + analysis calculations are "diffusion", "rdf", "cn", and "clusters". + db (str, optional): The connection information of the database to save the + analysis results to. If not provided, the connection information will be + read from the db.json file. + save_analysis_to_db (bool, optional): Whether to save the analysis results to + the database. Defaults to ``False``. + save_analysis_to_file (bool, optional): Whether to save the analysis results to + a file in the working_dir. Defaults to ``True``. + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + """ + _fw_name = "Process Analysis Calculations" + required_params = ["analysis_list"] + optional_params = [ + "db", + "save_analysis_to_db", + "save_analysis_to_file", + "working_dir", + ] + +
[docs] def run_task(self, fw_spec): + db = self.get("db", None) + working_dir = self.get("working_dir", fw_spec.get("working_dir", os.getcwd())) + save_analysis_to_db = self.get("save_analysis_to_db", False) + save_analysis_to_file = self.get("save_analysis_to_file", True) + + box = fw_spec.get("box", None) + if box: + box = box.as_dict() + + systems_dict = { + "smiles": fw_spec.get("smiles", []), + "nmols": fw_spec.get("num_mols_list", []), + "natoms_per_mol": fw_spec.get("num_atoms_per_mol", []), + "mass": fw_spec.get("masses", []), + "box": box, + } + + for analysis in self["analysis_list"]: + systems_dict[analysis] = fw_spec.get(analysis) + + if fw_spec.get("run_id_list"): + systems_dict["run_ids"] = fw_spec["run_id_list"] + + if save_analysis_to_db: + db = get_db(input_db=db) + db.insert_system(systems_dict) + + if fw_spec.get("lammps_run_loc_list"): + systems_dict["lammps_run_locs"] = fw_spec["lammps_run_loc_list"] + + if save_analysis_to_file: + if "lammps_run_ids" in systems_dict: + del systems_dict["lammps_run_ids"] + file = os.path.join(working_dir, "system.json") + with open(file, "w") as f: + f.write(json.dumps(systems_dict, default=DATETIME_HANDLER)) + + logger.info("Analysis calculations complete")
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/firetasks/run.html b/html/_modules/mispr/lammps/firetasks/run.html new file mode 100644 index 00000000..b212432f --- /dev/null +++ b/html/_modules/mispr/lammps/firetasks/run.html @@ -0,0 +1,1186 @@ + + + + + + + + + + + + + + + + mispr.lammps.firetasks.run - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.firetasks.run

+# coding: utf-8
+
+
+# Defines firetasks for running LAMMPS simulations and AmberTools.
+
+import os
+import re
+import json
+import shutil
+import logging
+import subprocess
+
+from configparser import ConfigParser
+
+from pymatgen.io.lammps.inputs import LammpsInput
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+
+from mispr.lammps.utilities.opls import MaestroRunner
+from mispr.gaussian.utilities.mol import process_mol
+from mispr.gaussian.utilities.misc import recursive_compare_dicts
+from mispr.lammps.utilities.utilities import (
+    get_db,
+    process_ff_doc,
+    add_ff_labels_to_dict,
+)
+from mispr.gaussian.utilities.metadata import get_mol_formula
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+CONFIG_PATH = os.path.normpath(
+    os.path.join(
+        os.path.dirname(os.path.abspath(__file__)),
+        "..", "config", "config.ini"
+    )
+)
+
+OPLS_DOI = "10.1002/jcc.20292"
+
+
+
[docs]@explicit_serialize +class RunLammpsDirect(FiretaskBase): + """ + Run a LAMMPS simulation from a single control file. + + Args: + working_dir (str, optional): The directory to run the simulation in. Defaults + to the current working directory. file. + control_filename (str, optional): Name of the LAMMPS control file. Defaults to + "complex.lammpsin". + lammps_cmd (str, optional): The command to run LAMMPS. If not provided, the + command will attempt to read from the "config.ini" file. + net_ntasks (int, optional): The number of processors to run the simulation on. + If not provided, the number of processors will be read from the ``fw_spec`` + based on the number of nodes used and the number of tasks per node. + """ + _fw_name = "Run Lammps" + required_params = [] + optional_params = [ + "working_dir", + "control_filename", + "lammps_cmd", + "net_ntasks" + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + control_filename = self.get("control_filename", "complex.lammpsin") + control_file_path = os.path.join(working_dir, control_filename) + + ntasks_node = fw_spec.get("_queueadapter", {"ntasks_per_node": 1}).get( + "ntasks_per_node", 1 + ) + nodes = fw_spec.get("_queueadapter", {"nodes": 1}).get("nodes", 1) + net_ntasks = self.get("net_ntasks", ntasks_node * nodes) + command = self.get("lammps_cmd") + + if not command: + config = ConfigParser() + config.read(CONFIG_FILE_DIR + "/config.ini") + command = config["LammpsRunCalc"]["lcmd"] + command = command.replace("$control_path$", control_file_path) + command = command.replace("$SLURM_NTASKS", str(net_ntasks)) + + logger.info("Running command: {}".format(command)) + return_code = subprocess.call(command, shell=True) + logger.info( + "Finished running with return code: {}".format(return_code) + )
+ + +
[docs]@explicit_serialize +class RunLammpsFake(FiretaskBase): + """ + Run a fake LAMMPS simulation. + + Args: + ref_dir (str): The directory containing the reference LAMMPS files. + working_dir (str, optional): The directory to run the fake simulation in. + Defaults to the current working directory. + control_filename (str, optional): The name of the LAMMPS control file. Defaults + to "complex.lammpsin". + """ + required_params = ["ref_dir"] + optional_params = ["working_dir", "control_filename"] + +
[docs] def run_task(self, fw_spec): + self._verify_inputs() + self._clear_inputs() + self._generate_outputs()
+ + def _verify_inputs(self): + ref_dir = self["ref_dir"] + working_dir = self.get("working_dir", os.getcwd()) + control_file = self.get("control_filename", "complex.lammpsin") + + user_control = LammpsInput.from_file(f"{working_dir}/{control_file}") + ref_control = LammpsInput.from_file(f"{ref_dir}/{control_file}") + + ref_dict = ref_control.as_dict() + user_dict = user_control.as_dict() + + # remove spaces and keys starting with a # + user_dict = { + k: user_dict[k] + for k in user_dict + if not re.match(r"#(\s+)?", k) + if re.match(r"\S+?", k) + } + ref_dict = { + k: ref_dict[k] + for k in ref_dict + if not re.match(r"#(\s+)?", k) + if re.match(r"\S+?", k) + } + diff = recursive_compare_dicts(ref_dict, user_dict, + "ref_dict", "user_dict") + + if diff: + raise ValueError( + f"Control settings are inconsistent with reference \ + control!\n{diff}!" + ) + logger.info("RunLammpsFake: verified control successfully") + + def _clear_inputs(self): + working_dir = self.get("working_dir", os.getcwd()) + control_file = self.get("control_filename", "complex.lammpsin") + control_file = f"{working_dir}/{control_file}" + if os.path.exists(control_file): + os.remove(control_file) + + def _generate_outputs(self): + ref_dir = self["ref_dir"] + working_dir = self.get("working_dir", os.getcwd()) + for file in os.listdir(ref_dir): + full_path = f"{ref_dir}/{file}" + if os.path.isfile(full_path): + shutil.copy(full_path, working_dir) + logger.info("RunLammpsFake: ran fake Lammps, generated outputs")
+ + +# TODO: LAMMPS Custodian Firetask + + +
[docs]@explicit_serialize +class RunAntechamber(FiretaskBase): + """ + Run the Antechamber program. Intented to be used to generate the partial charges + for the molecule in a mol2 file from a Gaussian ESP file. Refer to the AmberTools + documentation for more information on this program: + https://ambermd.org/AmberTools.php. + + Args: + working_dir (str, optional): The directory to run Antechamber in. Defaults to + the current working directory. + input_filename_a (str, optional): The name of the input file. Defaults to + "mol.esp". + input_file_type (str, optional): The type of the input file. Defaults to "gesp". + output_filename_a (str, optional): The name of the output file. Defaults to + "mol.mol2". + output_file_type (str, optional): The type of the output file. Defaults to "mol2". + charge_method (str, optional): The method to calculate the partial charges. + Defaults to "resp". + antechamber_cmd (str, optional): The command to run Antechamber. If not provided, + the command will be read from the "config.ini" file. + """ + _fw_name = "Run Antechamber" + required_params = [] + optional_params = [ + "working_dir", + "input_filename_a", + "input_file_type", + "output_filename_a", + "output_file_type", + "charge_method", + "antechamber_cmd", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + input_filename = self.get("input_filename_a", "mol.esp") + input_file_type = self.get("input_filetype", "gesp") + output_filename = self.get("output_filename_a", "mol.mol2") + output_file_type = self.get("output_filetype", "mol2") + charge_method = self.get("charge_method", "resp") + + input_file_path = os.path.join(working_dir, input_filename) + output_file_path = os.path.join(working_dir, output_filename) + + command = self.get("antechamber_cmd") + + if not command: + config = ConfigParser() + config.read(CONFIG_FILE_DIR + "/config.ini") + command = config["AmbertoolsRunCalc"]["acmd"] + command = ( + command.replace("$input_file$", input_file_path) + .replace("$input_type$", input_file_type) + .replace("$output_file$", output_file_path) + .replace("$output_type$", output_file_type) + .replace("$charge_method$", charge_method) + ) + + logger.info("Running command: {}".format(command)) + return_code = subprocess.call(command, shell=True) + logger.info( + "Finished running with return code: {}".format(return_code) + )
+ + +# TODO: Antechamber Custodian Firetask + + +
[docs]@explicit_serialize +class RunParmchk(FiretaskBase): + """ + Run the Parmchk program. Intended to be used to generate a frcmod file from a mol2 + file. Refer to the AmberTools documentation for more information on the Parmchk + program: https://ambermd.org/AmberTools.php. + + Args: + working_dir (str, optional): The directory to run Parmchk in. Defaults to the + current working directory. + input_filename_p (str, optional): The name of the input file. Defaults to + "mol.mol2". + output_filename_p (str, optional): The name of the output file. Defaults to + "mol.frcmod". + parmchk_cmd (str, optional): The command to run Parmchk. If not provided, the + command will be read from the "config.ini" file. + """ + _fw_name = "Run Parmchk" + required_params = [] + optional_params = [ + "working_dir", + "input_filename_p", + "output_filename_p", + "parmchk_cmd", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + input_filename = self.get("input_filename_p", "mol.mol2") + output_filename = self.get("output_filename_p", "mol.frcmod") + + input_file_path = os.path.join(working_dir, input_filename) + output_file_path = os.path.join(working_dir, output_filename) + + command = self.get("parmchk_cmd") + + if not command: + config = ConfigParser() + config.read(CONFIG_FILE_DIR + "/config.ini") + command = config["AmbertoolsRunCalc"]["pcmd"] + command = command.replace("$input_file$", input_file_path).replace( + "$output_file$", output_file_path + ) + + logger.info("Running command: {}".format(command)) + return_code = subprocess.call(command, shell=True) + logger.info( + "Finished running with return code: {}".format(return_code) + )
+ + +# TODO: Edit RunParmchk for general input file type +# TODO: Parmchk Custodian Firetask + + +
[docs]@explicit_serialize +class RunTleap(FiretaskBase): + """ + Run the Tleap program. Intended to be used to generate the GAFF parameters for a + single molecular species into a prmtop file from a mol2 file and a frcmod file. + Refer to the AmberTools documentation for more information on this program: + https://ambermd.org/AmberTools.php. + + Args: + working_dir (str, optional): The directory to run Tleap in. Defaults to the + current working directory. + script_filename (str, optional): The name of the script file. Defaults to + "tleap.in". + tleap_cmd (str, optional): The command to run Tleap. If not provided, the + command will be read from the "config.ini" file. + """ + _fw_name = "Run Tleap" + required_params = [] + optional_params = [ + "working_dir", + "script_filename", + "tleap_cmd", + "system_force_field_dict", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + script_filename = self.get("script_filename", "tleap.in") + script_file_path = os.path.join(working_dir, script_filename) + + command = self.get("tleap_cmd") + + if not command: + config = ConfigParser() + config.read(CONFIG_FILE_DIR + "/config.ini") + command = config["AmbertoolsRunCalc"]["tcmd"] + command = command.replace("$input_file$", script_file_path) + + logger.info("Running command: {}".format(command)) + return_code = subprocess.call(command, shell=True) + logger.info( + "Finished running with return code: {}".format(return_code) + )
+ + +# TODO: evaluate if the "system_force_field_dict" is necessary + +
[docs]@explicit_serialize +class RunMaestro(FiretaskBase): + """ + Run the Maestro program using the MaestroRunner class in the + ``mispr.lammps.utilities.opls`` module to generate OPLS force field parameters for + a molecule. After generating the parameters, add these parameters to the spec. + Refer to the Maestro documentation for more information on this program: + https://www.schrodinger.com/maestro. + + Args: + input_file (str): The path to the input file. + label (str, optional): The label for the molecule. Defaults to the molecule's + formula. + molecule (Molecule, optional): The molecule to generate force field parameters + for. If not provided, the molecule will be read from the input file. + mae_cmd (str, optional): The command to run the structconvert utility program. + If not provided, the command will be read from the "config.ini" file. + ffld_cmd (str, optional): The command to run the ``ffld_server`` utility program. + If not provided, the command will be read from the "config.ini" file. + working_dir (str, optional): The directory to run Maestro in. Defaults to the + current working directory. + maestro_cleanup (bool, optional): Whether to clean up the Maestro files after + running. Defaults to ``False``. + db (str, optional): The connection information of the database to save the force + field parameters to. If not provided, the connection information will be + read from the "db.json" file. + save_ff_to_db (bool, optional): Whether to save the force field parameters to a + database. Defaults to ``False``. + save_ff_to_file (bool, optional): Whether to save the force field parameters to + a file. Defaults to ``True``. + ff_filename (str, optional): The name of the file to save the force field + parameters to. Defaults to "ff.json". + system_force_field_dict (dict, optional): A dictionary to store the force field + parameters for multiple molecules. This is only needed if this dictionary + is not already in the ``fw_spec``. If this dict is not in the ``fw_spec`` or + provided by the user, an empty dict will be created. + """ + required_params = ["input_file"] + optional_params = [ + "label", + "molecule", + "mae_cmd", + "ffld_cmd", + "working_dir", + "maestro_cleanup", + "db", + "save_ff_to_db", + "save_ff_to_file", + "ff_filename", + "system_force_field_dict", + ] + +
[docs] def run_task(self, fw_spec): + input_file = self["input_file"] + working_dir = self.get("working_dir", os.getcwd()) + db = self.get("db", None) + ff_filename = self.get("ff_filename", "ff.json") + save_to_db = self.get("save_ff_to_db", False) + save_to_file = self.get("save_ff_to_file", True) + + molecule = self.get("molecule", fw_spec["prev_calc_molecule"]) + + if not molecule: + try: + molecule = process_mol("get_from_file", self["input_file"]) + except Exception as e: + logger.error("Could not read molecule from file: {}".format(e)) + raise e + + label = self.get("label", get_mol_formula(molecule)) + + maestro = MaestroRunner( + name=label, + input_file=input_file, + mae_cmd=self.get("mae_cmd"), + ffld_cmd=self.get("ffld_cmd"), + working_dir=working_dir, + ) + ff_params = maestro.get_opls_params(self.get("maestro_cleanup", False)) + ff_params["Molecule"] = molecule + + if save_to_db: + ff_doc = ff_params.copy() + ff_db = get_db(input_db=db) + ff_db.insert_force_field(ff_doc, "opls", doi=OPLS_DOI) + + if save_to_file: + ff_doc = process_ff_doc(ff_params.copy(), "opls", doi=OPLS_DOI) + with open(os.path.join(working_dir, ff_filename), "w") as file: + json.dump(ff_doc, file) + + labeled_ff_params = add_ff_labels_to_dict(ff_params, label) + + sys_ff_dict = fw_spec.get( + "system_force_field_dict", self.get("system_force_field_dict", {}) + ) + sys_ff_dict[label] = labeled_ff_params + return FWAction(update_spec={"system_force_field_dict": sys_ff_dict})
+ + +# TODO: tleap Custodian Firetask +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/firetasks/write_inputs.html b/html/_modules/mispr/lammps/firetasks/write_inputs.html new file mode 100644 index 00000000..884c3939 --- /dev/null +++ b/html/_modules/mispr/lammps/firetasks/write_inputs.html @@ -0,0 +1,1332 @@ + + + + + + + + + + + + + + + + mispr.lammps.firetasks.write_inputs - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.firetasks.write_inputs

+# coding: utf-8
+
+
+# Defines firetasks for writing LAMMPS input files.
+
+import os
+import json
+import logging
+
+from string import Template
+
+import numpy as np
+
+from pymatgen.core.structure import Molecule
+from pymatgen.io.lammps.data import LammpsData, LammpsDataWrapper
+from pymatgen.io.lammps.inputs import write_lammps_inputs
+
+from fireworks.core.firework import FWAction, FiretaskBase
+from fireworks.utilities.fw_utilities import explicit_serialize
+from fireworks.utilities.fw_serializers import DATETIME_HANDLER
+
+from mispr.lammps.defaults import TEMPLATE_TYPES, TLEAP_SETTINGS
+from mispr.lammps.utilities.utilities import (
+    get_db,
+    process_run,
+    add_ff_labels_to_dict,
+    lammps_mass_to_element,
+)
+from mispr.gaussian.utilities.metadata import get_chem_schema, get_mol_formula
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+TEMPLATE_DIR = os.path.normpath(
+    os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                 "..", "templates")
+)
+DEFAULT_KEY = "lammpsin_key"
+
+
+
[docs]@explicit_serialize +class WriteDataFile(FiretaskBase): + """ + Write LAMMPS data file for a bulk system in the current working directory. User can + provide a ``LammpsData object``, a ``LammpsDataWrapper`` object, or the inputs for + instantiating a ``LammpsDataWrapper`` object. See the ``LammpsData`` and + ``LammpsDataWrapper`` classes in the ``pymatgen.io.lammps.data`` module for more + information. + + Args: + working_dir (str, optional): Path to the working directory. Defaults to the + current working directory. + data_filename (str, optional): Name of data file to be written. Defaults to + "complex.data". + lammps_data (LammpsData, optional): The ``LammpsData`` object to be written as + the data file. Can be passed through the ``fw_spec`` or input by the user. + If both are provided, the one provided directly will be used. + lammps_data_wrapper (LammpsDataWrapper, optional): The wrapper for the + ``LammpsData`` object to be written as data file. Can be passed through + ``fw_spec`` or input by the user. If both are provided, the one provided + directly will be used. Will be ignored if ``lammps_data`` is provided. + system_force_field_dict (dict, optional): The force field parameters for the + system. Used as input for ``LammpsDataWrapper``. Intended to be created by + the ``GetForceField`` task. Can be passed through ``fw_spec`` or input by + the user. If both are provided, will take the one provided in the ``fw_spec``. + system_mixture_data (dict, optional): The information that will be used to + calculate the number of molecules of each type in the system. Used as input + for a ``LammpsDataWrapper`` object. Can be read from ``fw_spec`` or input + by the user; If both are provided, will use the one provided in the ``fw_spec``. + system_box_data (float, int, list, ndarray, optional): Information about the + system box; the value of this arg is determined by the + ``system_box_data_type``. Used as input for a ``LammpsDataWrapper`` object. + Can be passed through ``fw_spec`` or input by the user. If both are provided, + will take the one provided in the ``fw_spec``. + system_box_data_type (str, optional): Determines the type for ``system_box_data``. + Used as input for a ``LammpsDataWrapper`` object. Defaults to "cubic". + position_seed (int, optional): Seed for randomizing the positions of atoms. + Indirectly used as input for packmol through ``LammpsDataWrapper``. Defaults + to 150. + system_mixture_data_type (str, optional): Determines the content of + ``system_mixture_data``. Used as input for a ``LammpsDataWrapper`` object. + Defaults to "concentration". + scale_charges (bool, optional): Whether to scale the partial charges of all + molecules that have a non-zero net charge in the system. Only used if + building a system from ``LammpsDataWrapper`` inputs. + charge_scaling_factor (float): Factor by which to scale charges in the system. + Only used if building a system from ``LammpsDataWrapper`` inputs and if + ``scale_charges`` is ``True``. + """ + _fw_name = "Write Data File" + required_params = [] + optional_params = [ + "working_dir", + "data_filename", + "lammps_data", + "lammps_data_wrapper", + "system_force_field_dict", + "system_mixture_data", + "system_box_data", + "system_box_data_type", + "position_seed", + "system_mixture_data_type", + "scale_charges", + "charge_scaling_factor", + ] + +
[docs] def run_task(self, fw_spec): + # There are three main ways of creating a data file: + # 1: provide a LammpsData object as "lammps_data" + # optional parameter + # 2: provide a LammpsDataWrapper object as + # "lammps_data_wrapper" optional parameter + # 3: provide the inputs for instantiating a LammpsDataWrapper + # object + + # Set the path for writing the data file + working_dir = fw_spec.get("working_dir", + self.get("working_dir", os.getcwd())) + os.chdir(working_dir) + + data_file_name = self.get("data_filename", "complex.data") + data_file_path = os.path.join(working_dir, data_file_name) + + force_fields = None + mixture = None + box_data = None + lammps_data_wrapper = None + lammps_data = None + + # Now to find/instantiate the LammpsData object. There are + # several different input cases: + # Case where LammpsData object is an optional parameter + if isinstance(self.get("lammps_data"), LammpsData): + lammps_data = self.get("lammps_data") + + # Case where LammpsData object is passed through fw_spec + elif isinstance(fw_spec.get("lammps_data"), LammpsData): + lammps_data = fw_spec.get("lammps_data") + + # Case where LammpsDataWrapper object is an optional parameter + elif isinstance(self.get("lammps_data_wrapper"), LammpsDataWrapper): + lammps_data_wrapper = self.get("lammps_data_wrapper") + + # Case where LammpsDataWrapper object is passed through fw_spec + elif isinstance(fw_spec.get("lammps_data_wrapper"), LammpsDataWrapper): + lammps_data_wrapper = fw_spec.get("lammps_data_wrapper") + + # Case where only required arguments for LammpsDataWrapper + # are provided + elif all( + ( + isinstance( + fw_spec.get("system_force_field_dict", + self.get("system_force_field_dict")), + dict, + ), + isinstance( + fw_spec.get("system_mixture_data", + self.get("system_mixture_data")), + dict, + ), + isinstance( + fw_spec.get("system_box_data", + self.get("system_box_data")), + (float, int, list, np.ndarray), + ), + ) + ): + force_fields = fw_spec.get("system_force_field_dict", + self.get("system_force_field_dict")) + mixture = fw_spec.get("system_mixture_data", + self.get("system_mixture_data")) + box_data = fw_spec.get("system_box_data", + self.get("system_box_data")) + + # Case where no proper inputs exist: raise error + else: + raise KeyError( + "Not enough input objects for data file creation. " + "Add optional parameters or check fw_spec." + ) + + # Create LammpsDataWrapper object + if all((force_fields, mixture, box_data)): + scaling_factor = self.get("charge_scaling_factor") + if self.get("scale_charges") and scaling_factor: + for k, v in force_fields.items(): + if round(sum(force_fields[k]["Charges"])) != 0: + force_fields[k]["Charges"] = [ + i * scaling_factor for i in force_fields[k]["Charges"] + ] + box_data_type = self.get("system_box_data_type", "cubic") + mixture_type = self.get("system_mixture_data_type", + "concentration") + seed = self.get("position_seed", 150) + lammps_data_wrapper = LammpsDataWrapper( + system_force_fields=force_fields, + system_mixture_data=mixture, + box_data=box_data, + box_data_type=box_data_type, + mixture_data_type=mixture_type, + seed=seed, + check_ff_duplicates=False, + ) + + # Convert LammpsDataWrapper to LammpsData + if lammps_data_wrapper: + lammps_data = lammps_data_wrapper.build_lammps_data() + + n_mols_dict = lammps_data_wrapper.nmol_dict + molecules_list = [ + force_fields[mol_label]["Molecule"] + for mol_label in lammps_data_wrapper.sorted_mol_names + ] + smiles_list = [ + get_chem_schema(force_fields[mol_label]["Molecule"])["smiles"] + for mol_label in lammps_data_wrapper.sorted_mol_names + ] + num_mols_list = [ + n_mols_dict[name] + for name in lammps_data_wrapper.sorted_mol_names + ] + lmp_box = lammps_data.box + num_atoms_per_mol_list = [ + len(lammps_data_wrapper.ff_list[name]["Molecule"].sites) + for name in lammps_data_wrapper.sorted_mol_names + ] + default_masses_list = [] + recalc_masses_list = [] + for name in lammps_data_wrapper.sorted_mol_names: + default_masses_list += list( + lammps_data_wrapper.ff_list[name]["Masses"].values() + ) + for label in lammps_data_wrapper.ff_list[name]["Labels"]: + recalc_masses_list.append( + lammps_data_wrapper.ff_list[name]["Masses"][label] + ) + + # Write data file + if lammps_data: + lammps_data.write_file(filename=data_file_path, + distance=10, + charge=20) + return FWAction( + update_spec={ + "smiles": smiles_list, + "nmols": n_mols_dict, + "num_mols_list": num_mols_list, + "num_atoms_per_mol": num_atoms_per_mol_list, + "default_masses": default_masses_list, + "recalc_masses": recalc_masses_list, + "molecules": molecules_list, + "box": lmp_box, + }, + propagate=True, + ) + else: + pass
+ + +
[docs]@explicit_serialize +class WriteControlFile(FiretaskBase): + """ + Write a LAMMPS control file based on a template file or string. + + Args: + working_dir (str, optional): Path to working directory. Default is current + working directory. + db (str or dict, optional): Connection information for the calc database; If + ``save_runs_to_db`` is ``True``, then a document will be stored in the + database. Default is ``None``. + control_filename (str, optional): Name of control file to be written. Default is + "complex.lammpsin". + template_filename (str, optional): Name of template control file to be used. + Is not used if ``template_str`` is provided. Can refer to a custom template + or a template name from the ``mispr/lammps/templates`` directory. + template_dir (str, optional): Path to directory containing template file. If the + template is from ``mispr/lammps/templates``, then this is not needed. + template_str (str, optional): String containing template for control file. + control_settings (dict, optional): Dictionary of settings to be used in the + control file. If a mispr template is used, this dictionary will update the + corresponding control_settings dictionary in the ``mispr/lammps/defaults.py`` + file. Default is None. + save_runs_to_db (bool, optional): Whether to save the run info to the calc + database. Default is ``False``. + save_runs_to_file (bool, optional): Whether to save the run info to a file in + the working directory. Default is ``True``. + lammpsin_key (str, optional): Key in the ``fw_spec`` that corresponds with the + ``run_doc`` information. Default is "lammpsin". + """ + _fw_name = "Write Control File" + required_params = [] + optional_params = [ + "working_dir", + "db", + "control_filename", + "template_filename", + "template_dir", + "template_str", + "control_settings", + "save_runs_to_db", + "save_runs_to_file", + "lammpsin_key", + ] + +
[docs] def run_task(self, fw_spec): + # Set directory for writing control file + working_dir = fw_spec.get("working_dir", self.get("working_dir", + os.getcwd())) + template_dir = None + os.makedirs(working_dir, exist_ok=True) + os.chdir(working_dir) + + db = self.get("db", None) + save_to_db = self.get("save_runs_to_db", False) + save_to_file = self.get("save_runs_to_file", True) + + # Set filename for control file + control_filename = self.get("control_filename", "complex.lammpsin") + + # Set the settings parameter + control_settings = self.get("control_settings", None) + + default_masses_list = fw_spec.get("default_masses", []) + if default_masses_list: + lammps_elements = lammps_mass_to_element(default_masses_list) + if "X" not in lammps_elements: + control_settings["dump_modify_elements"] = "element {}".format( + " ".join(lammps_elements) + ) + + # There are three different cases for input of the template: + # Case 1: template as string + if isinstance(self.get("template_str"), str): + template_string = self.get("template_str") + template_filename = None + # Cases 2 and 3: template from file, with filename set by + # template_type variable + elif isinstance(self.get("template_filename"), str): + template_filename = self.get("template_filename") + # Case 2: template from file in /../templates/ directory + if template_filename in TEMPLATE_TYPES: + template_dir = TEMPLATE_DIR + # Case 3: template from file provided by user + elif isinstance(self.get("template_dir"), str): + template_dir = self.get("template_dir") + else: + raise KeyError( + "Directory containing custom template file was not " + "specified; add as optional parameter" + ) + else: + raise KeyError( + "Either template was not provided as a valid string or the " + "path to a template text file was not provided." + ) + + if template_filename: + template_path = os.path.join(template_dir, template_filename) + with open(template_path) as file: + template_string = file.read() + + write_lammps_inputs( + working_dir, + template_string, + settings=control_settings, + script_filename=control_filename, + ) + + smiles_list = fw_spec.get("smiles", []) + n_mols_dict = fw_spec.get("nmols", {}) + num_mols_list = fw_spec.get("num_mols_list", []) + lmp_box = fw_spec.get("box", None) + num_atoms_per_mol_list = fw_spec.get("num_atoms_per_mol", []) + recalc_masses_list = fw_spec.get("recalc_masses", []) + + run_doc = process_run( + smiles_list, + n_mols_dict, + lmp_box, + template_filename, + control_settings + ) + run_doc.update({"working_dir": working_dir}) + + run_list = {} + if save_to_db: + run_db = get_db(input_db=db) + run_id = run_db.insert_run(run_doc) + run_list["lammps_run_id_list"] = run_id + logger.info("Saved run info to db") + + if save_to_file: + file = os.path.join(working_dir, "run_file.json") + with open(file, "w") as run_file: + run_file.write(json.dumps(run_doc, default=DATETIME_HANDLER)) + run_list["lammps_run_loc_list"] = file + logger.info("Saved run info to json file") + + spec = { + "smiles": smiles_list, + "nmols": n_mols_dict, + "num_mols_list": num_mols_list, + "box": lmp_box, + "num_atoms_per_mol": num_atoms_per_mol_list, + "default_masses": default_masses_list, + "recalc_masses": recalc_masses_list, + } + + uid = self.get("lammpsin_key") + set_dict = {f"lammpsin->{DEFAULT_KEY}": run_doc} + if uid: + set_dict[f"lammpsin->{uid}"] = run_doc + mod_dict = {"_set": set_dict} + if run_list: + mod_dict.update({"_push": run_list}) + return FWAction(update_spec=spec, mod_spec=mod_dict, propagate=True)
+ + +# TODO: Write a firetask for writing a general data file +# TODO: Write a firetask for writing a general control file template \ +# (multiple fix options, general template) + + +
[docs]@explicit_serialize +class WriteTleapScript(FiretaskBase): + """ + Write a tleap script for generating a prmtop and inpcrd file for a molecule. + Intended to be used to obtain the parameters from the GAFF force field. + + Args: + working_dir (str): Path to the working directory. Defaults to current working + directory. + script_string (str): String containing the tleap script. If not provided, the + ``template_filename`` and ``template_dir`` must be provided. + template_filename (str): Name of the template file. Defaults to "gaff_tleap". + template_dir (str): Path to the directory containing the template file. Defaults + to the mispr/lammps/templates/ directory. + tleap_settings (dict): Dictionary containing the settings for the tleap script. + Used to update the ``TLEAP_SETTINGS`` dict in + mispr/lammps/defaults.py file. Defaults to empty dict. + script_filename (str): Name of the tleap script file. Defaults to "tleap.in". + """ + _fw_name = "Write Tleap Script" + required_params = [] + optional_params = [ + "working_dir", + "script_string", + "template_filename", + "template_dir", + "tleap_settings", + "script_filename", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + if isinstance(self.get("script_string"), str): + script_string = self.get("script_string") + else: + template_filename = self.get("template_filename", "gaff_tleap") + template_dir = self.get("template_dir", TEMPLATE_DIR) + template_file_path = os.path.join(template_dir, template_filename) + with open(template_file_path) as t_file: + script_string = t_file.read() + + tleap_settings = TLEAP_SETTINGS.update( + self.get("tleap_settings", fw_spec.get("tleap_settings", {})) + ) + + script_string = Template(script_string).substitute( + tleap_settings, **TLEAP_SETTINGS + ) + + script_filename = self.get("script_filename", "tleap.in") + script_file_path = os.path.join(working_dir, script_filename) + + with open(script_file_path, "w") as script: + script.write(script_string)
+ + +
[docs]@explicit_serialize +class LabelFFDict(FiretaskBase): + """ + Append molecule label to all atom labels in the force field dictionary. Ensures + that no two molecules can share the same atom labels provided that each molecule + has a unique label for the system. + + Args: + mol (Molecule, optional): pymatgen Molecule object; if not provided, the + ``prev_calc_molecule`` key from the ``fw_spec`` will be used. + unlabeled_dict (dict, optional): Dictionary containing the force field parameters + for the molecule; ignored if the ``ff_file`` is provided. + ff_file (str, optional): Path to the json file containing the force field + parameters for the molecule. + working_dir (str, optional): Path to the working directory. Defaults to current + working directory. + label (str, optional): Label for the molecule. Defaults to the molecular formula. + system_force_field_dict (dict, optional): Dictionary containing the force field + parameters for the system that is used as the input for ``LammpsDataWrapper`` + object; intended to be obtained from the spec; if present in the spec, + this will be ignored. + """ + _fw_name = "Label FF Dict" + required_params = [] + optional_params = [ + "mol", + "unlabeled_dict", + "ff_file", + "working_dir", + "label", + "system_force_field_dict", + ] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + ff_file = self.get("ff_file") + mol = self.get("mol", fw_spec.get("prev_calc_molecule")) + + if ff_file: + with open(ff_file, "r") as file: + unlabeled_dict = json.load(file) + # mol = unlabeled_dict["Molecule"] + else: + if not isinstance(mol, Molecule): + raise TypeError( + '"mol" input must be a PyMatGen Molecule object' + ) + + if not isinstance(self.get("unlabeled_dict"), dict): + raise TypeError('"unlabeled_dict" input must be a dict') + + unlabeled_dict = self.get("unlabeled_dict") + + unlabeled_dict["Molecule"] = mol + label = self.get("label", get_mol_formula(mol)) + labeled_dict = add_ff_labels_to_dict(unlabeled_dict, label) + sys_ff_dict = fw_spec.get( + "system_force_field_dict", self.get("system_force_field_dict", {}) + ) + sys_ff_dict[label] = labeled_dict + return FWAction(update_spec={"system_force_field_dict": sys_ff_dict})
+ + +
[docs]@explicit_serialize +class LabelFFDictFromDB(FiretaskBase): + """ + Append molecule label to all atom labels in a force field dictionary obtained from + the database. Ensures that no two molecules can share the same atom labels provided + that each molecule has a unique label for the system. + + Args: + filter (dict): Dictionary containing the filter used to query the database. + working_dir (str, optional): Path to the working directory. Defaults to + current working directory. + db (dict or str, optional): Information for connecting to the database as + either a dictionary of credentials or a path to a json file containing the + credentials; if not provided, the database specified in the env will be used. + label (str, optional): Label for the molecule. Defaults to the molecular formula. + system_force_field_dict (dict, optional): Dictionary containing the force field + parameters for the system that is used as the input for ``LammpsDataWrapper`` + object; intended to be obtained from the spec; if present in the spec, this + will be ignored. + """ + _fw_name = "Label FF Dict From DB" + required_params = ["filter"] + optional_params = ["working_dir", "db", "label", "system_force_field_dict"] + +
[docs] def run_task(self, fw_spec): + working_dir = self.get("working_dir", os.getcwd()) + os.chdir(working_dir) + + db = self.get("db", None) + ff_db = get_db(input_db=db) + + filter = self.get("filter") + unlabeled_ff_dict = ff_db.retrieve_force_field(**filter) + mol = Molecule.from_dict(unlabeled_ff_dict) + unlabeled_ff_dict["Molecule"] = mol + + label = self.get("label", get_mol_formula(mol)) + + labeled_ff_dict = add_ff_labels_to_dict(unlabeled_ff_dict, label) + + sys_ff_dict = fw_spec.get( + "system_force_field_dict", self.get("system_force_field_dict", {}) + ) + + sys_ff_dict[label] = labeled_ff_dict + + return FWAction(update_spec={"system_force_field_dict": sys_ff_dict})
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/fireworks/core.html b/html/_modules/mispr/lammps/fireworks/core.html new file mode 100644 index 00000000..7e912077 --- /dev/null +++ b/html/_modules/mispr/lammps/fireworks/core.html @@ -0,0 +1,1253 @@ + + + + + + + + + + + + + + + + mispr.lammps.fireworks.core - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.fireworks.core

+# coding: utf-8
+
+
+# Defines core fireworks for ambertools and lammps.
+
+import os
+import logging
+
+from fireworks import Firework
+
+from mdproptools.structural.rdf_cn import calc_atomic_rdf, calc_molecular_rdf
+
+from mispr.lammps.firetasks.run import (
+    RunTleap,
+    RunMaestro,
+    RunParmchk,
+    RunAntechamber,
+    RunLammpsDirect,
+)
+from mispr.gaussian.utilities.metadata import get_chem_schema
+from mispr.gaussian.workflows.base.core import _process_mol_check
+from mispr.lammps.firetasks.write_inputs import (
+    LabelFFDict,
+    WriteControlFile,
+    WriteTleapScript,
+    LabelFFDictFromDB,
+)
+from mispr.lammps.firetasks.parse_outputs import GetRDF, CalcDiff, ProcessPrmtop
+from mispr.gaussian.firetasks.geo_transformation import ProcessMoleculeInput
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+FIREWORK_KWARGS = Firework.__init__.__code__.co_varnames
+
+
+
[docs]def ambertools_tasks(**kwargs): + """ + Define a list of common tasks for generating GAFF parameters for a molecule. This is + a helper function for the GetFFDictFW Firework. + + Args: + kwargs: other kwargs that are passed to: + + 1. ``mispr.lammps.firetasks.run.RunAntechamber`` + 2. ``mispr.lammps.firetasks.run.RunParmchk`` + 3. ``mispr.lammps.firetasks.write_inputs.WriteTleapScript`` + 4. ``mispr.lammps.firetasks.run.RunTleap`` + 5. ``mispr.lammps.firetasks.parse_outputs.ProcessPrmtop`` + + Returns: + List of Firetasks. + """ + common_t = [ + RunAntechamber( + **{ + i: j + for i, j in kwargs.items() + if i in RunAntechamber.required_params + RunAntechamber.optional_params + } + ), + RunParmchk( + **{ + i: j + for i, j in kwargs.items() + if i in RunParmchk.required_params + RunParmchk.optional_params + } + ), + WriteTleapScript( + **{ + i: j + for i, j in kwargs.items() + if i + in WriteTleapScript.required_params + WriteTleapScript.optional_params + } + ), + RunTleap( + **{ + i: j + for i, j in kwargs.items() + if i in RunTleap.required_params + RunTleap.optional_params + } + ), + ProcessPrmtop( + **{ + i: j + for i, j in kwargs.items() + if i in ProcessPrmtop.required_params + ProcessPrmtop.optional_params + } + ), + ] + return common_t
+ + +
[docs]class GetFFDictFW(Firework): + """ + Generate the ff parameters for a molecule. + """ + + def __init__( + self, + mol, + mol_operation_type, + data, + operation_type="get_from_esp", + label="", + name="get_ff_dict", + parents=None, + working_dir=None, + db=None, + save_ff_to_db=False, + save_ff_to_file=True, + ff_filename="ff.json", + tag="unknown", + **kwargs + ): + """ + Args: + mol (Molecule, GaussianOutput, str, dict): Source of the molecule to be + processed. Should match the ``mol_operation_type``. + mol_operation_type (str): The type of molecule operation. See ``process_mol`` + defined in ``mispr/gaussian/utilities/mol.py`` for supported operations. + data (str, dict): Data to be processed, e.g., path to the esp file if + ``operation_type`` is ``get_from_esp``, path to the prmtop file if + ``operation_type`` is ``get_from_prmtop``, etc. + operation_type (str, optional): The operation to perform on the data to read + or generate the force field parameters. Defaults to ``get_from_esp``. + Supported commands: + + 1. ``get_from_esp``: If the input is an ESP file. + 2. ``get_from_prmtop``: If the input is a prmtop file. + 3. ``get_from_opls``: If the input is a molecule file to be used to + generate opls ff parameters. + 4. ``get_from_dict``: If the input is a dictionary of force field + parameters. e.g., + + .. code-block:: python + + { + "Molecule": pymatgen_molecule, + "Labels": atom_labels, + "Masses": atomtype_masses, + "Nonbond": nonbond_params, + "Bonds": bond_params, + "Angles": angle_params, + "Dihedrals": dihedral_params, + "Impropers": improper_params, + "Improper Topologies": improper_topologies, + "Charges": charges + } + + 5. 'get_from_file': If the input is a json file of the force field + parameters. + 6. 'get_from_db': If the input is a filter for the database to search + for the force field parameters. + + label (str, optional): Label for the molecule. This should be unique for + each different molecular species in the system. Defaults to an empty + string. In this case, the label will be obtained based on the molecular + formula. + name (str, optional): Name of the Firework. Defaults to ``get_ff_dict``. + parents (Firework or [Firework], optional): List of parent Fireworks that + this Firework depends on. Defaults to ``None``. + working_dir (str, optional): Directory to run the Firework in. Defaults to + the current working directory. + db (str or dict, optional): Database credentials. Could be provided as the + path to the "db.json" file or in the form of a dict. If none is provided, + attempts to read it from the configuration files to save the Firework to. + save_ff_to_db (bool, optional): Whether to save the force field to the + database. Defaults to ``False``. + save_ff_to_file (bool, optional): Whether to save the force field to a file. + Defaults to ``True``. + ff_filename (str, optional): Filename to save the force field to. Defaults + to "ff.json". + tag (str): Tag for the Firework. The provided tag will be stored in the db + documents for easy retrieval. Defaults to "unknown". + kwargs: Other kwargs that are passed to: + + 1. Firework.__init__ + 2. ``mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput`` + 3. ``mispr.lammps.firetasks.run.RunAntechamber`` + 4. ``mispr.lammps.firetasks.run.RunParmchk`` + 5. ``mispr.lammps.firetasks.write_inputs.WriteTleapScript`` + 6. ``mispr.lammps.firetasks.run.RunTleap`` + 7. ``mispr.lammps.firetasks.parse_outputs.ProcessPrmtop`` + 8. ``mispr.lammps.firetasks.run.RunMaestro`` + 9. ``mispr.lammps.firetasks.write_inputs.LabelFFDict`` + 10. ``mispr.lammps.firetasks.write_inputs.LabelFFDictFromDB`` + + """ + tasks = [] + working_dir = working_dir or os.getcwd() + + # TODO: add logic for ensuring that directory name is legal or at \ + # least usable + os.makedirs(working_dir, exist_ok=True) + + tasks.append( + ProcessMoleculeInput( + mol=mol, + operation_type=mol_operation_type, + db=db, + working_dir=working_dir, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessMoleculeInput.required_params + + ProcessMoleculeInput.optional_params + } + ) + ) + + if operation_type == "get_from_esp": + if not isinstance(data, str): + raise TypeError( + "data must be a str of the path to the esp " + 'file for operation_type="get_from_esp"' + ) + tasks += ambertools_tasks( + db=db, + working_dir=working_dir, + input_filename_a=data, + unique_molecule_name=label, + save_ff_to_db=save_ff_to_db, + save_ff_to_file=save_ff_to_file, + ff_filename=ff_filename, + **{ + i: j + for i, j in kwargs.items() + if i + in RunAntechamber.required_params + + RunAntechamber.optional_params + + RunParmchk.required_params + + RunParmchk.optional_params + + WriteTleapScript.required_params + + WriteTleapScript.optional_params + + RunTleap.required_params + + RunTleap.optional_params + + ProcessPrmtop.required_params + + ProcessPrmtop.optional_params + } + ) + + elif operation_type == "get_from_prmtop": + if not isinstance(data, str): + raise TypeError( + "data must be a str of the path to the prmtop " + 'file for operation_type="get_from_prmtop"' + ) + tasks.append( + ProcessPrmtop( + working_dir=working_dir, + db=db, + prmtop_path=data, + unique_molecule_name=label, + save_ff_to_db=save_ff_to_db, + save_ff_to_file=save_ff_to_file, + ff_filename=ff_filename, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessPrmtop.required_params + ProcessPrmtop.optional_params + } + ) + ) + + elif operation_type == "get_from_opls": + if not isinstance(data, str): + raise TypeError( + "data must be a str of the path to the molecule " + "file for operation_type='get_from_opls'. " + "Check https://www.schrodinger.com/kb/1278 for " + "supported structure file formats" + ) + tasks.append( + RunMaestro( + input_file=data, + label=label, + db=db, + working_dir=working_dir, + save_ff_to_db=save_ff_to_db, + save_ff_to_file=save_ff_to_file, + ff_filename=ff_filename, + **{ + i: j + for i, j in kwargs.items() + if i in RunMaestro.required_params + RunMaestro.optional_params + } + ) + ) + + elif operation_type == "get_from_dict": + if not isinstance(data, dict): + raise TypeError( + "data must be a dict for " 'operation_type="get_from_dict"' + ) + tasks.append( + LabelFFDict( + unlabeled_dict=data, + working_dir=working_dir, + label=label, + **{ + i: j + for i, j in kwargs.items() + if i + in LabelFFDict.required_params + LabelFFDict.optional_params + } + ) + ) + + elif operation_type == "get_from_file": + if not isinstance(data, str): + raise TypeError( + "data must be a str of the path to the ff " + 'json file for operation_type="get_from_file"' + ) + tasks.append( + LabelFFDict( + ff_file=data, + working_dir=working_dir, + label=label, + **{ + i: j + for i, j in kwargs.items() + if i + in LabelFFDict.required_params + LabelFFDict.optional_params + } + ) + ) + + elif operation_type == "get_from_db": + tasks.append( + LabelFFDictFromDB( + filter=data, + db=db, + working_dir=working_dir, + label=label, + **{ + i: j + for i, j in kwargs.items() + if i + in LabelFFDictFromDB.required_params + + LabelFFDictFromDB.optional_params + } + ) + ) + + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + super(GetFFDictFW, self).__init__( + tasks, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+ + +
[docs]class RunLammpsFW(Firework): + """ + Run a lammps simulation. + """ + def __init__( + self, + control_file=None, + db=None, + name="run_lammps", + parents=None, + working_dir=None, + save_run_to_db=True, + save_run_to_file=False, + tag="unknown", + **kwargs + ): + """ + Args: + control_file (str, optional): Path to the control file. If + not provided, the control file will be generated. + Defaults to None. + db (str or dict, optional): Database credentials. Could be + provided as the path to the db.json file or in the form + of a dict. If none is provided, attempts to read it + from the configuration files to save the Firework to. + name (str, optional): Name of the Firework. Defaults to + "run_lammps". + parents (Firework or [Firework], optional): List of parent + Fireworks that this Firework depends on. Defaults to + ``None``. + working_dir (str, optional): Directory to run the Firework + in. Defaults to the current working directory. + save_run_to_db (bool, optional): Whether to save the run to + the database. Defaults to True. + save_run_to_file (bool, optional): Whether to save the run + to a file. Defaults to False. + tag (str): Tag for the Firework. The provided tag will be + stored in the db documents for easy retrieval. Defaults + to "unknown". + kwargs: Other kwargs that are passed to: + + 1. Firework.__init__ + 2. ``mispr.lammps.firetasks.write_inputs.WriteControlFile`` + 3. ``mispr.lammps.firetasks.run.RunLammpsDirect`` + """ + tasks = [] + working_dir = working_dir or os.getcwd() + + if not control_file: + tasks.append( + WriteControlFile( + working_dir=working_dir, + db=db, + save_runs_to_db=save_run_to_db, + save_runs_to_file=save_run_to_file, + **{ + i: j + for i, j in kwargs.items() + if i + in WriteControlFile.required_params + + WriteControlFile.optional_params + } + ) + ) + + tasks.append( + RunLammpsDirect( + working_dir=working_dir, + **{ + i: j + for i, j in kwargs.items() + if i + in RunLammpsDirect.required_params + RunLammpsDirect.optional_params + } + ) + ) + + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + + super(RunLammpsFW, self).__init__( + tasks, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+ + +
[docs]class RunAnalysisFW(Firework): + """ + Run an analysis on a LAMMPS trajectory. + """ + def __init__( + self, + md_property, + name="run_analysis", + parents=None, + working_dir=None, + tag="unknown", + **kwargs + ): + """ + Args: + md_property (str): The property to calculate. Supported properties: + + 1. 'diffusion': Calculate the diffusion coefficient. + 2. 'rdf': Calculate the radial distribution function. + name (str, optional): Name of the Firework. Defaults to "run_analysis". + parents (Firework or [Firework], optional): List of parent Fireworks that + this Firework depends on. Defaults to ``None``. + working_dir (str, optional): Directory to run the Firework in. Defaults to + the current working directory. + tag (str): Tag for the Firework. The provided tag will be stored in the db + documents for easy retrieval. Defaults to "unknown". + kwargs: Other kwargs that are passed to: + + 1. Firework.__init__ + 2. ``mispr.lammps.firetasks.parse_outputs.CalcDiff`` + 3. ``mispr.lammps.firetasks.parse_outputs.GetRDF`` + 4. ``mispr.lammps.firetasks.parse_outputs.CalcDiff`` + """ + tasks = [] + working_dir = working_dir or os.getcwd() + + if md_property == "diffusion": + diff_kwargs = { + i: j + for i, j in kwargs.items() + if i in CalcDiff.required_params + CalcDiff.optional_params + } + diff_kwargs.update({"working_dir": working_dir}) + tasks.append(CalcDiff(**diff_kwargs)) + + elif md_property == "rdf": + rdf_kwargs = { + i: j + for i, j in kwargs.items() + if i + in inspect.getfullargspec(calc_atomic_rdf).args + + inspect.getfullargspec(calc_molecular_rdf).args + + GetRDF.required_params + + GetRDF.optional_params + } + rdf_kwargs.update({"working_dir": working_dir}) + tasks.append(GetRDF(**rdf_kwargs)) + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + super(RunAnalysisFW, self).__init__( + tasks, + parents=parents, + name=name, + spec=spec, + **{i: j for i, j in kwargs.items() if i in FIREWORK_KWARGS} + )
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/tests/base_test.html b/html/_modules/mispr/lammps/tests/base_test.html new file mode 100644 index 00000000..43213d65 --- /dev/null +++ b/html/_modules/mispr/lammps/tests/base_test.html @@ -0,0 +1,1138 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests.base_test - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.tests.base_test

+import os
+
+from collections import OrderedDict
+
+from fireworks import Workflow, LaunchPad, FiretaskBase, explicit_serialize
+from fireworks.core.rocket_launcher import rapidfire
+
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.io.ambertools import PrmtopParser
+from pymatgen.core.structure import Molecule
+
+from mispr.lammps.workflows.base import lammps_workflow
+from mispr.gaussian.utilities.metadata import get_mol_formula
+
+
+
[docs]@explicit_serialize +class PrintFW(FiretaskBase): + """ + Firetask for confirming that modspec works as intended in ProcessPrmtop firetask + """ + +
[docs] def run_task(self, fw_spec): + print(str(fw_spec["system_force_field_dict"]))
+ + +if __name__ == "__main__": + + # set up the LaunchPad and reset it + launchpad = LaunchPad( + host="mongodb://superuser:idlewide@localhost:27017/fireworks?authSource=admin", + uri_mode=True, + ) + launchpad.reset("", require_password=False) + + working_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "test_files", "data" + ) + + # Preparing inputs for ambertools for species not using existing ff models + # Phen_type parameter prep + Phen_type = "dhps" + Phen_type_gaussian_output = GaussianOutput( + os.path.join(working_dir, Phen_type + ".out") + ) + Phen_type_molecule = Phen_type_gaussian_output.structures[-1] + Phen_type_molecule.set_charge_and_spin( + Phen_type_gaussian_output.charge, Phen_type_gaussian_output.spin_multiplicity + ) + Phen_type_label = get_mol_formula(Phen_type_molecule) + Phen_type_param_dict = PrmtopParser( + os.path.join(working_dir, Phen_type_label + ".prmtop"), Phen_type_molecule, "" + ).to_dict() + # Oh parameter prep + Oh_gaussian_output = GaussianOutput(os.path.join(working_dir, "oh.out")) + Oh_molecule = Oh_gaussian_output.structures[-1] + Oh_molecule.set_charge_and_spin( + Oh_gaussian_output.charge, Oh_gaussian_output.spin_multiplicity + ) + Oh_label = get_mol_formula(Oh_molecule) + Oh_param_dict = PrmtopParser( + os.path.join(working_dir, Oh_label + ".prmtop"), Oh_molecule, "" + ).to_dict() + + # Preparing initial ff dict for species using existing ff models + # Spce parameter prep + Spce_molecule = Molecule.from_file(os.path.join(working_dir, "SPC_E.pdb")) + Spce_label = get_mol_formula(Spce_molecule) + Spce_param_dict = { + "Molecule": Spce_molecule, + "Labels": ["ow", "hw", "hw"], + "Masses": OrderedDict({"ow": 16.000, "hw": 1.008}), + "Nonbond": [[0.155394259, 3.16555789], [0.0, 0.0]], + "Bonds": [{"coeffs": [553.0, 1], "types": [("ow", "hw")]}], + "Angles": [{"coeffs": [100.0, 109.47], "types": [("hw", "ow", "hw")]}], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": [-0.8476, 0.4238, 0.4238], + } + # Na parameter prep + Na_molecule = Molecule.from_file(os.path.join(working_dir, "Na.pdb")) + Na_molecule.set_charge_and_spin(1) + Na_label = get_mol_formula(Na_molecule) + Na_param_dict = { + "Molecule": Na_molecule, + "Labels": ["na"], + "Masses": OrderedDict({"na": 22.99}), + "Nonbond": [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": [1.0], + } + + sys_ff_dict = { + Phen_type_label: Phen_type_param_dict, + Oh_label: Oh_param_dict, + Na_label: Na_param_dict, + Spce_label: Spce_param_dict, + } + + spec = {"system_force_field_dict": sys_ff_dict} + + # setting other inputs for creating the data file + x = 1.0 # Phen_type concentration + + system_mixture_data_type = "concentration" + system_mixture_data = { + "Solutes": { + Phen_type_label: { + "Initial Molarity": x, + "Final Molarity": x, + "Density": 1.25, + "Molar Weight": 180.21, + }, + Oh_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 1, + "Density": 2.13, + "Molar Weight": 17.007, + }, + Na_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 3 * x + 1, + "Density": 2.13, + "Molar Weight": 22.990, + }, + }, + "Solvents": {Spce_label: {"Density": 0.99705, "Molar Weight": 18.015}}, + } + + # other option for system_mixture_data + # system_mixture_data_type = 'number of molecules' + # system_mixture_data = {Phen_type_label: 9, + # Spce_label: 438, + # Oh_label: 9, + # Na_label: 38} + + system_box_side_length = 25.0 + position_seed = 51235 + velocity_seed = 36624 + data_filename = f"complex_from_{system_mixture_data_type}.data" + sys_mix_type = "concentration" + # sys_mix_type = "number of molecules" + sys_species_data = { + Phen_type_label: { + "molecule": Phen_type_molecule, + "ff_param_method": "get_from_prmtop", + "ff_param_data": os.path.join(working_dir, Phen_type_label + ".prmtop"), + "save_ff_to_file": True, + "save_ff_to_db": True, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": x, + "Final Molarity": x, + "Density": 1.25, + "Molar Weight": 180.21, + } + if sys_mix_type == "concentration" + else 8, + }, + Spce_label: { + "molecule": Spce_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Spce_param_dict, + "save_ff_to_file": True, + "mol_mixture_type": "Solvents", + "mixture_data": {"Density": 0.99705, "Molar Weight": 18.015} + if sys_mix_type == "concentration" + else 438, + }, + Oh_label: { + "molecule": Oh_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Oh_param_dict, + "save_ff_to_file": True, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 1, + "Density": 2.13, + "Molar Weight": 17.007, + } + if sys_mix_type == "concentration" + else 9, + }, + Na_label: { + "molecule": Na_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Na_param_dict, + "save_ff_to_file": True, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 3 * x + 1, + "Density": 2.13, + "Molar Weight": 22.990, + } + if sys_mix_type == "concentration" + else 38, + }, + } + + recipe = [ + ["emin", ["template_filename", "emin_gaff"]], + ["npt", ["template_filename", "npt"]], + ["melt", ["template_filename", "nvt"]], + ["quench", ["template_filename", "nvt"]], + ["nvt_0-20", ["template_filename", "nvt"]], + ["nvt_20-40", ["template_filename", "nvt"]], + ] + + v_seed = velocity_seed + # NEED TO CHANGE FOR EACH NEW PHEN TYPE + group_def = "\n".join( + [ + "group phen type 1 2 3 4 5 6 7", + "group wat type 8 9", + "group oh type 10 11", + "group na type 12", + ] + ) + + shake_group = "wat" + shake_top = "b 11 a 16" + timestep = 2 + dump_per = 25000 + compute_def = "\n".join( + [ + "compute P phen msd com yes", + "compute W wat msd com yes", + "compute O oh msd com yes", + "compute N na msd com yes", + ] + ) + ts_comp = "c_P[4] c_W[4] c_O[4] c_N[4]" + recipe_settings = [ + { + "data_file_name": "../complex.data", + "restart_final_name": "restart.emin.restart", + }, + { + "restart_file_name": "../emin/restart.emin.restart", + "group_definitions": group_def, + "velocity_seed": v_seed, + "shake_logic": "", + "shake_group": shake_group, + "shake_topologies": shake_top, + "thermo": 1000, + "timestep": timestep, + "dump_period": dump_per, + "restart_final_file_name": "restart.npt.restart", + "run": 1000000, + }, + { + "restart_file_name": "../npt/restart.npt.restart", + "group_definitions": group_def, + "shake_logic": "", + "shake_group": shake_group, + "shake_topologies": shake_top, + "temperature_initial": 500.0, + "temperature_final": 500.0, + "thermo": 1000, + "timestep": 1, + "dump_period": 50000, + "run": 1000000, + "restart_final_file_name": "restart.melt_500K.restart", + }, + { + "restart_file_name": "../melt/restart.melt_500K.restart", + "group_definitions": group_def, + "shake_logic": "", + "shake_group": shake_group, + "shake_topologies": shake_top, + "temperature_initial": 500.0, + "temperature_final": 298.15, + "thermo": 1000, + "timestep": timestep, + "dump_period": dump_per, + "run": 1000000, + "restart_final_file_name": "restart.quench_298-15K.restart", + }, + { + "restart_file_name": "../quench/restart.quench_298-15K.restart", + "group_definitions": group_def, + "shake_logic": "", + "shake_group": shake_group, + "shake_topologies": shake_top, + "temperature_initial": 298.15, + "temperature_final": 298.15, + "thermo": 2, + "compute_definitions": compute_def, + "thermo_style_compute": ts_comp, + "timestep": timestep, + "dump_period": dump_per, + "run": 10000000, + "restart_final_file_name": "restart.nvt_20-ns.restart", + }, + { + "restart_file_name": "../nvt_0-20/restart.nvt_20-ns.restart", + "group_definitions": group_def, + "shake_logic": "", + "shake_group": shake_group, + "shake_topologies": shake_top, + "temperature_initial": 298.15, + "temperature_final": 298.15, + "thermo": 2, + "compute_definitions": compute_def, + "thermo_style_compute": ts_comp, + "timestep": timestep, + "reset_timestep_logic": "#", + "dump_period": dump_per, + "run": 10000000, + "restart_final_file_name": "restart.nvt_40-ns.restart", + }, + ] + nodes = 2 + ntasks_node = 24 + ntasks = nodes * ntasks_node + mail_user = None + mail_type = None + partition = "rajput-24core" + + qadapter = [ + { + "queue": partition, + "walltime": "04:00:00", + "job_name": "emin", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + { + "queue": partition, + "walltime": "12:00:00", + "job_name": "npt", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + { + "queue": partition, + "walltime": "06:00:00", + "job_name": "melt", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + { + "queue": partition, + "walltime": "12:00:00", + "job_name": "quench", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + { + "queue": partition, + "walltime": "48:00:00", + "job_name": "nvt_20", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + { + "queue": partition, + "walltime": "48:00:00", + "job_name": "nvt_40", + "nodes": nodes, + "ntasks": ntasks, + "ntasks_per_node": ntasks_node, + "mail-user": mail_user, + "mail-type": mail_type, + }, + ] + + full_fws, full_links_dict = lammps_workflow( + system_species_data=sys_species_data, + system_mixture_type=sys_mix_type, + box_data=system_box_side_length, + working_dir=working_dir, + recipe=recipe, + recipe_settings=recipe_settings, + recipe_qadapter=qadapter, + save_runs_to_file=True, + ) + + print(full_links_dict) + for firework in full_fws: + print(firework) + + launchpad.add_wf(Workflow(full_fws, full_links_dict)) + rapidfire(launchpad) +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/tests/data.html b/html/_modules/mispr/lammps/tests/data.html new file mode 100644 index 00000000..b7f41cd4 --- /dev/null +++ b/html/_modules/mispr/lammps/tests/data.html @@ -0,0 +1,999 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests.data - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.tests.data

+import os
+
+from collections import OrderedDict
+
+from fireworks import LaunchPad, FiretaskBase, explicit_serialize
+
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.io.ambertools import PrmtopParser
+from pymatgen.core.structure import Molecule
+
+from mispr.gaussian.utilities.metadata import get_mol_formula
+
+
+
[docs]@explicit_serialize +class PrintFW(FiretaskBase): + """Firetask for confirming that modspec works as intended in ProcessPrmtop firetask""" + +
[docs] def run_task(self, fw_spec): + print(str(fw_spec["system_force_field_dict"]))
+ + +if __name__ == "__main__": + # set up the LaunchPad and reset it + launchpad = LaunchPad( + host="mongodb://superuser:idlewide@localhost:27017/fireworks?authSource=admin", + uri_mode=True, + ) + launchpad.reset("", require_password=False) + + working_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "test_files", "data" + ) + + # Preparing inputs for ambertools for species not using existing ff models + # # Phen_type parameter prep + Phen_type = "dhps" + Phen_type_gaussian_output = GaussianOutput( + os.path.join(working_dir, Phen_type + ".out") + ) + Phen_type_molecule = Phen_type_gaussian_output.structures[-1] + Phen_type_molecule.set_charge_and_spin( + Phen_type_gaussian_output.charge, Phen_type_gaussian_output.spin_multiplicity + ) + Phen_type_label = get_mol_formula(Phen_type_molecule) + Phen_type_param_dict = PrmtopParser( + os.path.join(working_dir, Phen_type_label + ".prmtop"), Phen_type_molecule, "" + ).to_dict() + + # # Oh parameter prep + Oh_gaussian_output = GaussianOutput(os.path.join(working_dir, "oh.out")) + Oh_molecule = Oh_gaussian_output.structures[-1] + Oh_molecule.set_charge_and_spin( + Oh_gaussian_output.charge, Oh_gaussian_output.spin_multiplicity + ) + Oh_label = get_mol_formula(Oh_molecule) + Oh_param_dict = PrmtopParser( + os.path.join(working_dir, Oh_label + ".prmtop"), Oh_molecule, "" + ).to_dict() + + # Preparing initial ff dict for species using existing ff models + # # Spce parameter prep + Spce_molecule = Molecule.from_file(os.path.join(working_dir, "SPC_E.pdb")) + Spce_label = get_mol_formula(Spce_molecule) + # Spce_param_dict = {'Molecule': Spce_molecule, + # 'Labels': ['ow' + Spce_label, 'hw' + Spce_label, 'hw' + Spce_label], + # 'Masses': OrderedDict({'ow' + Spce_label: 16.000, 'hw' + Spce_label: 1.008}), + # 'Nonbond': [[0.155394259, 3.16555789], [0.0, 0.0]], + # 'Bonds': [{'coeffs': [553.0, 1], 'types': [('ow' + Spce_label, 'hw' + Spce_label)]}], + # 'Angles': [{'coeffs': [100.0, 109.47], + # 'types': [('hw' + Spce_label, 'ow' + Spce_label, 'hw' + Spce_label)]}], + # 'Dihedrals': [], + # 'Impropers': [], + # 'Improper Topologies': None, + # 'Charges': [-0.8476, 0.4238, 0.4238]} + + Spce_param_dict = { + "Molecule": Spce_molecule, + "Labels": ["ow", "hw", "hw"], + "Masses": OrderedDict({"ow": 16.000, "hw": 1.008}), + "Nonbond": [[0.155394259, 3.16555789], [0.0, 0.0]], + "Bonds": [{"coeffs": [553.0, 1], "types": [("ow", "hw")]}], + "Angles": [{"coeffs": [100.0, 109.47], "types": [("hw", "ow", "hw")]}], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": [-0.8476, 0.4238, 0.4238], + } + + # # Na parameter prep + Na_molecule = Molecule.from_file(os.path.join(working_dir, "Na.pdb")) + Na_molecule.set_charge_and_spin(1) + Na_label = get_mol_formula(Na_molecule) + # print([Na_label]) + # Na_param_dict = {'Molecule': Na_molecule, + # 'Labels': ['na' + Na_label], + # 'Masses': OrderedDict({'na' + Na_label: 22.99}), + # 'Nonbond': [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + # 'Bonds': [], + # 'Angles': [], + # 'Dihedrals': [], + # 'Impropers': [], + # 'Improper Topologies': None, + # 'Charges': [1.0]} + + Na_param_dict = { + "Molecule": Na_molecule, + "Labels": ["na"], + "Masses": OrderedDict({"na": 22.99}), + "Nonbond": [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": [1.0], + } + + sys_ff_dict = { + Phen_type_label: Phen_type_param_dict, + Oh_label: Oh_param_dict, + Na_label: Na_param_dict, + Spce_label: Spce_param_dict, + } + + spec = {"system_force_field_dict": sys_ff_dict} + spec = {} + + # setting other inputs for creating the data file + x = 1.0 # Phen_type concentration + + system_mixture_data_type = "concentration" + system_mixture_data = { + "Solutes": { + Phen_type_label: { + "Initial Molarity": x, + "Final Molarity": x, + "Density": 1.25, + "Molar Weight": 180.21, + }, + Oh_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 1, + "Density": 2.13, + "Molar Weight": 17.007, + }, + Na_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 3 * x + 1, + "Density": 2.13, + "Molar Weight": 22.990, + }, + }, + "Solvents": {Spce_label: {"Density": 0.99705, "Molar Weight": 18.015}}, + } + + # # # other option for system_mixture_data + # system_mixture_data_type = 'number of molecules' + # system_mixture_data = {Phen_type_label: 9, + # Spce_label: 438, + # Oh_label: 9, + # Na_label: 38} + + system_box_side_length = 25.0 + + position_seed = 512454235 + + data_filename = f"complex_from_{system_mixture_data_type}.data" + + # # From this point on, there shouldn't be any need to alter the script for + # # getting gaff parameters using default methods + # + # t = [] + # + # # Check that ff parameters for all molecular species are in "system_force_field_dict" + # # t.append(PrintFW()) + # + # + # t.append(WriteDataFile(working_dir = working_dir, + # data_filename = data_filename, + # system_force_field_dict = sys_ff_dict, + # system_mixture_data = system_mixture_data, + # system_box_side_length = system_box_side_length, + # system_mixture_data_type = system_mixture_data_type, + # position_seed = position_seed)) + # + # # assemble FireWork from tasks and give the FireWork a unique id + # fire_work1 = Firework(t, spec = spec, name='MultMolFFDict', fw_id=1) + # + # # assemble Workflow from FireWorks and their connections by id + # wf = Workflow([fire_work1]) + # + # # store workflow and launch it + # launchpad.add_wf(wf) + # rapidfire(launchpad) + + sys_mix_type = "concentration" + # sys_mix_type = "number of molecules" + sys_species_data = { + Phen_type_label: { + "molecule": Phen_type_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Phen_type_param_dict, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": x, + "Final Molarity": x, + "Density": 1.25, + "Molar Weight": 180.21, + } + if sys_mix_type == "concentration" + else 8, + }, + Spce_label: { + "molecule": Spce_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Spce_param_dict, + "mol_mixture_type": "Solvents", + "mixture_data": {"Density": 0.99705, "Molar Weight": 18.015} + if sys_mix_type == "concentration" + else 438, + }, + Oh_label: { + "molecule": Oh_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Oh_param_dict, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 1, + "Density": 2.13, + "Molar Weight": 17.007, + } + if sys_mix_type == "concentration" + else 9, + }, + Na_label: { + "molecule": Na_molecule, + "ff_param_method": "get_from_dict", + "ff_param_data": Na_param_dict, + "mol_mixture_type": "Solutes", + "mixture_data": { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 3 * x + 1, + "Density": 2.13, + "Molar Weight": 22.990, + } + if sys_mix_type == "concentration" + else 38, + }, + } + + from mispr.lammps.workflows.base import lammps_data_fws + + fws, links_dict = lammps_data_fws( + sys_species_data, + sys_mix_type, + system_box_side_length, + data_filename="test_complex.data", + working_dir=working_dir, + ) + for firework in fws: + print(firework) + + # launchpad.add_wf(Workflow(fws, links_dict)) + # rapidfire(launchpad) +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/tests/esp_to_ff_dict_custom.html b/html/_modules/mispr/lammps/tests/esp_to_ff_dict_custom.html new file mode 100644 index 00000000..c43e8ba9 --- /dev/null +++ b/html/_modules/mispr/lammps/tests/esp_to_ff_dict_custom.html @@ -0,0 +1,903 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests.esp_to_ff_dict_custom - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.tests.esp_to_ff_dict_custom

+import os
+import pathlib
+
+from collections import OrderedDict
+
+import numpy as np
+
+from fireworks import Firework, Workflow, LaunchPad, FiretaskBase, explicit_serialize
+from fireworks.core.rocket_launcher import rapidfire
+
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.core.structure import Molecule
+
+from mispr.lammps.firetasks.run import RunTleap, RunParmchk, RunAntechamber
+from mispr.gaussian.utilities.metadata import get_mol_formula
+from mispr.lammps.firetasks.write_inputs import WriteTleapScript
+from mispr.lammps.firetasks.parse_outputs import ProcessPrmtop
+
+
+
[docs]@explicit_serialize +class PrintFW(FiretaskBase): + """ + Firetask for confirming that modspec works as intended in ProcessPrmtop firetask + """ + +
[docs] def run_task(self, fw_spec): + print(str(fw_spec["system_force_field_dict"]))
+ + +if __name__ == "__main__": + + # set up the LaunchPad and reset it + launchpad = LaunchPad() + launchpad.reset("", require_password=False) + + working_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "test_files", "esp_to_data" + ) + + # write inputs for initial + # Phen_type parameter prep + Phen_type = "dhps" + Phen_type_gaussian_output = GaussianOutput( + os.path.join(working_dir, Phen_type + ".out") + ) + Phen_type_molecule = Phen_type_gaussian_output.structures[-1] + Phen_type_molecule.set_charge_and_spin( + Phen_type_gaussian_output.charge, Phen_type_gaussian_output.spin_multiplicity + ) + Phen_type_label = get_mol_formula(Phen_type_molecule) + + # Oh parameter prep + Oh_gaussian_output = GaussianOutput(os.path.join(working_dir, "oh.out")) + Oh_molecule = Oh_gaussian_output.structures[-1] + Oh_molecule.set_charge_and_spin( + Oh_gaussian_output.charge, Oh_gaussian_output.spin_multiplicity + ) + Oh_label = get_mol_formula(Oh_molecule) + + # Spce parameter prep + Spce_molecule = Molecule.from_file(os.path.join(working_dir, "SPC_E.pdb")) + Spce_label = get_mol_formula(Spce_molecule) + Spce_param_dict = { + "Molecule": Spce_molecule, + "Labels": ["ow" + Spce_label, "hw" + Spce_label, "hw" + Spce_label], + "Masses": OrderedDict({"ow" + Spce_label: 16.000, "hw" + Spce_label: 1.008}), + "Nonbond": [[0.155394259, 3.16555789], [0.0, 0.0]], + "Bonds": [ + {"coeffs": [553.0, 1], "types": [("ow" + Spce_label, "hw" + Spce_label)]} + ], + "Angles": [ + { + "coeffs": [100.0, 109.47], + "types": [("hw" + Spce_label, "ow" + Spce_label, "hw" + Spce_label)], + } + ], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([-0.8476, 0.4238, 0.4238]), + } + # Na parameter prep + Na_molecule = Molecule.from_file(os.path.join(working_dir, "Na.pdb")) + Na_molecule.set_charge_and_spin(1) + Na_label = get_mol_formula(Na_molecule) + # print([Na_label]) + Na_param_dict = { + "Molecule": Na_molecule, + "Labels": ["na" + Na_label], + "Masses": OrderedDict({"na" + Na_label: 22.99}), + "Nonbond": [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([1.0]), + } + + sys_ff_dict = {Na_label: Na_param_dict, Spce_label: Spce_param_dict} + + spec = {"system_force_field_dict": sys_ff_dict} + + molecules_without_ff_parameters = [Phen_type_molecule, Oh_molecule] + esp_file_names = ["dhps.esp", "oh.esp"] + + # From this point on, there shouldn't be any need to alter the script for + # getting gaff parameters using default methods + t = [] + for i, molecule in enumerate(molecules_without_ff_parameters): + mol_label = get_mol_formula(molecule) + mol2_filename = f"{mol_label}.mol2" + frcmod_filename = f"{mol_label}.frcmod" + prmtop_filename = f"{mol_label}.prmtop" + inpcrd_filename = f"{mol_label}.inpcrd" + + esp_filename = esp_file_names[i] + esp_source_path = os.path.join(working_dir, esp_filename) + + subdir_path = os.path.join(working_dir, mol_label) + pathlib.Path(subdir_path).mkdir(parents=True, exist_ok=True) + esp_dest_path = os.path.join(subdir_path, esp_filename) + + tleap_settings = { + "mol2_file_path": os.path.join(subdir_path, mol2_filename), + "frcmod_file_path": os.path.join(subdir_path, frcmod_filename), + "prmtop_file_path": os.path.join(subdir_path, prmtop_filename), + "inpcrd_file_path": os.path.join(subdir_path, inpcrd_filename), + } + + # t.append(FileTransferTask({'files': esp_source_path, + # 'dest': esp_dest_path, + # 'mode': 'copy'})) + t.append( + RunAntechamber( + working_dir=subdir_path, + input_filename_a=esp_filename, + output_filename_a=mol2_filename, + ) + ) + t.append( + RunParmchk( + working_dir=subdir_path, + input_filename_p=mol2_filename, + output_filename_p=frcmod_filename, + ) + ) + t.append( + WriteTleapScript(working_dir=subdir_path, tleap_settings=tleap_settings) + ) + t.append(RunTleap(working_dir=subdir_path)) + t.append( + ProcessPrmtop( + working_dir=subdir_path, + molecule=molecule, + prmtop_filename=prmtop_filename, + ) + ) + + t.append(PrintFW()) + + # assemble FireWork from tasks and give the FireWork a unique id + fire_work1 = Firework(t, spec=spec, name="MultMolFFDict", fw_id=1) + + # assemble Workflow from FireWorks and their connections by id + wf = Workflow([fire_work1]) + + # store workflow and launch it + launchpad.add_wf(wf) + rapidfire(launchpad) +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/tests/esp_to_ff_dict_function.html b/html/_modules/mispr/lammps/tests/esp_to_ff_dict_function.html new file mode 100644 index 00000000..ad5019f8 --- /dev/null +++ b/html/_modules/mispr/lammps/tests/esp_to_ff_dict_function.html @@ -0,0 +1,940 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests.esp_to_ff_dict_function - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.tests.esp_to_ff_dict_function

+import os
+import pathlib
+
+from collections import OrderedDict
+
+import numpy as np
+
+from fireworks import (
+    Firework,
+    Workflow,
+    LaunchPad,
+    FiretaskBase,
+    FileTransferTask,
+    explicit_serialize,
+)
+from fireworks.core.rocket_launcher import rapidfire
+
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.core.structure import Molecule
+
+from mispr.lammps.fireworks.core import ambertools_tasks
+from mispr.gaussian.utilities.metadata import get_mol_formula
+from mispr.lammps.firetasks.write_inputs import WriteDataFile
+
+
+
[docs]@explicit_serialize +class PrintFW(FiretaskBase): + """ + Firetask for confirming that modspec works as intended in ProcessPrmtop firetask + """ + +
[docs] def run_task(self, fw_spec): + print(str(fw_spec["system_force_field_dict"]))
+ + +if __name__ == "__main__": + + # set up the LaunchPad and reset it + launchpad = LaunchPad() + launchpad.reset("", require_password=False) + + working_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "test_files", "esp_to_data" + ) + + # Preparing inputs for ambertools for species not using existing ff models + # Phen_type parameter prep + Phen_type = "dhps" + Phen_type_gaussian_output = GaussianOutput( + os.path.join(working_dir, Phen_type + ".out") + ) + Phen_type_molecule = Phen_type_gaussian_output.structures[-1] + Phen_type_molecule.set_charge_and_spin( + Phen_type_gaussian_output.charge, Phen_type_gaussian_output.spin_multiplicity + ) + Phen_type_label = get_mol_formula(Phen_type_molecule) + + # Oh parameter prep + Oh_gaussian_output = GaussianOutput(os.path.join(working_dir, "oh.out")) + Oh_molecule = Oh_gaussian_output.structures[-1] + Oh_molecule.set_charge_and_spin( + Oh_gaussian_output.charge, Oh_gaussian_output.spin_multiplicity + ) + Oh_label = get_mol_formula(Oh_molecule) + + # Preparing initial ff dict for species using existing ff models + # Spce parameter prep + Spce_molecule = Molecule.from_file(os.path.join(working_dir, "SPC_E.pdb")) + Spce_label = get_mol_formula(Spce_molecule) + Spce_param_dict = { + "Molecule": Spce_molecule, + "Labels": ["ow" + Spce_label, "hw" + Spce_label, "hw" + Spce_label], + "Masses": OrderedDict({"ow" + Spce_label: 16.000, "hw" + Spce_label: 1.008}), + "Nonbond": [[0.155394259, 3.16555789], [0.0, 0.0]], + "Bonds": [ + {"coeffs": [553.0, 1], "types": [("ow" + Spce_label, "hw" + Spce_label)]} + ], + "Angles": [ + { + "coeffs": [100.0, 109.47], + "types": [("hw" + Spce_label, "ow" + Spce_label, "hw" + Spce_label)], + } + ], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([-0.8476, 0.4238, 0.4238]), + } + # Na parameter prep + Na_molecule = Molecule.from_file(os.path.join(working_dir, "Na.pdb")) + Na_molecule.set_charge_and_spin(1) + Na_label = get_mol_formula(Na_molecule) + Na_param_dict = { + "Molecule": Na_molecule, + "Labels": ["na" + Na_label], + "Masses": OrderedDict({"na" + Na_label: 22.99}), + "Nonbond": [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([1.0]), + } + + sys_ff_dict = {Na_label: Na_param_dict, Spce_label: Spce_param_dict} + spec = {"system_force_field_dict": sys_ff_dict} + + # setting which species need ff parameters + molecules_without_ff_parameters = [Phen_type_molecule, Oh_molecule] + esp_file_names = ["dhps.esp", "oh.esp"] + + # setting other inputs for creating the data file + x = 1.0 # Phen_type concentration + + system_mixture_data_type = "concentration" + system_mixture_data = { + "Solutes": { + Phen_type_label: { + "Initial Molarity": x, + "Final Molarity": x, + "Density": 1.25, + "Molar Weight": 180.21, + }, + Oh_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 1, + "Density": 2.13, + "Molar Weight": 17.007, + }, + Na_label: { + "Initial Molarity": 3 * x + 1, + "Final Molarity": 3 * x + 1, + "Density": 2.13, + "Molar Weight": 22.990, + }, + }, + "Solvents": {Spce_label: {"Density": 0.99705, "Molar Weight": 18.015}}, + } + + # # other option for system_mixture_data + # system_mixture_data_type = 'number of molecules' + # system_mixture_data = {Phen_type_label: 9, + # Spce_label: 438, + # Oh_label: 9, + # Na_label: 38} + + system_box_side_length = 25.0 + + position_seed = 512454235 + + data_filename = f"complex_from_{system_mixture_data_type}.data" + + # From this point on, there shouldn't be any need to alter the script for + # getting gaff parameters using default methods + + t = [] + + for i, molecule in enumerate(molecules_without_ff_parameters): + mol_label = get_mol_formula(molecule) + + esp_filename = esp_file_names[i] + esp_source_path = os.path.join(working_dir, esp_filename) + + subdir_path = os.path.join(working_dir, mol_label) + pathlib.Path(subdir_path).mkdir(parents=True, exist_ok=True) + esp_dest_path = os.path.join(subdir_path, esp_filename) + + t.append( + FileTransferTask( + { + "files": [{"src": esp_source_path, "dest": esp_dest_path}], + "mode": "copy", + } + ) + ) + + t += ambertools_tasks( + input_filename=esp_file_names[i], + molecule=molecule, + working_dir=subdir_path, + file_label=mol_label, + ) + + # Check that ff parameters for all molecular species are in "system_force_field_dict" + t.append(PrintFW()) + + t.append( + WriteDataFile( + working_dir=working_dir, + data_filename=data_filename, + system_mixture_data=system_mixture_data, + system_box_side_length=system_box_side_length, + system_mixture_data_type=system_mixture_data_type, + position_seed=position_seed, + ) + ) + + # assemble FireWork from tasks and give the FireWork a unique id + fire_work1 = Firework(t, spec=spec, name="EspToDataFunc", fw_id=1) + + # assemble Workflow from FireWorks and their connections by id + wf = Workflow([fire_work1]) + + # store workflow and launch it + launchpad.add_wf(wf) + rapidfire(launchpad) +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/tests/prmtop.html b/html/_modules/mispr/lammps/tests/prmtop.html new file mode 100644 index 00000000..e976fd99 --- /dev/null +++ b/html/_modules/mispr/lammps/tests/prmtop.html @@ -0,0 +1,840 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests.prmtop - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.tests.prmtop

+import os
+
+from collections import OrderedDict
+
+import numpy as np
+
+from fireworks import Firework, Workflow, LaunchPad, FiretaskBase, explicit_serialize
+from fireworks.core.rocket_launcher import rapidfire
+
+from pymatgen.io.gaussian import GaussianOutput
+from pymatgen.core.structure import Molecule
+
+from mispr.gaussian.utilities.metadata import get_mol_formula
+from mispr.lammps.firetasks.parse_outputs import ProcessPrmtop
+
+
+
[docs]@explicit_serialize +class PrintFW(FiretaskBase): + """ + Firetask for confirming that modspec works as intended in ProcessPrmtop firetask + """ + +
[docs] def run_task(self, fw_spec): + print(str(fw_spec["system_force_field_dict"]))
+ + +if __name__ == "__main__": + + # set up the LaunchPad and reset it + launchpad = LaunchPad() + launchpad.reset("", require_password=False) + + working_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "test_files", "prmtop" + ) + + # write inputs for initial + # Phen_type parameter prep + Phen_type = "dhps" + Phen_type_gaussian_output = GaussianOutput( + os.path.join(working_dir, Phen_type + ".out") + ) + Phen_type_molecule = Phen_type_gaussian_output.structures[-1] + Phen_type_molecule.set_charge_and_spin( + Phen_type_gaussian_output.charge, Phen_type_gaussian_output.spin_multiplicity + ) + Phen_type_label = get_mol_formula(Phen_type_molecule) + # Spce parameter prep + Spce_molecule = Molecule.from_file(os.path.join(working_dir, "SPC_E.pdb")) + Spce_label = get_mol_formula(Spce_molecule) + Spce_param_dict = { + "Molecule": Spce_molecule, + "Labels": ["ow" + Spce_label, "hw" + Spce_label, "hw" + Spce_label], + "Masses": OrderedDict({"ow" + Spce_label: 16.000, "hw" + Spce_label: 1.008}), + "Nonbond": [[0.155394259, 3.16555789], [0.0, 0.0]], + "Bonds": [ + {"coeffs": [553.0, 1], "types": [("ow" + Spce_label, "hw" + Spce_label)]} + ], + "Angles": [ + { + "coeffs": [100.0, 109.47], + "types": [("hw" + Spce_label, "ow" + Spce_label, "hw" + Spce_label)], + } + ], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([-0.8476, 0.4238, 0.4238]), + } + # Na parameter prep + Na_molecule = Molecule.from_file(os.path.join(working_dir, "Na.pdb")) + Na_molecule.set_charge_and_spin(1) + Na_label = get_mol_formula(Na_molecule) + Na_param_dict = { + "Molecule": Na_molecule, + "Labels": ["na" + Na_label], + "Masses": OrderedDict({"na" + Na_label: 22.99}), + "Nonbond": [[0.02639002, 2.590733472]], # from frcmod.ions1lm_126_spce (2015) + # 'Nonbond': [[0.3526418, 2.159538]], # from frcmod.ionsjc_tip3p (2008) + "Bonds": [], + "Angles": [], + "Dihedrals": [], + "Impropers": [], + "Improper Topologies": None, + "Charges": np.asarray([1.0]), + } + + sys_ff_dict = {Na_label: Na_param_dict, Spce_label: Spce_param_dict} + + spec = {"system_force_field_dict": sys_ff_dict} + + task1 = ProcessPrmtop( + working_dir=working_dir, + molecule=Phen_type_molecule, + prmtop_filename="dhps.prmtop", + ) + + task2 = PrintFW() + + # assemble FireWork from tasks and give the FireWork a unique id + fire_work1 = Firework([task1, task2], spec=spec, name="ParsePrmtop", fw_id=1) + + # assemble Workflow from FireWorks and their connections by id + wf = Workflow([fire_work1]) + + # store workflow and launch it + launchpad.add_wf(wf) + rapidfire(launchpad) +
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/utilities/opls.html b/html/_modules/mispr/lammps/utilities/opls.html new file mode 100644 index 00000000..20e86691 --- /dev/null +++ b/html/_modules/mispr/lammps/utilities/opls.html @@ -0,0 +1,1248 @@ + + + + + + + + + + + + + + + + mispr.lammps.utilities.opls - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.utilities.opls

+# coding: utf-8
+
+
+# Implements a core class MaestroRunner for assigning force field
+# parameters on a molecule using Maestro software.
+
+import os
+import re
+import logging
+import itertools
+import subprocess
+
+from configparser import ConfigParser
+
+import pandas as pd
+
+from pymatgen.core.structure import Molecule
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+
+__author__ = "Rasha Atwi"
+__maintainer__ = "Rasha Atwi"
+__email__ = "rasha.atwi@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Aug 2022"
+__version__ = "0.0.4"
+
+logger = logging.getLogger(__name__)
+
+NONBONDED_HEADER = "OPLSAA FORCE FIELD TYPE ASSIGNED\n"
+BONDS_HEADER = (
+    " Stretch            k            r0    quality         bt        comment\n"
+)
+ANGLES_HEADER = (
+    " Bending                      k       theta0    quality   at  comment\n"
+)
+DIHEDRALS_HEADER = " proper Torsion                     V1      V2      V3      V4    quality  tt  comment\n"
+IMPROPER_HEADER = " improper Torsion                   V2    quality  comment\n"
+
+
+
[docs]class MaestroRunner: + """ + Wrapper for assigning OPLS_2005 force field parameters for a molecule using Maestro + software of Schrondinger. The OPLS_2005 parameters are described in: + + Banks, J.L.; Beard, H.S.; Cao, Y.; Cho, A.E.; Damm, W.; Farid, R.; + Felts, A.K.; Halgren, T.A.; Mainz, D.T.; Maple, J.R.; Murphy, R.; + Philipp, D.M.; Repasky, M.P.; Zhang, L.Y.; Berne, B.J.; Friesner, + R.A.; Gallicchio, E.; Levy. R.M. Integrated Modeling Program, + Applied Chemical Theory (IMPACT). J. Comp. Chem. 2005, 26, 1752. + + The OPLS_2005 parameters are located in (you need to replace the version in the path + with the correct Schrondinger version installed): + + $SCHRODINGER/mmshare-vversion/data/f14/ + + To use this class, you need to do the following: + + 1. Download the free version of Maestro (https://www.schrodinger.com/freemaestro) + 2. Install Maestro and set the environment variable $SCHRODINGER, e.g., + 'export SCHRODINGER=/opt/schrodinger/suites2022-2'. Check + https://www.schrodinger.com/kb/1842 for more details. + + """ + + def __init__(self, name, input_file, mae_cmd=None, ffld_cmd=None, working_dir=None): + """ + Args: + name (str): Name of the molecule to use when saving the mae and log files + generated by Maestro. + input_file (str): Molecule/structure file to use for converting to a mae + file. For a full list of supported formats, check + https://www.schrodinger.com/kb/1278. + mae_cmd (str): Full command to use for converting the structure format to + mae file; if not specified, will try to parse the command from the + MISPR configuration file. + ffld_cmd (str): Full command to use for generating the force field parameters + from the mae file. If not specified, will try to parse the command from + the MISPR configuration file. + working_dir (str): Working directory where the ``input_file`` is located and + Maestro files to be generated. + """ + self.name = name + self.input_file = input_file + self.mae_cmd = mae_cmd + self.ffld_cmd = ffld_cmd + self.working_dir = working_dir or os.getcwd() + + if not os.path.isabs(self.input_file): + self.input_file = f"{self.working_dir}/{self.input_file}" + +
[docs] def get_opls_params(self, cleanup=True): + """ + Wrapper function that converts input structure to mae format, uses it to + generate a log file with the force field parameters of the molecule, parses the + log file to generate a dictionary of force parameters in a format compatible + with the lammps workflow in MISPR, and optionally cleans up the working + directory by removing the intermediate files generated in the process. + + Args: + cleanup (bool): Whether to clean up the working directory. Defaults to + ``True``. + + Returns: + dict: Dictionary with force field parameters. + """ + if not self.input_file.endswith(".mae"): + self.convert_mol_to_mae() + self.get_ff_log() + cosolvent_param = self.convert_ff_log_to_json() + if cleanup: + self.cleanup() + return cosolvent_param
+ + @staticmethod + def _get_num_lines(file_): + """ + Returns the number of lines in a file. + + Args: + file_ (str): file to read + + Returns: + int + """ + return sum(1 for line in open(file_)) + + @staticmethod + def _get_footer(file_, footer_str): + """ + Returns the number of lines remaining in the file after a footer + string. + + Args: + file_ (str): file to read + footer_str (str): line to read + + Returns: + int + """ + with open(file_) as f: + g = itertools.dropwhile(lambda x: x != footer_str, f) + footer_len = len([i for i, _ in enumerate(g)]) + return footer_len + + @staticmethod + def _get_atom_type(atom_string): + """ + Finds the weight of an atom from a string representation. + + Args: + atom_string (str): atom representation, e.g. Cl1, H10, etc. + Returns: + float + """ + match = re.match(r"([a-z]+)([0-9]+)", atom_string, re.I) + if match: + items = match.groups() + mol = Molecule.from_str(f"[{items[0]}]", fmt="smi") + return mol[0].species.weight + else: + raise ValueError(f"Atom type cannot be determined from {atom_string}") + +
[docs] def convert_mol_to_mae(self): + """ + Converts a structure input file to a mae file. + """ + if not self.mae_cmd: + cfg = ConfigParser() + cfg.read(CONFIG_FILE_DIR + "/config.ini") + self.mae_cmd = cfg["MaestroCalc"]["mae_cmd"] + cmd = self.mae_cmd.replace("$input_file$", self.input_file).replace( + "$output_file$", f"{self.working_dir}/{self.name}.mae" + ) + logger.info("Running command: {}".format(cmd)) + return_code = subprocess.call(cmd, env=os.environ, shell=True) + logger.info("Finished running with return code: {}".format(return_code))
+ +
[docs] def get_ff_log(self): + """ + Generates a log file with force field parameters using a mae + file. + """ + if not self.ffld_cmd: + cfg = ConfigParser() + cfg.read(CONFIG_FILE_DIR + "/config.ini") + self.ffld_cmd = cfg["MaestroCalc"]["ffld_cmd"] + cmd = self.ffld_cmd.replace( + "$input_file$", f"{self.working_dir}/{self.name}.mae" + ).replace("$output_file$", f"{self.working_dir}/{self.name}.log") + logger.info("Running command: {}".format(cmd)) + return_code = subprocess.call(cmd, env=os.environ, shell=True) + logger.info("Finished running with return code: {}".format(return_code))
+ +
[docs] def convert_ff_log_to_json(self): + """ + Converts the force field parameters in the log file to a + dictionary format that is compatible with MISPR. + """ + log_file = f"{self.working_dir}/{self.name}.log" + num_lines = self._get_num_lines(log_file) + + # non bonded + row_skips = num_lines - self._get_footer(log_file, NONBONDED_HEADER) + 3 + footer_skips = ( + self._get_footer( + log_file, + BONDS_HEADER, + ) + + 3 + ) + nonbonded_df = pd.read_csv( + log_file, + skiprows=row_skips, + skipfooter=footer_skips, + delimiter=r"\s\s+", + comment=":", + engine="python", + keep_default_na=False, + names=[ + "atom", + "type", + "vdw", + "symbol", + "charge", + "sigma", + "epsilon", + "quality", + "comment", + ], + ).reset_index(drop=True) + + nonbonded_df = nonbonded_df.drop(0) + + df_cols = [] + for i in nonbonded_df.columns[:-1]: + if nonbonded_df[i].dtype == "object": + df_cols.append(nonbonded_df[i].str.split(expand=True)) + else: + df_cols.append(nonbonded_df[i]) + nonbonded_df = pd.concat(df_cols, axis=1, ignore_index=True) + nonbonded_df = nonbonded_df[[0, 3, 4, 5, 6]] + nonbonded_df.columns = ["Atom", "Type", "Charge", "Sigma", "Epsilon"] + labels = nonbonded_df["Type"].to_list() + charges = nonbonded_df["Charge"].to_list() + nonbonded_df_unique = nonbonded_df.drop_duplicates(subset=["Type"]).reset_index( + drop=True + ) + atoms_dict = { + i: self._get_atom_type(j) + for i, j in zip(nonbonded_df_unique["Type"], nonbonded_df_unique["Atom"]) + } + non_bonded = [ + [i, j] + for i, j in zip( + nonbonded_df_unique["Epsilon"], nonbonded_df_unique["Sigma"] + ) + ] + + # bonds + row_skips = num_lines - self._get_footer( + log_file, + BONDS_HEADER, + ) + footer_skips = self._get_footer( + log_file, + ANGLES_HEADER, + ) + bonds_df = pd.read_csv( + log_file, + skiprows=row_skips, + skipfooter=footer_skips, + delimiter=r"\s+", + engine="python", + ).reset_index() + + bond_data = [] + if not bonds_df.empty: + bonds_df = bonds_df[["quality", "comment", "level_2", "level_3"]] + df = bonds_df[["quality", "level_2", "level_3"]] + df.columns = ["comment", "level_2", "level_3"] + del bonds_df["quality"] + bonds_df = bonds_df.append(df) + bonds_df.columns = ["Bond", "K", "r"] + bonds_df = bonds_df.join( + bonds_df["Bond"] + .str.split("-", expand=True) + .rename(columns={0: "t1", 1: "t2"}) + ) + bonds_df["Bond"] = bonds_df.apply( + lambda x: "-".join( + ( + [x["t1"], x["t2"]] + if not ( + x["t1"] > x["t2"] + or (x["t1"] == x["t2"] and x["t1"] > x["t2"]) + ) + else [x["t2"], x["t1"]] + ) + ), + axis=1, + ) + bonds_df.drop(["t1", "t2"], axis=1, inplace=True) + bonds_df = bonds_df.drop_duplicates(subset=["Bond"]).reset_index(drop=True) + + for index, row in bonds_df.iterrows(): + bond_data.append( + {"coeffs": [row[1], row[2]], "types": [tuple(row[0].split("-"))]} + ) + + # angles + row_skips = num_lines - self._get_footer( + log_file, + ANGLES_HEADER, + ) + footer_skips = self._get_footer( + log_file, + DIHEDRALS_HEADER, + ) + angles_df = pd.read_csv( + log_file, + skiprows=row_skips, + skipfooter=footer_skips, + delimiter=r"\s+", + engine="python", + ).reset_index() + + angle_data = [] + if not angles_df.empty: + angles_df = angles_df[["quality", "comment", "level_3", "Bending"]] + df = angles_df[["quality", "level_3", "Bending"]] + df.columns = ["comment", "level_3", "Bending"] + del angles_df["quality"] + angles_df = angles_df.append(df) + angles_df.columns = ["Angle", "K", "Theta"] + angles_df = angles_df.join( + angles_df["Angle"] + .str.split("-", expand=True) + .rename(columns={0: "t1", 1: "t2", 2: "t3"}) + ) + angles_df = angles_df.loc[ + (angles_df["t1"].isin(atoms_dict.keys())) + & (angles_df["t2"].isin(atoms_dict.keys())) + & (angles_df["t3"].isin(atoms_dict.keys())) + ] + angles_df["Angle"] = angles_df.apply( + lambda x: "-".join( + ( + [x["t1"], x["t2"], x["t3"]] + if not ( + x["t1"] > x["t3"] + or (x["t1"] == x["t3"] and x["t1"] > x["t3"]) + ) + else [x["t3"], x["t2"], x["t1"]] + ) + ), + axis=1, + ) + angles_df.drop(["t1", "t2", "t3"], axis=1, inplace=True) + angles_df = angles_df.drop_duplicates(subset=["Angle"]).reset_index( + drop=True + ) + + for index, row in angles_df.iterrows(): + angle_data.append( + {"coeffs": [row[1], row[2]], "types": [tuple(row[0].split("-"))]} + ) + + # dihedrals + row_skips = num_lines - self._get_footer( + log_file, + DIHEDRALS_HEADER, + ) + footer_skips = self._get_footer( + log_file, + IMPROPER_HEADER, + ) + dihedrals_df = pd.read_csv( + log_file, + skiprows=row_skips, + skipfooter=footer_skips, + delimiter=r"\s+", + engine="python", + ).reset_index() + + dihedral_data = [] + if not dihedrals_df.empty: + dihedrals_df = dihedrals_df[ + ["quality", "comment", "proper", "Torsion", "V1", "V2"] + ] + df = dihedrals_df[["quality", "proper", "Torsion", "V1", "V2"]] + df.columns = ["comment", "proper", "Torsion", "V1", "V2"] + del dihedrals_df["quality"] + dihedrals_df = dihedrals_df.append(df) + dihedrals_df.columns = ["Dihedral", "V1", "V2", "V3", "V4"] + dihedrals_df = dihedrals_df.join( + dihedrals_df["Dihedral"] + .str.split("-", expand=True) + .rename(columns={0: "t1", 1: "t2", 2: "t3", 3: "t4"}) + ) + dihedrals_df = dihedrals_df.loc[ + (dihedrals_df["t1"].isin(atoms_dict.keys())) + & (dihedrals_df["t2"].isin(atoms_dict.keys())) + & (dihedrals_df["t3"].isin(atoms_dict.keys())) + & (dihedrals_df["t4"].isin(atoms_dict.keys())) + ] + dihedrals_df["Dihedral"] = dihedrals_df.apply( + lambda x: "-".join( + ( + [x["t1"], x["t2"], x["t3"], x["t4"]] + if not ( + x["t1"] > x["t4"] + or (x["t1"] == x["t4"] and x["t1"] > x["t4"]) + ) + else [x["t4"], x["t3"], x["t2"], x["t1"]] + ) + ), + axis=1, + ) + dihedrals_df.drop(["t1", "t2", "t3", "t4"], axis=1, inplace=True) + dihedrals_df[["V1", "V2", "V3", "V4"]] = ( + dihedrals_df[["V1", "V2", "V3", "V4"]] / 2 + ) + dihedrals_df = dihedrals_df.drop_duplicates( + subset=["Dihedral"] + ).reset_index(drop=True) + + for index, row in dihedrals_df.iterrows(): + dihedral_data.append( + { + "coeffs": [ + row[i] for i in range(len(dihedrals_df.columns) - 1) + ], + "types": [tuple(row[0].split("-"))], + } + ) + mapping = {0: [1, 0], 1: [2, 180], 2: [3, 0]} + for i in range(len(dihedral_data)): + list_ = dihedral_data[i]["coeffs"][1:] + data = [i for i, e in enumerate(list_) if e != 0] + if not data: + data = [0] + dihedrals = [[list_[i]] + mapping[i] for i in data] + dihedrals = [item for sublist in dihedrals for item in sublist] + dihedral_data[i]["coeffs"] = ["fourier", len(data)] + dihedrals + + # impropers + row_skips = num_lines - self._get_footer(log_file, IMPROPER_HEADER) + improper_data = [] + improper_top_data = [] + + if num_lines > row_skips: + improper_df = pd.read_csv( + log_file, skiprows=row_skips, delimiter=r"\s\s+", engine="python" + ).reset_index() + if not improper_df.empty: + improper_df = improper_df[ + ["level_0", "level_1", "level_2", "improper Torsion", "V2"] + ].copy() + + df = nonbonded_df.reset_index() + improper_top_df = improper_df.copy() + improper_top_df.replace( + df[["Atom", "index"]].set_index("Atom").squeeze().to_dict(), + inplace=True, + ) + improper_top_data = improper_top_df[ + ["level_0", "level_1", "level_2", "improper Torsion"] + ].values.tolist() + + improper_df.replace( + nonbonded_df[["Atom", "Type"]] + .set_index("Atom") + .squeeze() + .to_dict(), + inplace=True, + ) + + improper_df.drop_duplicates( + subset=["level_0", "level_1", "level_2", "improper Torsion"], + keep="last", + inplace=True, + ) + for index, row in improper_df.iterrows(): + improper_data.append( + { + "coeffs": ["cvff", row[-1] / 2, -1, 2], + "types": [ + tuple( + row[i] for i in range(len(improper_df.columns) - 1) + ) + ], + } + ) + + logger.info("Finished converting OPLS parameters to MISPR format") + + ff_params = { + "Labels": labels, + "Masses": atoms_dict, + "Nonbond": non_bonded, + "Bonds": bond_data, + "Angles": angle_data, + "Dihedrals": dihedral_data, + "Impropers": improper_data, + "Improper Topologies": [[i - 1 for i in j] for j in improper_top_data if j], + "Charges": charges, + } + return ff_params
+ +
[docs] def cleanup(self): + """ + Deletes the log and mae files created by Maestro + """ + for ext in ["log", "mae"]: + os.remove(f"{self.working_dir}/{self.name}.{ext}")
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/utilities/utilities.html b/html/_modules/mispr/lammps/utilities/utilities.html new file mode 100644 index 00000000..c2d20855 --- /dev/null +++ b/html/_modules/mispr/lammps/utilities/utilities.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + + + + mispr.lammps.utilities.utilities - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.utilities.utilities

+# coding: utf-8
+
+
+# Defines lammps utility functions.
+
+import os
+import json
+import math
+
+from collections import OrderedDict
+
+from fireworks.fw_config import CONFIG_FILE_DIR
+
+from mispr.gaussian.utilities.metadata import get_chem_schema
+from mispr.gaussian.utilities.fw_utilities import get_list_fireworks_and_tasks
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+
+
[docs]def add_ff_labels_to_BADI_lists(ff_list, label): + """ + Add extra string to the end of all atom type labels in lists containing information + about Bonds, Angles, Dihedrals, or Impropers (BADI). This function is intended to be + used through the ``add_ff_labels_to_dict``. + + Args: + ff_list (List): The value from ``ff_dict`` using one of the following keys: + 'Bonds', 'Angles', 'Dihedrals', or 'Impropers'. The form of this list + should be as follows: + + .. code-block:: python + + [{'coeffs': [Float, ...], 'types': [(Str, ...), ...]}, ...] + + label (str): A label for the molecular species that is unique for the system + being created. + """ + output_badi_list = [] + for dict_ in ff_list: + new_types = [] + for type in dict_["types"]: + new_types.append(tuple(atom + label for atom in type)) + output_badi_list.append({"coeffs": dict_["coeffs"], "types": new_types}) + return output_badi_list
+ + +
[docs]def add_ff_labels_to_dict(ff_dict, label): + """ + Args: + ff_dict: A dictionary containing the force field information for a molecule. + The dictionary should have the following form: + + .. code-block:: python + + { + "Molecule": pmg.Molecule, + "Labels": List, + "Masses": OrderedDict, + "Nonbond": List, + "Bonds": [{'coeffs': [a, b], 'types': [('x1', 'x2'), ...]}, ...], + "Angles": [{'coeffs': [a, b], 'types': [('x1', 'x2', 'x3'), ...]}, ...], + "Dihedrals": [{'coeffs': [a, b, c], 'types': [('x1', 'x2', 'x3', 'x4), ...]}, ...], + "Impropers": [{'coeffs': [a, b, c], 'types': [('x1', 'x2', 'x3', 'x4), ...]}, ...], + "Improper Topologies": List, + "Charges": np.Array, + ... + } + + label (str): + """ + output_labels = [old_label + label for old_label in ff_dict["Labels"]] + + output_masses = OrderedDict() + for atom_type, mass in ff_dict["Masses"].items(): + output_masses[atom_type + label] = mass + + output_bonds = add_ff_labels_to_BADI_lists(ff_dict["Bonds"], label) + output_angles = add_ff_labels_to_BADI_lists(ff_dict["Angles"], label) + output_dihedrals = add_ff_labels_to_BADI_lists(ff_dict["Dihedrals"], label) + output_impropers = add_ff_labels_to_BADI_lists(ff_dict["Impropers"], label) + + output_ff_dict = { + "Molecule": ff_dict["Molecule"], + "Labels": output_labels, + "Masses": output_masses, + "Nonbond": ff_dict["Nonbond"], + "Bonds": output_bonds, + "Angles": output_angles, + "Dihedrals": output_dihedrals, + "Impropers": output_impropers, + "Improper Topologies": ff_dict["Improper Topologies"], + "Charges": ff_dict["Charges"], + } + return output_ff_dict
+ + +
[docs]def get_db(input_db=None): + from mispr.lammps.database import LammpsSysDb + + if not input_db: + input_db = f"{CONFIG_FILE_DIR}/db.json" + if not os.path.isfile(input_db): + raise FileNotFoundError("Please provide the database configurations") + if isinstance(input_db, dict): + db = LammpsSysDb(**input_db) + else: + db = LammpsSysDb.from_db_file(input_db) + return db
+ + +
[docs]def process_ff_doc(parameter_dict, method=None, doi=None, **kwargs): + mol = parameter_dict.pop("Molecule") + ff_dict = get_chem_schema(mol) + ff_dict.update(parameter_dict) + ff_dict["method"] = method + ff_dict["doi"] = doi + ff_dict.update(kwargs) + return ff_dict
+ + +
[docs]def process_run(smiles, nmols, box, template_filename, control_settings=None): + if box is not None: + box_setting = box.as_dict() + else: + box_setting = {} + run_dict = { + "smiles": smiles, + "nmols": nmols, + "box": box_setting, + "job_type": template_filename, + "control_settings": control_settings, + } + return run_dict
+ + +
[docs]def run_fake_lammps(workflow, ref_dirs, control_filenames=None): + from mispr.lammps.firetasks.run import RunLammpsFake + + list_fireworks_and_tasks = get_list_fireworks_and_tasks( + workflow, task_substring=["RunLammps"] + ) + if not control_filenames: + control_filenames = ["complex.lammpsin"] * len(ref_dirs) + + for ind, (i_firework, i_task) in enumerate(list_fireworks_and_tasks): + workflow.fws[i_firework].tasks[i_task] = RunLammpsFake( + ref_dir=ref_dirs[ind], control_filename=control_filenames[ind] + ) + return workflow
+ + +
[docs]def lammps_mass_to_element(lammps_masses): + """ + Create a dict for mapping atom mass to element. + + Args: + lammps_masses (list): List of masses in lammps units. + + Returns: + dict + """ + with open(os.path.join(os.path.dirname(__file__), "../data/masses.json")) as f: + masses = json.load(f) + + elements = ["X"] * len(lammps_masses) + for ind, mass in enumerate(lammps_masses): + for item in masses.items(): + if math.isclose(mass, item[1], abs_tol=0.01): + elements[ind] = item[0] + return elements
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_modules/mispr/lammps/workflows/base.html b/html/_modules/mispr/lammps/workflows/base.html new file mode 100644 index 00000000..68cad690 --- /dev/null +++ b/html/_modules/mispr/lammps/workflows/base.html @@ -0,0 +1,1285 @@ + + + + + + + + + + + + + + + + mispr.lammps.workflows.base - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Source code for mispr.lammps.workflows.base

+# coding: utf-8
+
+
+# Defines standard lammps workflows.
+
+import os
+
+from fireworks.core.firework import Firework, Workflow
+
+from mispr.lammps.defaults import (
+    NPT_SETTINGS,
+    NVT_SETTINGS,
+    EMIN_SETTINGS,
+    LAMMPS_RECIPE,
+    RECIPE_SETTINGS,
+    GENERAL_QADAPTER,
+    QADAPTER_RUN_LAMMPS_SPEC,
+)
+from mispr.lammps.fireworks.core import GetFFDictFW, RunLammpsFW
+from mispr.gaussian.utilities.files import recursive_relative_to_absolute_path
+from mispr.gaussian.workflows.base.core import _process_mol_check
+from mispr.lammps.firetasks.write_inputs import WriteDataFile
+from mispr.lammps.firetasks.parse_outputs import (
+    CalcCN,
+    GetRDF,
+    CalcDiff,
+    ExtractClusters,
+    ProcessAnalysis,
+)
+
+__author__ = "Matthew Bliss"
+__maintainer__ = "Matthew Bliss"
+__email__ = "matthew.bliss@stonybrook.edu"
+__status__ = "Development"
+__date__ = "Apr 2020"
+__version__ = "0.0.4"
+
+
+
[docs]def lammps_data_fws( + system_species_data, + system_mixture_type, + box_data, + box_data_type="cubic", + data_file_name="complex.data", + working_dir=None, + db=None, + tag="unknown", + **kwargs, +): + """ + Generate FireWorks for writing LAMMPS data files. + + Args: + system_species_data (dict): Dictionary containing species data. The keys are the + species labels and the values are dictionaries containing the following keys: + + * molecule (Molecule, GaussianOutput, str, dict): Source of the molecule to + be processed. See ``process_mol`` in ``mispr/gaussian/utilities/mol.py`` + for supported operations. + * molecule_operation_type (str): Type of molecule operation. Must match with + ``molecule`` value. + * ff_param_method (str): Method for obtaining force field parameters. Must + match with ``ff_param_data`` value. See available methods for ``GetFFDictFw`` + in ``mispr/lammps/fireworks/core.py``. + * ff_param_data (str or dict): Data regarding necessary information to obtain + ff parameters. Must match with ``ff_param_method`` value. + * mol_mixture_type (str): Type of mixture data. Must be "Solutes" or "Solvents". + * mixture_data (int or dict): Information regarding the number of molecules + of this type in the system. Depends on the ``system_mixture_type`` parameter. + + system_mixture_type (str): Type of mixture data. Must be "concentration" or + "number of molecules". See ``LammpsDataWrapper`` in + ``pymatgen/io/lammps/data.py`` for more information. + box_data (float, int, list (3,2), array (3,2), or LammpsBox): Definitions for + box size. See ``box_data_type`` for info how to define this parameter. + box_data_type (str, optional): Determines the value of the ``box_data`` parameter. + Can be one of the following: 'cubic', 'rectangular', or 'LammpsBox'. If + 'cubic', ``box_data`` must be a float or int; if 'rectangular', ``box_data`` + must be an array-like with size (3,2); if 'LammpsBox', ``box_data`` must be + a ``LammpsBox`` object. Defaults to 'cubic'. + data_file_name (str, optional): Name of the data file to be written. Defaults to + "complex.data". + working_dir (str, optional): Directory where the data files will be written. + Defaults to the current working directory. + db (str or dict, optional): Database credentials. Could be a string with the path + to the database file or a dictionary with the database credentials. If none + is provided, attempts to read the configuration files. Only used when + ``save_ff_to_db`` is ``True``. + tag (str, optional): Tag for the Fireworks. Defaults to "unknown". + kwargs (keyword arguments): Additional keyword arguments. + + Returns: + fireworks (list): List of FireWorks for writing LAMMPS data files. + """ + if not working_dir: + working_dir = os.getcwd() + + fireworks = [] + system_mixture_data = {} + + if system_mixture_type == "concentration": + system_mixture_data = {"Solutes": {}, "Solvents": {}} + + for label, ff_data in system_species_data.items(): + # Generate ff files in separate directories + mol = recursive_relative_to_absolute_path(ff_data["molecule"], working_dir) + ff_data["ff_param_data"] = recursive_relative_to_absolute_path( + ff_data["ff_param_data"], working_dir + ) + mol_charge = ff_data.get("charge", None) + mol_operation_type, mol, label, _, _, _ = _process_mol_check( + working_dir=working_dir, + mol_operation_type=ff_data["molecule_operation_type"], + mol=mol, + mol_name=label, + db=db, + charge=mol_charge, + process_mol_func=kwargs.get("process_mol_func", False), + ) + # TODO: add logic for ensuring that directory name is legal or at \ + # least usable + cur_species_dir = os.path.join(working_dir, label) + + # TODO: add logic for not setting file names that do not exist, \ + # but code should work as is + mol2_filename = f"{label}.mol2" + frcmod_filename = f"{label}.frcmod" + prmtop_filename = f"{label}.prmtop" + inpcrd_filename = f"{label}.inpcrd" + + save_ff_to_db = ff_data.get("save_ff_to_db") + save_ff_to_file = ff_data.get("save_ff_to_file") + + ff_fw = GetFFDictFW( + mol=mol, + mol_operation_type=mol_operation_type, + data=ff_data["ff_param_data"], + operation_type=ff_data["ff_param_method"], + label=label, + db=db, + working_dir=cur_species_dir, + output_filename_a=mol2_filename, + input_filename_p=mol2_filename, + output_filename_p=frcmod_filename, + prmtop_filename=prmtop_filename, + save_ff_to_db=save_ff_to_db, + save_ff_to_file=save_ff_to_file, + tleap_settings={ + "mol2_file_path": os.path.join(cur_species_dir, mol2_filename), + "frcmod_file_path": os.path.join(cur_species_dir, frcmod_filename), + "prmtop_file_path": os.path.join(cur_species_dir, prmtop_filename), + "inpcrd_file_path": os.path.join(cur_species_dir, inpcrd_filename), + }, + charge=mol_charge, + **kwargs, + ) + fireworks.append(ff_fw) + + if system_mixture_type == "concentration": + system_mixture_data[ff_data["mol_mixture_type"]][label] = ff_data[ + "mixture_data" + ] + elif system_mixture_type == "number of molecules": + system_mixture_data[label] = ff_data["mixture_data"] + + spec = kwargs.pop("spec", {}) + spec.update({"tag": tag, "_launch_dir": working_dir}) + extra_data_file_name = kwargs.pop("data_filename", "") + data_fw = Firework( + [ + WriteDataFile( + working_dir=working_dir, + data_filename=data_file_name, + system_mixture_data_type=system_mixture_type, + system_mixture_data=system_mixture_data, + system_box_data=box_data, + system_box_data_type=box_data_type, + **{ + i: j + for i, j in kwargs.items() + if i + in WriteDataFile.required_params + WriteDataFile.optional_params + }, + ) + ], + name="write_data_file", + parents=fireworks[-1], + spec=spec, + ) + fireworks.append(data_fw) + return fireworks
+ + +
[docs]def lammps_run_fws( + recipe=LAMMPS_RECIPE, + recipe_settings=RECIPE_SETTINGS, + recipe_qadapter=QADAPTER_RUN_LAMMPS_SPEC, + init_spec=None, + db=None, + working_dir=None, + save_runs_to_db=True, + save_runs_to_file=False, + **kwargs, +): + """ + Generate FireWorks for running LAMMPS simulations. + + Args: + recipe (list, optional): List of lists containing the name of the step and the + template filename or string for the LAMMPS input file. Defaults to + LAMMPS_RECIPE. + recipe_settings (list, optional): List of dictionaries containing the settings + for each step in the recipe. Defaults to RECIPE_SETTINGS. + recipe_qadapter (list, optional): List of dictionaries containing the settings + for the queue adapter for each step in the recipe. Defaults to + QADAPTER_RUN_LAMMPS_SPEC. + init_spec (dict, optional): Initial spec for the FireWorks. Defaults to ``None``. + db (str or dict, optional): Database credentials. Could be a string with the path + to the database file or a dictionary with the database credentials. If none + is provided, attempts to read the configuration files. Only used when + ``save_runs_to_db`` is ``True``. + working_dir (str, optional): Directory where the data files will be written. + Defaults to the current working directory. + save_runs_to_db (bool, optional): Whether to save the runs to the database. + Defaults to ``True``. + save_runs_to_file (bool, optional): Whether to save the runs to a file. Defaults + to ``False``. + kwargs (keyword arguments): Additional keyword arguments. + + Returns: + fireworks( list): List of FireWorks for running LAMMPS simulations. + """ + + if not working_dir: + working_dir = os.getcwd() + + fireworks = [] + + default_recipe_step_names = [step[0] for step in LAMMPS_RECIPE] + + for index, step in enumerate(recipe): + cur_step_dir = os.path.join(working_dir, step[0]) + lammpsin_key = f"run_{index}" + matching_default_step_index = None + if step[0] in default_recipe_step_names: + matching_default_step_index = default_recipe_step_names.index(step[0]) + cur_qadapter_spec = QADAPTER_RUN_LAMMPS_SPEC[ + matching_default_step_index + ].copy() + else: + cur_qadapter_spec = GENERAL_QADAPTER.copy() + cur_qadapter_spec.update(recipe_qadapter[index]) + + cur_spec_dict = {} + if index == 0 and init_spec is not None: + cur_spec_dict = init_spec.copy() + cur_spec_dict.update({"_queueadapter": cur_qadapter_spec}) + + if step[1][0] == "template_filename": + if step[1][1] == "emin_gaff" or step[1][1] == "emin": + cur_setting = EMIN_SETTINGS.copy() + elif step[1][1] == "npt": + cur_setting = NPT_SETTINGS.copy() + elif step[1][1] == "nvt": + cur_setting = NVT_SETTINGS.copy() + else: + cur_setting = recipe_settings[index].copy() + cur_setting.update(recipe_settings[index]) + + cur_firework = RunLammpsFW( + working_dir=cur_step_dir, + db=db, + template_filename=step[1][1], + control_settings=cur_setting, + spec=cur_spec_dict, + save_run_to_db=save_runs_to_db, + save_run_to_file=save_runs_to_file, + lammpsin_key=lammpsin_key, + **kwargs, + ) + fireworks.append(cur_firework) + elif step[1][0] == "template_str": + cur_setting = recipe_settings[index] + cur_firework = RunLammpsFW( + working_dir=cur_step_dir, + template_str=step[1][1], + control_settings=cur_setting, + db=db, + lammpsin_key=lammpsin_key, + spec=cur_spec_dict, + **kwargs, + ) + fireworks.append(cur_firework) + return fireworks
+ + +
[docs]def lammps_analysis_fws(analysis_list, analysis_settings, working_dir, **kwargs): + """ + Generate FireWorks for running LAMMPS analysis. + + Args: + analysis_list (list): List of analysis types to perform. Supported types are: + 'diffusion', 'rdf', 'cn', and 'clusters'. + analysis_settings (list): List of dictionaries containing the settings for each + analysis type. + working_dir (str): Directory where the data files will be written. + kwargs (keyword arguments): Additional keyword arguments. + + Returns: + fireworks (list): List of FireWorks for running LAMMPS analysis. + links_dict (dict): Dictionary containing the links between the FireWorks. + """ + fireworks = [] + links_dict = {} + analysis_fw_ids = {} + analysis_dir = os.path.join(working_dir, "analysis") + + if len(analysis_list) != len(analysis_settings): + raise ValueError( + f"{len(analysis_list)} types of analysis are requested while " + f"{len(analysis_settings)} types of analysis settings are " + f"provided" + ) + + for index, analysis in enumerate(analysis_list): + cur_settings = analysis_settings[index] + if analysis == "diffusion": + diff_dir = os.path.join(analysis_dir, "diff") + name = "diffusion_analysis" + cur_settings.update( + { + "outputs_dir": os.path.abspath( + os.path.join(diff_dir, "..", "..", "nvt") + ) + } + ) + cur_firework = Firework( + CalcDiff(diff_settings=cur_settings, working_dir=diff_dir), + name=name, + spec={"_launch_dir": diff_dir}, + ) + fireworks.append(cur_firework) + + elif analysis == "rdf": + rdf_dir = os.path.join(analysis_dir, "rdf") + name = "rdf_analysis" + cur_settings.update( + { + "filename": os.path.abspath( + os.path.join(rdf_dir, "..", "..", "nvt", "dump.nvt.*.dump") + ) + } + ) + cur_firework = Firework( + GetRDF(rdf_settings=cur_settings, working_dir=rdf_dir), + name=name, + spec={"_launch_dir": rdf_dir}, + ) + fireworks.append(cur_firework) + + elif analysis == "cn": + cn_dir = os.path.join(analysis_dir, "cn") + name = "cn_analysis" + cur_settings.update( + { + "filename": os.path.abspath( + os.path.join(cn_dir, "..", "..", "nvt", "dump.nvt.*.dump") + ) + } + ) + cur_firework = Firework( + CalcCN(cn_settings=cur_settings, working_dir=cn_dir), + name=name, + spec={"_launch_dir": cn_dir}, + ) + fireworks.append(cur_firework) + + elif analysis == "clusters": + clusters_dir = os.path.join(analysis_dir, "clusters") + name = "cluster_analysis" + cur_settings.update( + { + "filename": os.path.abspath( + os.path.join(clusters_dir, "..", "..", "nvt", "dump.nvt.*.dump") + ) + } + ) + cur_firework = Firework( + ExtractClusters( + cluster_settings=cur_settings, working_dir=clusters_dir + ), + name=name, + spec={"_launch_dir": clusters_dir}, + ) + fireworks.append(cur_firework) + + else: + raise ValueError(f"Unsupported analysis type: {analysis}") + + analysis_fw_ids[name] = [cur_firework.fw_id, cur_settings] + + if "cn_analysis" in analysis_fw_ids: + if "r_cut" not in analysis_fw_ids["cn_analysis"][1]: + if "rdf_analysis" not in analysis_fw_ids: + raise ValueError( + "Cutoff distance required for calculating the CN is " + "not found and cannot be computed without performing " + "an RDF analysis" + ) + else: + links_dict[analysis_fw_ids["rdf_analysis"][0]] = analysis_fw_ids[ + "cn_analysis" + ][0] + if "cluster_analysis" in analysis_fw_ids: + if "r_cut" not in analysis_fw_ids["cluster_analysis"][1]: + links_dict[analysis_fw_ids["cn_analysis"][0]] = analysis_fw_ids[ + "cluster_analysis" + ][0] + + if "cluster_analysis" in analysis_fw_ids and "cn_analysis" not in analysis_fw_ids: + if "r_cut" not in analysis_fw_ids["cluster_analysis"][1]: + raise ValueError( + "Cutoff distance required for extracting clusters is " + "not found and cannot be computed without performing " + "a CN analysis" + ) + + final_analysis_fw = Firework( + ProcessAnalysis( + analysis_list=analysis_list, + working_dir=analysis_dir, + **{ + i: j + for i, j in kwargs.items() + if i + in ProcessAnalysis.required_params + ProcessAnalysis.optional_params + }, + ), + parents=fireworks[:], + name="analysis_postprocessing", + spec={"_launch_dir": analysis_dir}, + ) + fireworks.append(final_analysis_fw) + return fireworks, links_dict
+ + +
[docs]def lammps_workflow( + system_species_data=None, + system_mixture_type=None, + box_data=None, + box_data_type="cubic", + data_file_name="data.mixture", + recipe=LAMMPS_RECIPE, + recipe_settings=RECIPE_SETTINGS, + recipe_qadapter=QADAPTER_RUN_LAMMPS_SPEC, + db=None, + working_dir=None, + analysis_list=None, + analysis_settings=None, + name="lammps_workflow", + **kwargs, +): + """ + Create a LAMMPS workflow. + + Args: + system_species_data (dict, optional): Dictionary containing species data. Refer + to the ``lammps_data_fws`` function for more information. Defaults to + ``None``. If not provided, the workflow will not create any FireWorks for + writing LAMMPS data files. + system_mixture_type (str): Type of mixture data. Must be "concentration" or + "number of molecules". See ``LammpsDataWrapper`` in + ``pymatgen/io/lammps/data.py`` for more information. Defaults to ``None``. + If not provided, the workflow will not create any FireWorks for writing + LAMMPS data files. + box_data (float, int, list (3,2), array (3,2), or LammpsBox): Definitions for + box size. See ``lammps_data_fws`` for info on how to define this parameter. + Defaults to ``None``. If not provided, the workflow will not create any + FireWorks for writing LAMMPS data files. + box_data_type (str, optional): Determines the value of the ``box_data`` + parameter. Defaults to 'cubic'. + data_file_name (str, optional): Name of the data file to be written. Defaults + to 'data.mixture'. + recipe (list, optional): List of lists containing the name of the step and the + template filename or string for the LAMMPS input file. Defaults to + LAMMPS_RECIPE. + recipe_settings (list, optional): List of dictionaries containing the settings + for each step in the recipe. Defaults to RECIPE_SETTINGS. + recipe_qadapter (list, optional): List of dictionaries containing the settings + for the queue adapter for each step in the recipe. Defaults to + QADAPTER_RUN_LAMMPS_SPEC. + db (str or dict, optional): Database credentials. Could be a string with the + path to the database file or a dictionary with the database credentials. + If none is provided, attempts to read the configuration files. Only used when + ``save_runs_to_db`` is ``True``. Defaults to ``None``. + working_dir (str, optional): Directory where the data files will be written. + Defaults to the current working directory. + analysis_list (list, optional): List of analysis types to perform. Supported + types are: 'diffusion', 'rdf', 'cn', and 'clusters'. Defaults to ``None``. + If not provided, the workflow will not create any FireWorks for running + LAMMPS analysis. + analysis_settings (list, optional): List of dictionaries containing the settings + for each analysis type. Defaults to ``None``. If not provided, the workflow + will not create any FireWorks for running LAMMPS analysis. + name (str, optional): Name of the workflow. Defaults to 'lammps_workflow'. + kwargs (keyword arguments): Additional keyword arguments. + + Returns: + Workflow + """ + + if not working_dir: + working_dir = os.getcwd() + + fireworks = [] + links_dict = {} + if all([system_species_data, system_mixture_type, box_data]): + data_fws = lammps_data_fws( + system_species_data, + system_mixture_type, + box_data, + box_data_type=box_data_type, + data_file_name=data_file_name, + working_dir=working_dir, + db=db, + **kwargs, + ) + fireworks += data_fws + + run_fws = lammps_run_fws( + recipe=recipe, + recipe_settings=recipe_settings, + recipe_qadapter=recipe_qadapter, + db=db, + working_dir=working_dir, + **kwargs, + ) + fireworks += run_fws + + for index, fw in enumerate(fireworks[:-1]): + links_dict[fw.fw_id] = fireworks[index + 1].fw_id + + if analysis_list: + if not analysis_settings: + analysis_settings = [{}] * len(analysis_list) + analysis_fws, analysis_links_dict = lammps_analysis_fws( + analysis_list, analysis_settings, working_dir=working_dir, **kwargs + ) + links_dict[fireworks[-1].fw_id] = [i.fw_id for i in analysis_fws] + fireworks += analysis_fws + links_dict.update(analysis_links_dict) + + return Workflow(fireworks, links_dict=links_dict, name=name)
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/_sources/changelog.rst.txt b/html/_sources/changelog.rst.txt new file mode 100644 index 00000000..04e530a4 --- /dev/null +++ b/html/_sources/changelog.rst.txt @@ -0,0 +1,15 @@ +========= +Changelog +========= + +**v0.0.1** + +* Initial release (R. Atwi and M. Bliss) + +**v0.0.4** + +* Support for retrieving molecules from pubchem directly and using them in the workflows +* Support for OPLS 2005 ff by running Maestro in the backend +* Option for charge scaling of ionic species when preparing the lammps data file +* Automatic identification of system element types when creating dump files in lammps simulations +* Addition of MDPropTools package for analysis of MD trajectories as dependency \ No newline at end of file diff --git a/html/_sources/citing.rst.txt b/html/_sources/citing.rst.txt new file mode 100644 index 00000000..62f5ed50 --- /dev/null +++ b/html/_sources/citing.rst.txt @@ -0,0 +1,33 @@ +=============================== +Citing MISPR +=============================== +If you find MISPR useful in your research, please consider citing the following papers: + +**Paper 1 (MISPR):** + +.. code-block:: bibtex + + @article{atwi2022mispr, + title = {MISPR: An automated infrastructure for high-throughput DFT and MD simulations}, + author = {Atwi, Rasha and Bliss, Matthew and Makeev, Maxim and Rajput, Nav Nidhi}, + year = {2022} + } + +Download as :download:`BibTeX <_static/mispr_citation.bib>` + +**Paper 2 (Hybrid NMR Workflow):** + +.. code-block:: bibtex + + @article{atwi2022automated, + title = {An automated framework for high-throughput predictions of NMR chemical shifts within liquid solutions}, + author = {Atwi, Rasha and Chen, Ying and Han, Kee Sung and Mueller, Karl T and Murugesan, Vijayakumar and Rajput, Nav Nidhi}, + journal = {Nature Computational Science}, + volume = {2}, + number = {2}, + pages = {112--122}, + year = {2022}, + publisher = {Nature Publishing Group} + } + +Download as :download:`BibTeX <_static/nmr_citation.bib>` \ No newline at end of file diff --git a/html/_sources/index.rst.txt b/html/_sources/index.rst.txt new file mode 100644 index 00000000..75c74c72 --- /dev/null +++ b/html/_sources/index.rst.txt @@ -0,0 +1,149 @@ +:orphan: + +.. title:: MISPR documentation + +.. module:: mispr + +.. toctree:: + :hidden: + + overview + keywords + +.. toctree:: + :caption: Installation πŸ”§ + :hidden: + :titlesonly: + + Overview + Prerequisites + Configuration Files + Running a Test Workflow + +.. toctree:: + :caption: Workflows πŸ”€ + :hidden: + + workflows/basics + workflows/supported + workflows/tutorials + workflows/custom + +.. toctree:: + :caption: Resources πŸ–‡οΈ + :hidden: + + resources/faq + resources/resources + +.. toctree:: + :caption: Code Documentation πŸ“š + :hidden: + :titlesonly: + + mispr + +.. toctree:: + :caption: Development πŸ’» + :hidden: + + changelog + citing + license + +################################## +MISPR |release| Documentation +################################## + +MISPR is a Python library for computational materials science and contains +preset workflows for running complex hierarchical density functional +theory (DFT) and classical molecular dynamics (MD) simulations to compute +properties of materials. + +.. figure:: _static/summary.jpeg + :scale: 70% + + +************* +Installation +************* + +.. grid:: 1 1 2 2 + + .. grid-item:: + + Install using `pip `__: + + .. code-block:: bash + + pip install mispr + +.. important:: + Before you can start using MISPR, there are additional steps you need to follow. + Please refer to the :doc:`installation guide ` for complete setup instructions, + including any dependencies or configuration files required. + + +******************* +Learning Resources +******************* + +.. grid:: 1 1 2 2 + + .. grid-item-card:: + :padding: 2 + + About MISPR + ^^^ + + - :doc:`Overview ` + - :doc:`Dependencies and prerequisites ` + + .. grid-item-card:: + :padding: 2 + + Workflows + ^^^ + + - :doc:`Workflow basics ` + - :doc:`Supported workflows ` + - :doc:`External learning resources ` + + .. grid-item-card:: + :padding: 2 + + How-tos + ^^^ + + - :doc:`Tutorials ` + - :doc:`MISPR FAQ ` + + .. grid-item-card:: + :padding: 2 + + Code documentation + ^^^ + - :doc:`Subpackages ` + +************************************ +Contributing / Reporting / Support +************************************ +Contirbuting to MISPR can be in the form of: + +* Requesting or adding new workflows and features +* Reporting or fixing bugs and issues +* Contributing to the documentation and/or examples + +If you want to add or change something in the code, you can do this by +forking `MISPR on GitHub `_ and +submitting a pull request. + +If you submit a bug report, we will review it and move it to GitHub issues, +where its progress can be tracked. + +For other inquiries, please contact us at rasha.atwi@stonybrook.edu. + + + + + diff --git a/html/_sources/installation/configuration.rst.txt b/html/_sources/installation/configuration.rst.txt new file mode 100644 index 00000000..1a837086 --- /dev/null +++ b/html/_sources/installation/configuration.rst.txt @@ -0,0 +1,259 @@ +=============================== +Configuration Files +=============================== +After setting up the environment and installing the software, you will +need to configure the software to work with your system. This is done by +creating the following set of configuration files. + +.. note:: + This page is intended to help you get set-up for the first time using + FireWorks and MISPR so you can learn how these software work. Please + refer to the `FireWorks `__ + documentation for more information on these files and how FireWorks works. + Here, we will only discuss the basic configuration options which are + sufficient for using MISPR as in this tutorial. + + +Writing the Configuration Files +------------------------------------ + +.. tab-set:: + + .. tab-item:: db.json + + This file contains the basic MongoDB information like the + credentials required to connect to the database where the + calculation outputs will be stored. Note that + JSON strings require double quotes except for the value of + "port" which is an integer. + + .. code-block:: json + + { + "admin_user": "|ADMIN_USERNAME|", + "admin_password": "|ADMIN_PASSWORD|", + "aliases": {}, + "collection": "|COLLECTION|", + "database": "|DB_NAME|", + "host": "|HOSTNAME|", + "port": |PORT|, + } + + .. tab-item:: my_fworker.yaml + + This file stores your FireWorker's credentials. In + the `FireWorks `__, a + FireWorker can be as simple as the workstation used to host the + LaunchPad or complicated like a supercomputing center with a + queueing system. + + .. code-block:: yaml + + name: |WORKER_NAME| + category: '' + query: '{}' + env: + db_file: |CODES_DIR|/config/db.json + scratch_dir: null + + The following parameters are defined in the file: + + * ``name``: the name of the worker where your job will be run; + this is helpful when you have multiple workers; see + `FireWorks documentation on controlling the Worker `_ + if you need more information on setting up this file if you are + using more than one worker. + + * ``category`` and ``queue``: these parameters can control which + calculations are run on which worker; the default settings will + allow all calculations to be run + + * ``env``: defines worker-specific settings like the path to the + db file and the scratch directory for fast disk access + + .. tab-item:: my_launchpad.yaml + + This is the FireWorks LaunchPad file that contains the MongoDB + credentials required to connect to the database for storing + and managing workflows within FireWorks. Note that the ``db.json`` + file we created earlier is used to connect to the database + where the results are stored and is used by MISPR while + ``my_launchpad.yaml`` is used by FireWorks. The two databases + can be the same or different databases. If they are the same databases, + then the information here will be mostly the same as that in the + ``db.json`` file. + + .. code-block:: yaml + + host: |HOSTNAME| + port: |PORT| + name: |LAUNCHPAD_NAME| + username: |ADMIN_USERNAME| + password: |ADMIN_PASSWORD| + logdir: null + strm_lvl: INFO + user_indices: [] + wf_user_indices: [] + authsource: null + uri_mode: |URI_MODE| + mongoclient_kwargs: {} + + The following parameters need to be defined in the file: + + * ``host``: the hostname of the MongoDB server + + * ``port``: the port number of the MongoDB server + + * ``name``: the name of the MongoDB server + + * ``username``: the username to connect to the MongoDB server + + * ``password``: the password to connect to the MongoDB server + + Note that if the ``uri_mode`` is set to true, the ``host`` + should be the full `URI string `_. + In this case, the ``username`` and ``password`` are not used. + + If you want to pass other custom keyword arguments + (e.g., SSL/TLS arguments) to the MongoClient connection, you + can do that via ``mongoclient_kwargs``. See + `pymongo documentation `_ + for more details. + + .. tab-item:: my_qadapter.yaml + + This is the queue adapter file required by FireWorks to + automatically communicate with the queueing system. + The example provided here is for SLURM machines and does not + include a full list of possible parameters, but you can + check the rest of the parameters or parameters that can be + specified for other queue systems (e.g., PBS, SGE, etc.) + `here `_. + + .. code-block:: yaml + + _fw_name: CommonAdapter + _fw_q_type: SLURM + rocket_launch: rlaunch -w |CODES_DIR|/config singleshot + nodes: 1 + walltime: 24:00:00 + queue: null + account: null + job_name: null + pre_rocket: null + post_rocket: null + logdir: |CODES_DIR|/logs + + The following parameters are defined in the file: + + * ``_fw_name``: ``CommonAdapter`` means that the queue is one of + the built-in queue systems + + * ``_fw_q_type``: the queue system type (e.g., SLURM, PBS, SGE, etc.) + + * ``rocket_launch``: the method to use for launching Rockets + + * ``nodes``, ``walltime``, ``queue``, ``account``, ``job_name``: + parameters you normally specify in your SLURM script for + allocating resources + + * ``pre_rocket`` and ``post_rocket``: the commands to run + before and after launching the Rocket (e.g., module load + packages) + + * ``logdir``: path to the log directory + + .. note:: + Specifying singleshot in the file will limit each + reserved job to running only one firework at a time even if other + fireworks are waiting to be run. This can be changed to rapidfire + to run all fireworks in parallel. You can go over the FireWorks + documentation to learn the difference between these launching modes. + + .. tab-item:: config.ini + + This file contains the commands to run Gaussian, LAMMPS, and AmberTools. + These commands are specific to your computing resources you are + running on. The example provided here is meant to show how these + commands should be defined, but you need to change them to match your + system. + + .. code-block:: yaml + + [RunCalc] + gcmd: g16 < "$input_path$" > "$output_path$" + formchkcmd: formchk "$input_path$" "$output_path$" + + [LammpsRunCalc] + lcmd: mpirun -np $SLURM_NTASKS lmp_mpi -in $control_path$ + lammps_gpu_cmd: null + + [AmbertoolsRunCalc] + acmd: antechamber -i $input_file$ -fi $input_type$ -o $output_file$ -fo $output_type$ -c $charge_method$ -s 2 + pcmd: parmchk2 -i $input_file$ -f mol2 -o $output_file$ + tcmd: tleap -f $input_file$ + + [MaestroCalc] + mae_cmd: $SCHRODINGER/utilities/structconvert $input_file$ $output_file$ + ffld_cmd: $SCHRODINGER/utilities/ffld_server -imae $input_file$ -version 14 -print_parameters -out_file $output_file$ + + The following commands are defined in the file: + + * ``gcmd``: the command to run Gaussian + * ``formchkcmd``: the command to run Gaussian formchk to convert + a Gaussian checkpoint file into formatted forms + * ``lcmd``: the command to run LAMMPS + * ``lammps_gpu_cmd``: the command to run LAMMPS on a GPU + * ``acmd``: the command to run Antechamber + * ``pcmd``: the command to run Parmchk2 + * ``tcmd``: the command to run tleap + + .. note:: + Anything between two dollar signs ($ $) is a placeholder for + a variable and should not be changed. + + Anything between the square brackets ([]), e.g., [RunCalc], + or before the colons (:), e.g., gmcd, should not be changed + since these are used to point MISPR to the commands to run. + + .. tab-item:: FW_config.yaml + + This is the master FireWorks configuration file that controls + FireWorks settings and points to the location of the other + configuration files. + + .. code-block:: yaml + + CONFIG_FILE_DIR: |CODES_DIR|/config + + The ``CONFIG_FILE_DIR`` is expected to contain the + other configuration files. For a list of control settings that + can be added to this file, check + `FireWorks documentation on modifying the FW config `_. + +Configuring Bash Profile +------------------------------ +After creating the above six configuration files and replacing the +placeholders with your specific settings, create a directory in +your ``|CODES_DIR|`` (see :doc:`Definition <../keywords>`) called ``config`` +and move the above configuration files into it. The ``|CODES_DIR|/config`` +should look like: + +:: + + config + β”œβ”€β”€ config.ini + β”œβ”€β”€ db.json + β”œβ”€β”€ FW_config.yaml + β”œβ”€β”€ my_fworker.yaml + β”œβ”€β”€ my_launchpad.yaml + └── my_qadapter.yaml + +Now, append the following lines to your ``.bash_profile`` or ``.bashrc`` +file in order to set an environment variable that tells FireWorks where +to find the ``FW_config.yaml`` file, which will in turn tell FireWorks +where the rest of the configuration files are: + +.. code-block:: bash + + export FW_CONFIG_FILE=|CODES_DIR|/config/FW_config.yaml \ No newline at end of file diff --git a/html/_sources/installation/dependencies.rst.txt b/html/_sources/installation/dependencies.rst.txt new file mode 100644 index 00000000..7cc079e1 --- /dev/null +++ b/html/_sources/installation/dependencies.rst.txt @@ -0,0 +1,176 @@ +=============================== +Prerequisites +=============================== + +Virtual python environment +------------------------------ +MISPR depends on a number of third party Python packages, and usually on +specific versions of those packages. In order not to interfere with third +party packages needed by other software on your machine or cluster, we +strongly recommend isolating MISPR in a virtual python environment. In the +following, we describe how to create a virtual python environment using +the `virtualenv `_ tool, but +feel free to use your preferred environment manager +(e.g. `conda `_). + +.. tip:: + :title: Recommendation + + We recommend that you use Python version 3.7 since this is the version that we have + tested MISPR with. + +Creating the virtual environment +================================= +To create and activate a new virtual environment, go to your +``|CODES_DIR|`` (see :doc:`Definition <../keywords>`), and run the following commands:: + + pip install --user --upgrade virtualenv # install virtualenv tool + python -m virtualenv mispr_env # create "mispr_env" environment + source mispr_env/bin/activate # activate "mispr_env" environment + +This will create a directory in your ``|CODES_DIR|`` named ``mispr_env``, +where all the packages will be installed. After activation, your prompt +should have ``(mispr_env)`` in front of it, indicating that you are +working inside the virtual environment. The activation script ensures +that python programs have access only to packages installed inside the +virtualenv. +To deactivate the enviornment, simply run:: + + deactivate + +.. note:: + You may need to install ``pip`` and ``setuptools`` in your virtual + enviornment in case the system or user version of these tools is old:: + + pip install -U setuptools pip + +Computational chemistry software +--------------------------------- + +At the backend, MISPR uses: + +* `Gaussian `_ software to perform DFT calculations +* `AmberTools `_ to generate GAFF parameters +* `LAMMPS `_ to run MD simulations +* `Packmol `_ to + create initial configurations for MD simulations. To install packmol, + follow their `user guide `_ + +Ensure that you have access to the executables of these software +before using MISPR. Gaussian is a commercial software +that requires a license while AmberTools, LAMMPS, and Packmol are open source. +If Gaussian, AmberTools, and LAMMPS are already installed on supercomputing +resources, the user typically needs to load their corresponding modules +before their use. + +Materials Project base libraries +--------------------------------- +* `pymatgen `_: MISPR uses pymatgen for handling + different molecule representations and i/o operations specific to + Gaussian and LAMMPS. We have made changes to the pymatgen library to + make it compatible with our needs in MISPR. These changes have not + been merged yet with the main pymatgen library. Therefore, in order + to use MISPR, you need to install the MolMD version of pymatgen by + running the following commands in your ``|CODES_DIR|``:: + + git clone https://github.com/molmd/pymatgen.git + cd pymatgen + python setup.py install +* `FireWorks `_: MISPR + uses FireWorks to design, manage, and execute workflows. To install, + simply type:: + + pip install FireWorks + + Further details can be found in the `FireWorks documentation `_. + + .. note:: + While FireWorks is used in MISPR for managing the DFT and MD + workflows due to its many advantages, it takes some time to learn + and get used to it. + +* `custodian `_: MISPR uses + custodian for handling errors that occur during the simulations and + correcting them according to predefined rules. We have added a Gaussian + plug-in to the custodian library, but similar to the pymatgen changes, + these changes have not been merged yet with the main custodian library. + Therefore, in order to use MISPR, you need to install the MolMD version + of custodian by running the following commands in your ``|CODES_DIR|``:: + + git clone https://github.com/molmd/custodian.git + cd custodian + python setup.py install + +MongoDB +------------------------- +Following the design decisions of the Materials Project, MISPR uses +`MongoDB `__ as the backend database. +MongoDB is a NoSQL database that is designed to store and retrieve +data in a highly efficient and scalable manner. It stores data in the +form of documents represented in the JSON (JavaScript Object Notation) +format, which is similar to a Python dictionary. + +MISPR uses MongoDB to: + +* Add, remove, and search the status of workflows - feature of + `FireWorks `__ (required) +* Create computational databases of DFT and MD predicted properties - + Feature of MISPR (optional but strongly recommended) + +Setting up MongoDB +============================ +Options for getting MongoDB are: + +* Install it yourself locally by following the instructions at + `MongoDB `__. + This is pretty simple and typically works well if you are starting out + with MISPR and want to learn how to use a database. However, with this + option, you are limited with the storage space on your local machine and + you do not have the option to share the database with other users. You + also need to have the necessary privileges to install mongo on your machine. +* Set up an account using a commercial service, which is typically + the simplest and easiest to use but is not free of charge for databases + with large size. Examples of such services include Atlas and MongoDB Atlas, + which offer 500 MB databases for free. This is typically enough to get + started for small projects. +* Self-host a MongoDB server or ask your supercomputing center to offer + MongoDB hosting. This is more complicated than the other options and + will require continuous maintenance of the server. + +After creating a new database, you need to keep record of your credentials. +These will be used later in setting up the configuration files required +by FireWorks. + +.. note:: + MongoDB must be accessible from the computers you are using to run + the workflows. + +Testing your MongoDB connection +================================ +**Establishing a Connection to MongoDB Using Pymongo:** + +You need to import MongoClient from pymongo and then create a new MongoClient instance. +This instance is used to connect to your MongoDB instance: + +.. code-block:: python + + from pymongo import MongoClient + + client = MongoClient("mongodb://localhost:27017/") + +In this example, we're connecting to a MongoDB instance that runs on the same machine +(localhost) on port 27017, which is the default port for MongoDB. + +**Testing the Connection to MongoDB:** + +We can check the connection by listing all the databases: + +.. code-block:: python + + print(client.list_database_names()) + +If the connection is successful, this command will return a list of names of the databases that are present in the +MongoDB instance. + +Remember, for you to connect to a MongoDB instance, the MongoDB server needs to be installed and running. +If it's not running on localhost:27017, you will need to provide the appropriate connection string. \ No newline at end of file diff --git a/html/_sources/installation/index.rst.txt b/html/_sources/installation/index.rst.txt new file mode 100644 index 00000000..d5b8cee4 --- /dev/null +++ b/html/_sources/installation/index.rst.txt @@ -0,0 +1,82 @@ +============= +Installation +============= +Before installing MISPR, you need to follow the steps below in order: + +1. (Optional) Create a :ref:`installation/dependencies:Virtual python environment` +2. Make sure you have access to the :ref:`installation/dependencies:Computational chemistry software` + needed to run the DFT and MD simulations +3. Install :ref:`installation/dependencies:Materials Project base libraries` +4. Set up :ref:`installation/dependencies:MongoDB` database +5. :ref:`Install MISPR and MDPropTools ` +6. Prepare the :doc:`configuration files ` +7. :doc:`Run a test workflow ` + +.. note:: + Throughout the installation instructions, it is assumed that you are + familiar with Python and with basic Linux shell commands. If not, + `Linux Journey `_ and + `Python For Beginners `_ + are some recommended starting points. + +Installing MISPR and MDPropTools +-------------------------------- +MISPR and MDPropTools can be installed either from the python package +index (good for most users) or directly from their GitHub +repositories (good for developers). + +Installation Method 1: Using pip +================================ +To install, simply type: + +.. code-block:: bash + + pip install mispr + pip install mdproptools + +Installation Method 2: Development mode +======================================= + +.. _codes-develop-mode: + +To make changes directly to the source and contribute to the development +of MISPR, you can install MISPR and MDPropTools in development mode. + +.. note:: + If you had already installed MISPR via pip or conda, you + should uninstall that first before starting the installation in + development mode. This ensures that you will not have any conflicts + resulting from two different code installations. + +The steps for installing the packages in development mode are below. + +1. Activate your conda environment or virtual environment + +2. Create a ``codes`` directory in ``|CODES_DIR|`` + +3. ``cd`` to your newly created ``|CODES_DIR|/codes`` directory + +4. Clone the packages you want to install in development mode using git:: + + git clone https://github.com/molmd/mdproptools.git + git clone https://github.com/molmd/mispr.git + + Now you should have mdproptools and mispr directories in your ``codes`` + directory. + +5. For each of these packages, ``cd`` into their folders and run + ``pip install -e .`` or use the ``conda`` equivalent. Once installed, + if you make changes to the code in these packages, the changes + will take effect immediately without having to reinstall the package. + +Post-installation +------------------------- +1. Before you go any further, confirm your package installations are correct. + First start IPython by typing ``ipython`` in your terminal, then confirm that + the commands ``import mdproptools`` and ``import mispr`` execute + without any errors + +2. To update these codes later on, execute ``git pull`` followed by + ``pip install -e .`` or the ``conda`` equivalent in the corresponding + folder if you installed in development mode. If you installed via pip, + you can simply execute ``pip install --upgrade mispr``. \ No newline at end of file diff --git a/html/_sources/installation/test.rst.txt b/html/_sources/installation/test.rst.txt new file mode 100644 index 00000000..02ace824 --- /dev/null +++ b/html/_sources/installation/test.rst.txt @@ -0,0 +1,151 @@ +=============================== +Running a Test Workflow +=============================== +After installing MISPR and its dependencies and setting up the configuration +files, it is important to make sure everything is working correctly. +Therefore, we will now run a very simple test workflow that optimizes the +structure of a molecule. Later in :doc:`Workflow Tutorials <../workflows/tutorials>`, +we will show how to run more complex workflows. + +.. note:: + ``lpad`` and ``qlaunch`` that are used in this tutorial are part of + FireWorks software. You can refer to FireWorks documentation if you + need additional information. + +Initialize the database +------------------------------ +Initialize the database by running the following command:: + + lpad reset + + + +.. warning:: + This command should only be executed one time when you are first + initializing the database set-up. If you reset your LaunchPad at a + later time, you will erase all existing entries in your FireWorks + database, which includes your fireworks, workflows, and launches + collections. + +.. note:: + Your Python environment where FireWorks is installed must be active + before you run this command. + +Running the above command will return something like this:: + + Are you sure? This will RESET 0 workflows and all data. (Y/N)y + 2022-08-15 17:04:42,224 INFO Performing db tune-up + 2022-08-15 17:04:42,683 INFO LaunchPad was RESET. + +Add a workflow +------------------------------ +The next step is to add a workflow to the database. We will run a +workflow that optimizes the geometry of a monoglyme molecule starting +from its xyz file. Note that you need to have the **monoglyme.xyz** file in +your working directory. You will need to run the following Python code +by creating a file called ``optimize_geometry.py``: + +.. code-block:: python + + from mispr.gaussian.fireworks.core import CalcFromMolFW + from fireworks import LaunchPad, Workflow + + lpad = LaunchPad.auto_load() + wf = Workflow([CalcFromMolFW("monoglyme.xyz", "get_from_file", + gaussian_input_params={"route_parameters": {"opt": None}}, + save_to_file=True, save_to_db=True)]) + lpad.add_wf(wf) + +and then running the following command in terminal:: + + python optimize_geometry.py + + +This will add a structure optimization workflow to the database. + +Verify the workflow +------------------------------ +To check the status of this workflow in the database, run the following +command in terminal:: + + lpad get_fws -s READY + +It will return something like this:: + + { + "fw_id": 1, + "created_on": "2022-08-16T20:32:54.554404", + "updated_on": "2022-08-16T20:32:54.554716", + "state": "READY", + "name": "calc_from_mol" + } + +Alternatively, you can query your ``fireworks`` collection in the MongoDB +database directly or start FireWorks' `LaunchPad `_ +web gui from your local machine (assuming you have also set up +configuration files there):: + + lpad webgui + + + +Submit the workflow +------------------------------ +To launch this job through queue, use the qlaunch command from FireWorks. +qlaunch has 3 modes: singleshot, rapidfire, and multi: + +* ``singleshot``: launches one job at a time +* ``rapidfire``: launches multiple jobs at once; you'll most likely + want to use this mode where it is important to add the ``-m`` + flag to specify how many jobs to launch at once to prevent submitting + too many jobs at once. +* ``multi``: creates one job with multiple fireworks runs + +Here is an example command for launching one job from the terminal in the +same working directory as before:: + + qlaunch singleshot + +If you are not running your jobs through a queue, replace the +``qlaunch`` command with ``rlaunch``. + +Monitor the workflow +------------------------------ +If all went well, you can determine the status of your running jobs by +using the following command in the terminal:: + + lpad get_fws -s RUNNING + +or:: + + lpad get_fws -s COMPLETED + +If your job has failed, your can rerun it using the following command +(replacing ``fw_id`` with 1, which is the id of your firework, since +you only have one firework in your launchpad at this point):: + + lpad rerun_fws -i + +Query the database for the results +-------------------------------------- +Once this workflow is completed, you will see the generated Gaussian +input and output files as well as a ``run.json`` file that contains a +summary of the job in the same working directory. + +Additionally, you can query the database for the results of your jobs +by using the InChI representation of the monoglyme molecule as a query +criteria: + +.. code-block:: python + + from mispr.gaussian.utilities.db_utilities import get_db + + db = get_db() + db.retrieve_run(inchi="InChI=1S/C4H10O2/c1-5-3-4-6-2/h3-4H2,1-2H3")[0] + +This will return a dictionary of the results as they are saved in the +database. Alternatively, you can the view the results using MongoDB +Compass, and the generated documents from the run will appear like the +following in the ``runs`` collection of the ``gaussian`` database: + +.. figure:: ../_static/document.png \ No newline at end of file diff --git a/html/_sources/keywords.rst.txt b/html/_sources/keywords.rst.txt new file mode 100644 index 00000000..28e36971 --- /dev/null +++ b/html/_sources/keywords.rst.txt @@ -0,0 +1,18 @@ +=========== +Keywords +=========== + +.. list-table:: + :widths: 25 75 + :header-rows: 1 + + * - Keyword + - Definition + * - ``|CODES_DIR|`` + - Main directory where the virtual python environment is created and the configuration files are stored + * - ``LaunchPad`` + - FireWorks database that controls the workflows. It stores all the tasks to be run and their status (e.g., RUNNING, WAITING, COMPLETED, etc.) + * - ``FireTask`` + - Computing task to be performed + * - ``FireWork`` + - A list of FireTasks that are to be run in sequence \ No newline at end of file diff --git a/html/_sources/license.rst.txt b/html/_sources/license.rst.txt new file mode 100644 index 00000000..dec08f73 --- /dev/null +++ b/html/_sources/license.rst.txt @@ -0,0 +1,7 @@ +========== +License +========== + +MISPR is released under the MIT License. + +.. literalinclude:: _static/LICENSE.rst \ No newline at end of file diff --git a/html/_sources/mispr.common.rst.txt b/html/_sources/mispr.common.rst.txt new file mode 100644 index 00000000..dac55ef4 --- /dev/null +++ b/html/_sources/mispr.common.rst.txt @@ -0,0 +1,21 @@ +mispr.common package +==================== + +Submodules +---------- + +mispr.common.pubchem module +--------------------------- + +.. automodule:: mispr.common.pubchem + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.common + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.firetasks.rst.txt b/html/_sources/mispr.gaussian.firetasks.rst.txt new file mode 100644 index 00000000..22050fca --- /dev/null +++ b/html/_sources/mispr.gaussian.firetasks.rst.txt @@ -0,0 +1,45 @@ +mispr.gaussian.firetasks package +================================ + +Submodules +---------- + +mispr.gaussian.firetasks.geo\_transformation module +--------------------------------------------------- + +.. automodule:: mispr.gaussian.firetasks.geo_transformation + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.firetasks.parse\_outputs module +---------------------------------------------- + +.. automodule:: mispr.gaussian.firetasks.parse_outputs + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.firetasks.run\_calc module +----------------------------------------- + +.. automodule:: mispr.gaussian.firetasks.run_calc + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.firetasks.write\_inputs module +--------------------------------------------- + +.. automodule:: mispr.gaussian.firetasks.write_inputs + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.gaussian.firetasks + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.fireworks.rst.txt b/html/_sources/mispr.gaussian.fireworks.rst.txt new file mode 100644 index 00000000..90d5aa35 --- /dev/null +++ b/html/_sources/mispr.gaussian.fireworks.rst.txt @@ -0,0 +1,29 @@ +mispr.gaussian.fireworks package +================================ + +Submodules +---------- + +mispr.gaussian.fireworks.break\_mol module +------------------------------------------ + +.. automodule:: mispr.gaussian.fireworks.break_mol + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.fireworks.core module +------------------------------------ + +.. automodule:: mispr.gaussian.fireworks.core + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.gaussian.fireworks + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.rst.txt b/html/_sources/mispr.gaussian.rst.txt new file mode 100644 index 00000000..743265f5 --- /dev/null +++ b/html/_sources/mispr.gaussian.rst.txt @@ -0,0 +1,40 @@ +mispr.gaussian package +====================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + mispr.gaussian.firetasks + mispr.gaussian.fireworks + mispr.gaussian.utilities + mispr.gaussian.workflows + +Submodules +---------- + +mispr.gaussian.database module +------------------------------ + +.. automodule:: mispr.gaussian.database + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.defaults module +------------------------------ + +.. automodule:: mispr.gaussian.defaults + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.gaussian + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.utilities.rst.txt b/html/_sources/mispr.gaussian.utilities.rst.txt new file mode 100644 index 00000000..60d2a6cf --- /dev/null +++ b/html/_sources/mispr.gaussian.utilities.rst.txt @@ -0,0 +1,93 @@ +mispr.gaussian.utilities package +================================ + +Submodules +---------- + +mispr.gaussian.utilities.db\_utilities module +--------------------------------------------- + +.. automodule:: mispr.gaussian.utilities.db_utilities + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.dbdoc module +------------------------------------- + +.. automodule:: mispr.gaussian.utilities.dbdoc + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.files module +------------------------------------- + +.. automodule:: mispr.gaussian.utilities.files + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.fw\_utilities module +--------------------------------------------- + +.. automodule:: mispr.gaussian.utilities.fw_utilities + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.gout module +------------------------------------ + +.. automodule:: mispr.gaussian.utilities.gout + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.inputs module +-------------------------------------- + +.. automodule:: mispr.gaussian.utilities.inputs + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.metadata module +---------------------------------------- + +.. automodule:: mispr.gaussian.utilities.metadata + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.misc module +------------------------------------ + +.. automodule:: mispr.gaussian.utilities.misc + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.mol module +----------------------------------- + +.. automodule:: mispr.gaussian.utilities.mol + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.utilities.rdkit module +------------------------------------- + +.. automodule:: mispr.gaussian.utilities.rdkit + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.gaussian.utilities + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.workflows.base.rst.txt b/html/_sources/mispr.gaussian.workflows.base.rst.txt new file mode 100644 index 00000000..b86eedb6 --- /dev/null +++ b/html/_sources/mispr.gaussian.workflows.base.rst.txt @@ -0,0 +1,61 @@ +mispr.gaussian.workflows.base package +===================================== + +Submodules +---------- + +mispr.gaussian.workflows.base.bde module +---------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.bde + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.workflows.base.binding\_energy module +---------------------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.binding_energy + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.workflows.base.core module +----------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.core + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.workflows.base.esp module +---------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.esp + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.workflows.base.ip\_ea module +------------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.ip_ea + :members: + :undoc-members: + :show-inheritance: + +mispr.gaussian.workflows.base.nmr module +---------------------------------------- + +.. automodule:: mispr.gaussian.workflows.base.nmr + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.gaussian.workflows.base + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.gaussian.workflows.rst.txt b/html/_sources/mispr.gaussian.workflows.rst.txt new file mode 100644 index 00000000..dbec3d29 --- /dev/null +++ b/html/_sources/mispr.gaussian.workflows.rst.txt @@ -0,0 +1,18 @@ +mispr.gaussian.workflows package +================================ + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + mispr.gaussian.workflows.base + +Module contents +--------------- + +.. automodule:: mispr.gaussian.workflows + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.hybrid.firetasks.rst.txt b/html/_sources/mispr.hybrid.firetasks.rst.txt new file mode 100644 index 00000000..7b3ab01b --- /dev/null +++ b/html/_sources/mispr.hybrid.firetasks.rst.txt @@ -0,0 +1,21 @@ +mispr.hybrid.firetasks package +============================== + +Submodules +---------- + +mispr.hybrid.firetasks.nmr\_from\_md module +------------------------------------------- + +.. automodule:: mispr.hybrid.firetasks.nmr_from_md + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.hybrid.firetasks + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.hybrid.rst.txt b/html/_sources/mispr.hybrid.rst.txt new file mode 100644 index 00000000..2f5bba3e --- /dev/null +++ b/html/_sources/mispr.hybrid.rst.txt @@ -0,0 +1,30 @@ +mispr.hybrid package +==================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + mispr.hybrid.firetasks + mispr.hybrid.workflows + +Submodules +---------- + +mispr.hybrid.defaults module +---------------------------- + +.. automodule:: mispr.hybrid.defaults + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.hybrid + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.hybrid.workflows.rst.txt b/html/_sources/mispr.hybrid.workflows.rst.txt new file mode 100644 index 00000000..312259eb --- /dev/null +++ b/html/_sources/mispr.hybrid.workflows.rst.txt @@ -0,0 +1,29 @@ +mispr.hybrid.workflows package +============================== + +Submodules +---------- + +mispr.hybrid.workflows.core module +---------------------------------- + +.. automodule:: mispr.hybrid.workflows.core + :members: + :undoc-members: + :show-inheritance: + +mispr.hybrid.workflows.nmr module +--------------------------------- + +.. automodule:: mispr.hybrid.workflows.nmr + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.hybrid.workflows + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.firetasks.rst.txt b/html/_sources/mispr.lammps.firetasks.rst.txt new file mode 100644 index 00000000..e2ca5d5e --- /dev/null +++ b/html/_sources/mispr.lammps.firetasks.rst.txt @@ -0,0 +1,37 @@ +mispr.lammps.firetasks package +============================== + +Submodules +---------- + +mispr.lammps.firetasks.parse\_outputs module +-------------------------------------------- + +.. automodule:: mispr.lammps.firetasks.parse_outputs + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.firetasks.run module +--------------------------------- + +.. automodule:: mispr.lammps.firetasks.run + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.firetasks.write\_inputs module +------------------------------------------- + +.. automodule:: mispr.lammps.firetasks.write_inputs + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps.firetasks + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.fireworks.rst.txt b/html/_sources/mispr.lammps.fireworks.rst.txt new file mode 100644 index 00000000..1b6a189f --- /dev/null +++ b/html/_sources/mispr.lammps.fireworks.rst.txt @@ -0,0 +1,21 @@ +mispr.lammps.fireworks package +============================== + +Submodules +---------- + +mispr.lammps.fireworks.core module +---------------------------------- + +.. automodule:: mispr.lammps.fireworks.core + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps.fireworks + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.rst.txt b/html/_sources/mispr.lammps.rst.txt new file mode 100644 index 00000000..bd0acbfe --- /dev/null +++ b/html/_sources/mispr.lammps.rst.txt @@ -0,0 +1,41 @@ +mispr.lammps package +==================== + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + mispr.lammps.firetasks + mispr.lammps.fireworks + mispr.lammps.tests + mispr.lammps.utilities + mispr.lammps.workflows + +Submodules +---------- + +mispr.lammps.database module +---------------------------- + +.. automodule:: mispr.lammps.database + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.defaults module +---------------------------- + +.. automodule:: mispr.lammps.defaults + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.tests.rst.txt b/html/_sources/mispr.lammps.tests.rst.txt new file mode 100644 index 00000000..d6a00dde --- /dev/null +++ b/html/_sources/mispr.lammps.tests.rst.txt @@ -0,0 +1,117 @@ +mispr.lammps.tests package +========================== + +Submodules +---------- + +mispr.lammps.tests.antechamber module +------------------------------------- + +.. automodule:: mispr.lammps.tests.antechamber + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.base\_test module +------------------------------------ + +.. automodule:: mispr.lammps.tests.base_test + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.control module +--------------------------------- + +.. automodule:: mispr.lammps.tests.control + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.custom\_data\_workflow module +------------------------------------------------ + +.. automodule:: mispr.lammps.tests.custom_data_workflow + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.data module +------------------------------ + +.. automodule:: mispr.lammps.tests.data + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.electrolyte\_wf module +----------------------------------------- + +.. automodule:: mispr.lammps.tests.electrolyte_wf + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.esp\_to\_ff\_dict\_custom module +--------------------------------------------------- + +.. automodule:: mispr.lammps.tests.esp_to_ff_dict_custom + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.esp\_to\_ff\_dict\_function module +----------------------------------------------------- + +.. automodule:: mispr.lammps.tests.esp_to_ff_dict_function + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.liquid\_wf\_local module +------------------------------------------- + +.. automodule:: mispr.lammps.tests.liquid_wf_local + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.parmchk module +--------------------------------- + +.. automodule:: mispr.lammps.tests.parmchk + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.prmtop module +-------------------------------- + +.. automodule:: mispr.lammps.tests.prmtop + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.run\_lammps module +------------------------------------- + +.. automodule:: mispr.lammps.tests.run_lammps + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.tests.tleap module +------------------------------- + +.. automodule:: mispr.lammps.tests.tleap + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps.tests + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.utilities.rst.txt b/html/_sources/mispr.lammps.utilities.rst.txt new file mode 100644 index 00000000..433522f1 --- /dev/null +++ b/html/_sources/mispr.lammps.utilities.rst.txt @@ -0,0 +1,29 @@ +mispr.lammps.utilities package +============================== + +Submodules +---------- + +mispr.lammps.utilities.opls module +---------------------------------- + +.. automodule:: mispr.lammps.utilities.opls + :members: + :undoc-members: + :show-inheritance: + +mispr.lammps.utilities.utilities module +--------------------------------------- + +.. automodule:: mispr.lammps.utilities.utilities + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps.utilities + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.lammps.workflows.rst.txt b/html/_sources/mispr.lammps.workflows.rst.txt new file mode 100644 index 00000000..e6511648 --- /dev/null +++ b/html/_sources/mispr.lammps.workflows.rst.txt @@ -0,0 +1,21 @@ +mispr.lammps.workflows package +============================== + +Submodules +---------- + +mispr.lammps.workflows.base module +---------------------------------- + +.. automodule:: mispr.lammps.workflows.base + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: mispr.lammps.workflows + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/mispr.rst.txt b/html/_sources/mispr.rst.txt new file mode 100644 index 00000000..ba30d80c --- /dev/null +++ b/html/_sources/mispr.rst.txt @@ -0,0 +1,21 @@ +mispr package +============= + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + mispr.common + mispr.gaussian + mispr.hybrid + mispr.lammps + +Module contents +--------------- + +.. automodule:: mispr + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/modules.rst.txt b/html/_sources/modules.rst.txt new file mode 100644 index 00000000..4d1a62f9 --- /dev/null +++ b/html/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +mispr +===== + +.. toctree:: + :maxdepth: 4 + + mispr diff --git a/html/_sources/overview.rst.txt b/html/_sources/overview.rst.txt new file mode 100644 index 00000000..53224c3b --- /dev/null +++ b/html/_sources/overview.rst.txt @@ -0,0 +1,67 @@ +========== +Overview +========== +MISPR (Materials Informatics for Structure-Property Relationships) is a +high-throughput computational infrastructure aimed at guiding and +accelerating materials discovery, optimization, and deployment for +liquid solutions by seamlessly integrating density functional theory +(DFT) with classical molecular dynamics (MD) techniques. + +MISPR is motivated by the Materials Genome Initiative (MGI) principles and is +built on top of open-source Python packages developed for the `Materials +Project `_ such as `pymatgen `_, +`FireWorks `_ , +and `custodian `_, as +well as `MDPropTools `_, which +is an in-house package for analyzing MD output and trajectory files. + +.. figure:: _static/overview.png + +**Features of MISPR include**: + +* Automation of DFT and MD simulations and all their underlying tasks + from file management and job submission to supercomputing resources, + to output parsing and data analytics; a task that can be done to a + single molecule/system or to a large number of systems in parallel + +* Creation of computational databases of force field parameters and DFT + and MD derived properties of molecular systems for establishing + structure-property relations and maintaining data provenance and + reproducibility + +* Detection of the inevitable errors that occur during the simulations + and their on-the-fly correction based on template responses that have + been designed relying on human intuition coupled with extensive + experience to significantly improve the success rate of high-throughput + simulations while eliminating human intervention + +* Support for flexible and well-tested DFT workflows that compute various + properties of individual molecular species or complexes such as bond + dissociation energy, binding energy, redox potential, and nuclear + magnetic resonance (NMR) tensors + +* Derivation of many molecular ensemble properties such as radial + distribution functions, diffusion coefficients, viscosity, and + conductivity of liquid solutions, which are critical to understanding + complex inter- and intra-atomic interactions controlling the performance + of solutions within various chemistry, biology, and materials science + applications + +* Seamless integration of DFT and MD simulations through hybrid + workflows that enable force field generation and information flow + between the two length scales to allow exploring wide chemical and + parameter spaces (e.g., temperature, pressure, concentration, etc.), + a task that can be infeasible experimentally and challenging using + manual calculations + +* Automatic extraction of hundreds of thousands of solvation structures + from MD ensembles and their use in DFT workflows to accurately represent + the electronic environment, which is crucial to derive reliable energetics + and other properties such as NMR chemical shifts and redox potentials + and match them to experimental data + +.. note:: + MISPR is primarily built to work with `Gaussian `_ + electronic structure software for DFT calculation and + `LAMMPS `_ + open-source software for MD simulations. \ No newline at end of file diff --git a/html/_sources/resources/faq.rst.txt b/html/_sources/resources/faq.rst.txt new file mode 100644 index 00000000..22db95a8 --- /dev/null +++ b/html/_sources/resources/faq.rst.txt @@ -0,0 +1,5 @@ +=========== +FAQ +=========== + +This page is under construction. \ No newline at end of file diff --git a/html/_sources/resources/resources.rst.txt b/html/_sources/resources/resources.rst.txt new file mode 100644 index 00000000..c1366a60 --- /dev/null +++ b/html/_sources/resources/resources.rst.txt @@ -0,0 +1,22 @@ +============= +Helpful Links +============= + +Code Documentation +------------------------------ +* `pymatgen `_ +* `FireWorks `_ +* `custodian `_ +* `Gaussian `_ +* `LAMMPS `_ + +Code Capsules +------------------------------ +* `MISPR workshop for high-school students `_: + a compute capsule that stores the Python environment for the workshop + and includes Jupyter notebooks for predicting various materials + properties using MISPR +* `NMR tutorial `_: a compute + capsule that shows how to use the hybrid NMR workflow in MISPR to + sample solvation structures from MD simulations and predict their + NMR chemical shifts in a fully automated manner \ No newline at end of file diff --git a/html/_sources/setup.rst.txt b/html/_sources/setup.rst.txt new file mode 100644 index 00000000..552eb49d --- /dev/null +++ b/html/_sources/setup.rst.txt @@ -0,0 +1,7 @@ +setup module +============ + +.. automodule:: setup + :members: + :undoc-members: + :show-inheritance: diff --git a/html/_sources/workflows/basics.rst.txt b/html/_sources/workflows/basics.rst.txt new file mode 100644 index 00000000..c61dff37 --- /dev/null +++ b/html/_sources/workflows/basics.rst.txt @@ -0,0 +1,64 @@ +==================== +Workflow Basics +==================== +A scientific workflow in MISPR provides a complete description of the +procedure leading to the final data used to predict the desired property +of a given molecule or system. It consists of multiple steps ranging +from the initial setup of a molecule or system of molecules to a +sequence of calculations with dependencies and optional automated +post-processing of parsed data to derive properties of interest. + +.. note:: + The workflow model we use to encode DFT and MD recipes in MISPR is + defined by the FireWorks workflow software. + +A workflow in FireWorks is modeled as a Directed Acyclic Graph +representing the chain of relationships between +computational operations. A workflow consists of one or more Fireworks +(jobs) with dependencies. The workflow contains information +about the links between Fireworks to execute them in the correct order. +Each Firework consists of one or more Firetasks that run sequentially. +A Firetask is an atomic computing job that can call shell scripts, +transfer files, write/delete files, or execute other Python functions. +An example of the structure of a DFT workflow in MISPR is shown below: + +.. figure:: ../_static/workflow.png + +Once a Workflow object is created, the user can use the FireWorks package +to execute the calculations on various computing resources. The goal of +MISPR infrastructure is to provide preset workflows for +computing properties relevant to the molecular science community and to +simplify the process of creating new workflows by using the implemented +FireWorks and Firetasks in MISPR as building blocks for custom workflows. + +At the end of each workflow in MISPR, an analysis FireTask is performed +to analyze the results and generate a report. The report is in the form +of a JSON file and/or MongoDB document. It contains all the input parameters +used in the calculations, the output data, general information about the +calculation like the software version used (Gaussian, LAMMPS, MISPR, etc.), +the wall time the full run took, and chemical metadata about the molecule +or system of molecules (e.g. SMILES, InChI, molecular formula, etc.). + +In general, each property predicted by MISPR workflows is the result of +multiple Gaussian or LAMMPS calculations, and the predicted property is +represented by a single file/document summarizing data and "raw" information +collected from different calculation steps. The MongoDB document +corresponding to a predicted property is stored in a MongoDB collection +named after the property. For example, bond dissociation energies are +stored in a ``bde`` collection in the database while electrostatic +partial charges are saved in an ``esp`` collection and so on. Some of +the analysis FireTasks also include optional plotting of the results. +Besides the final summary file/document, MISPR stores data from the +intermediate calculation steps into a collection called ``runs`` in the +database. + +The following diagram summarizes the process in MISPR workflows to generate +the analysis files/documents: + +.. figure:: ../_static/analysis.png + +.. note:: + The above diagram shows one example of the structure of a workflow + where the Fireworks are executed sequentially. Some workflows contain + parallel Fireworks. However, the analysis Firework + is always the last Firework in all the workflows in MISPR. \ No newline at end of file diff --git a/html/_sources/workflows/custom.rst.txt b/html/_sources/workflows/custom.rst.txt new file mode 100644 index 00000000..fbbd11e2 --- /dev/null +++ b/html/_sources/workflows/custom.rst.txt @@ -0,0 +1,5 @@ +========================= +Creating Custom Workflows +========================= + +This page is under construction. \ No newline at end of file diff --git a/html/_sources/workflows/supported.rst.txt b/html/_sources/workflows/supported.rst.txt new file mode 100644 index 00000000..c7795f1f --- /dev/null +++ b/html/_sources/workflows/supported.rst.txt @@ -0,0 +1,33 @@ +==================== +Supported Workflows +==================== +Some of the workflows available as of July 2022 are: + +* DFT: + * Electrostatic partial charges (ESP) + * NMR shifts + * Redox potentials + * Binding energies + * Bond dissociation energies +* MD: + * Initial configuration building, generation of `GAFF `_ + or `OPLS `_ parameters, + running of MD simulations + * Analysis of output and trajectory files (e.g. RDF, coordination + number, diffusion coefficients, etc.) +* Hybrid: + * Core workflow for optimizing the individual structure of the + mixture of components, generating their ESP charges, and using + them in MD simulations + * NMR: deriving NMR chemicals for stable solvation structures + extracted from MD simulations + +One can customize any of the above workflows or create their own by reusing +the building blocks provided by MISPR. The above preset workflows are in +``mispr/gaussian/workflows/base``, ``mispr/lammps/workflows/base``, and +``mispr/hybrid/workflows``. + +.. note:: + Other types of force field parameters can be provided as + inputs to the MD workflow, thereby skipping the force field + generation step. \ No newline at end of file diff --git a/html/_sources/workflows/tutorials.rst.txt b/html/_sources/workflows/tutorials.rst.txt new file mode 100644 index 00000000..eac6408d --- /dev/null +++ b/html/_sources/workflows/tutorials.rst.txt @@ -0,0 +1,172 @@ +=================== +Workflow Tutorials +=================== + +This page is under construction. + +Running an ESP workflow +------------------------------ +The ESP workflow calculates the partial charges on atoms of a molecule. The charges are +fit to the electrostatic potential at points selected according to the Merz-Singh-Kollman +scheme, but other schemes supported by Gaussian can be used as well. + +**The ESP workflow performs the following steps:** + +.. mermaid:: + + %%{ + init: { + 'theme': 'base', + 'themeVariables': { + 'primaryTextColor': 'black', + 'lineColor': 'lightgrey', + 'secondaryColor': 'pink', + 'tertiaryColor': 'lightgrey' + } + } + }%% + + graph TD + A[(Input Structure)] -->|Preprocessing| DFT + DFT -->| | B[Geometry Optimization] + B -->| | C[Frequency Calculation] + C -->| | D[ESP Calculation] + D -->|Postprocessing| E[(Output)] + + subgraph DFT + B[Geometry Optimization] + C[Frequency Calculation] + D[ESP Calculation] + end + + style A fill:#EBEBEB,stroke:#BB2528 + style DFT fill:#DDEEFF,stroke:#DDEEFF,font-weight:bold + style B fill:#fff,stroke-dasharray: 5, 5, stroke:#BB2528 + style C fill:#fff,stroke-dasharray: 5, 5, stroke:#BB2528 + style D fill:#fff,stroke:#BB2528 + style E fill:#EBEBEB,stroke:#BB2528 + +.. note:: + The geometry optimization and frequency calculation steps (marked with a dashed + border in the above diagram) are optional. If the input structure is already + optimized, the workflow will skip these steps. + + +In the following example, we will run the ESP workflow on a monoglyme molecule. + +.. code-block:: python + :linenos: + + from fireworks import LaunchPad + + from mispr.gaussian.workflows.base.esp import get_esp_charges + + lpad = LaunchPad.auto_load() + + wf, _ = get_esp_charges( + mol_operation_type="get_from_pubchem", # (1)! + mol="monoglyme", + format_chk=True, + save_to_db=True, + save_to_file=True, + additional_prop_doc_fields={"name": "monoglyme"}, + tag="mispr_tutorial", + ) + lpad.add_wf(wf) # (2)! + +.. code-annotations:: + 1. + :code:`mol_operation_type` refers to the operation to be performed on the input to process the molecule. + + In this example, we are requesting to directly retrieve the molecule from PubChem by providing a + common name for the molecule to be used as query criteria for searching the PubChem database via + the :code:`mol` input argument. For a list of supported :code:`mol_operation_type` and the corresponding + :code:`mol`, refer to :meth:`mispr.gaussian.utilities.mol.process_mol`. + + 2. Adds the workflow to the launchpad. + + +Download :download:`esp_tutorial.py <../_downloads/esp_tutorial.py>`. + +Run the script using the following command: + +.. code-block:: bash + + python esp_tutorial.py + +And then launch the job through the queueing system using the following command: + +.. code-block:: bash + + qlaunch rapidfire # (1)! + +.. code-annotations:: + 1. + This command can submit a large number of jobs at once + or maintain a certain number of jobs in the queue. + +The workflow will run and create a directory named :code:`C4H10O2` in the current working +directory. The directory will contain the following subdirectories: + +.. code-block:: bash + + C4H10O2 + β”œβ”€β”€ Optimization + β”œβ”€β”€ Frequency + β”œβ”€β”€ ESP + β”œβ”€β”€ analysis + +Inside the :code:`Optimization`, :code:`Frequency`, and :code:`ESP` subdirectories, you +will find the Gaussian input and output files for the corresponding step. Inside the +:code:`Optimization` subdirectory, you will also find a "convergence.png" figure that +shows the forces and displacement convergence during the course of the optimization. + +.. figure:: ../_static/convergence.png + +The :code:`analysis` subdirectory contains the results of the workflow in the form of a +:code:`esp.json` file. You can read the content of the :code:`esp.json` file using the +following commands: + +.. code-block:: python + :linenos: + + import json + + with open("C4H10O2/analysis/esp.json", "r") as f: + esp = json.load(f) + + print(esp["esp"]) + +This will output the partial charges on the atoms of the molecule: + +.. code-block:: python + + { + "1": ["O", -0.374646], + "2": ["O", -0.373831], + "3": ["C", 0.132166], + "4": ["C", 0.132716], + "5": ["C", 0.034284], + "6": ["C", 0.031733], + "7": ["H", 0.033853], + "8": ["H", 0.034024], + "9": ["H", 0.034218], + "10": ["H", 0.034388], + "11": ["H", 0.070724], + "12": ["H", 0.03474], + "13": ["H", 0.03438], + "14": ["H", 0.034621], + "15": ["H", 0.071656], + "16": ["H", 0.034974], + } + +Running a BDE workflow +------------------------------ + + +Running an MD workflow +------------------------------ + + +Running a hybrid workflow +------------------------------ diff --git a/html/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/html/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 00000000..eb19f698 --- /dev/null +++ b/html/_sphinx_design_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/html/_sphinx_design_static/design-tabs.js b/html/_sphinx_design_static/design-tabs.js new file mode 100644 index 00000000..36b38cf0 --- /dev/null +++ b/html/_sphinx_design_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/html/_static/LICENSE.rst b/html/_static/LICENSE.rst new file mode 100644 index 00000000..ba657a33 --- /dev/null +++ b/html/_static/LICENSE.rst @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Stony Brook University + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/html/_static/analysis.png b/html/_static/analysis.png new file mode 100644 index 00000000..2c8fa034 Binary files /dev/null and b/html/_static/analysis.png differ diff --git a/html/_static/check-solid.svg b/html/_static/check-solid.svg new file mode 100644 index 00000000..92fad4b5 --- /dev/null +++ b/html/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/html/_static/clipboard.min.js b/html/_static/clipboard.min.js new file mode 100644 index 00000000..54b3c463 --- /dev/null +++ b/html/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT Β© Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/html/_static/copybutton.css b/html/_static/copybutton.css new file mode 100644 index 00000000..f1916ec7 --- /dev/null +++ b/html/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/html/_static/copybutton.js b/html/_static/copybutton.js new file mode 100644 index 00000000..2ea7ff3e --- /dev/null +++ b/html/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': 'Β‘Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'CopiΓ© !', + 'copy_failure': 'Γ‰chec de la copie', + }, + 'ru': { + 'copy': 'Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ', + 'copy_to_clipboard': 'Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π² Π±ΡƒΡ„Π΅Ρ€', + 'copy_success': 'Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΎ!', + 'copy_failure': 'НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ', + }, + 'zh-CN': { + 'copy': '倍刢', + 'copy_to_clipboard': '倍刢到ε‰ͺ贴板', + 'copy_success': '倍刢成功!', + 'copy_failure': '倍刢倱θ΄₯', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/html/_static/copybutton_funcs.js b/html/_static/copybutton_funcs.js new file mode 100644 index 00000000..dbe1aaad --- /dev/null +++ b/html/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/html/_static/css/rtd_sphinx_search.min.css b/html/_static/css/rtd_sphinx_search.min.css new file mode 100644 index 00000000..b52e1909 --- /dev/null +++ b/html/_static/css/rtd_sphinx_search.min.css @@ -0,0 +1 @@ +@-webkit-keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes fade-in{0%{opacity:0}to{opacity:1}}.search__backdrop,.search__outer__wrapper{position:fixed;top:0;left:0;width:100%;height:100%;z-index:700}.search__backdrop{z-index:500;display:none;background-color:rgba(0,0,0,.502)}.search__outer{margin:auto;position:absolute;top:0;left:0;right:0;bottom:0;z-index:100000;height:80%;width:80%;max-height:1000px;max-width:1500px;padding:10px;overflow-y:scroll;border:1px solid #e0e0e0;line-height:1.875;background-color:#fcfcfc;-webkit-box-shadow:1px 3px 4px rgba(0,0,0,.09);box-shadow:1px 3px 4px rgba(0,0,0,.09);text-align:left}.search__outer::-webkit-scrollbar-track{border-radius:10px;background-color:#fcfcfc}.search__outer::-webkit-scrollbar{width:7px;height:7px;background-color:#fcfcfc}.search__outer::-webkit-scrollbar-thumb{border-radius:10px;background-color:#8f8f8f}.search__cross__img{width:15px;height:15px;margin:12px}.search__cross{position:absolute;top:0;right:0}.search__cross:hover{cursor:pointer}.search__outer__input{width:90%;height:30px;font-size:19px;outline:0;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#fcfcfc;border:0;border-bottom:1px solid #757575;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgNDUxIDQ1MSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDUxIDQ1MTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQoJPHBhdGggZD0iTTQ0Ny4wNSw0MjhsLTEwOS42LTEwOS42YzI5LjQtMzMuOCw0Ny4yLTc3LjksNDcuMi0xMjYuMUMzODQuNjUsODYuMiwyOTguMzUsMCwxOTIuMzUsMEM4Ni4yNSwwLDAuMDUsODYuMywwLjA1LDE5Mi4zDQoJCXM4Ni4zLDE5Mi4zLDE5Mi4zLDE5Mi4zYzQ4LjIsMCw5Mi4zLTE3LjgsMTI2LjEtNDcuMkw0MjguMDUsNDQ3YzIuNiwyLjYsNi4xLDQsOS41LDRzNi45LTEuMyw5LjUtNA0KCQlDNDUyLjI1LDQ0MS44LDQ1Mi4yNSw0MzMuMiw0NDcuMDUsNDI4eiBNMjYuOTUsMTkyLjNjMC05MS4yLDc0LjItMTY1LjMsMTY1LjMtMTY1LjNjOTEuMiwwLDE2NS4zLDc0LjIsMTY1LjMsMTY1LjMNCgkJcy03NC4xLDE2NS40LTE2NS4zLDE2NS40QzEwMS4xNSwzNTcuNywyNi45NSwyODMuNSwyNi45NSwxOTIuM3oiLz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjwvc3ZnPg0K);background-repeat:no-repeat;background-position:left;background-size:15px 15px;padding-left:25px}.search__outer__input:focus{outline:0}.search__outer .bar{position:relative;display:block;width:90%;margin-bottom:15px}.search__outer .bar:after,.search__outer .bar:before{content:"";height:2px;width:0;bottom:1px;position:absolute;background:#5264ae;-webkit-transition:.2s ease all;-o-transition:.2s ease all;transition:.2s ease all}.search__outer .bar:before{left:50%}.search__outer .bar:after{right:50%}.search__outer__input:focus~.bar:after,.search__outer__input:focus~.bar:before{width:50%}.search__result__box{padding:0 10px}.search__result__single{margin-top:10px;border-bottom:1px solid #e6e6e6}.outer_div_page_results:hover,.search__result__box .active{background-color:#f5f5f5}.search__error__box{color:#000;min-width:300px;font-weight:700}.outer_div_page_results{margin:5px 0;overflow:auto;padding:3px 5px}.search__result__single a{text-decoration:none;cursor:pointer}.search__result__title{display:inline-block;font-weight:500;margin-bottom:15px;margin-top:0;font-size:15px;color:#6ea0ec;border-bottom:1px solid #6ea0ec}.search__result__subheading{color:#000;font-weight:700;float:left;width:20%;font-size:15px;margin-right:10px;word-break:break-all;overflow-x:hidden}.search__result__content{text-decoration:none;color:#000;font-size:15px;display:block;margin:0;line-height:inherit;float:right;width:calc(80% - 15px);text-align:left}.search__outer span{font-style:normal}.search__outer .search__result__title span{background-color:#e5f6ff;padding-bottom:3px;border-bottom-color:#000}.search__outer .search__result__content span{background-color:#e5f6ff;border-bottom:1px solid #000}.search__result__subheading span{border-bottom:1px solid #000}.br-for-hits{display:block;content:"";margin-top:10px}.rtd_ui_search_subtitle{all:unset;color:inherit;font-size:85%}.rtd__search__credits{margin:auto;position:absolute;top:0;left:0;right:0;bottom:calc(-80% - 20px);width:80%;max-width:1500px;height:30px;overflow:hidden;background:#eee;z-index:100000;border:1px solid #eee;padding:5px 10px;text-align:center;color:#000}.rtd__search__credits a{color:#000;text-decoration:underline}.search__domain_role_name{font-size:80%;letter-spacing:1px}.search__filters{padding:0 10px}.search__filters li,.search__filters ul{display:-webkit-box;display:-ms-flexbox;display:flex}.search__filters ul{list-style:none;padding:0;margin:0}.search__filters li{-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-right:15px}.search__filters label{margin:auto}.search__filters .search__filters__title,.search__filters label{color:#000;font-size:15px}@media (max-width:670px){.rtd__search__credits{height:50px;bottom:calc(-80% - 40px);overflow:hidden}}@media (min-height:1250px){.rtd__search__credits{bottom:calc(-1000px - 30px)}}@media (max-width:630px){.search__result__content,.search__result__subheading{float:none;width:90%}} \ No newline at end of file diff --git a/html/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css b/html/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css new file mode 100644 index 00000000..eb19f698 --- /dev/null +++ b/html/_static/design-style.1e8bd061cd6da7fc9cf755528e8ffc24.min.css @@ -0,0 +1 @@ +.sd-bg-primary{background-color:var(--sd-color-primary) !important}.sd-bg-text-primary{color:var(--sd-color-primary-text) !important}button.sd-bg-primary:focus,button.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}a.sd-bg-primary:focus,a.sd-bg-primary:hover{background-color:var(--sd-color-primary-highlight) !important}.sd-bg-secondary{background-color:var(--sd-color-secondary) !important}.sd-bg-text-secondary{color:var(--sd-color-secondary-text) !important}button.sd-bg-secondary:focus,button.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}a.sd-bg-secondary:focus,a.sd-bg-secondary:hover{background-color:var(--sd-color-secondary-highlight) !important}.sd-bg-success{background-color:var(--sd-color-success) !important}.sd-bg-text-success{color:var(--sd-color-success-text) !important}button.sd-bg-success:focus,button.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}a.sd-bg-success:focus,a.sd-bg-success:hover{background-color:var(--sd-color-success-highlight) !important}.sd-bg-info{background-color:var(--sd-color-info) !important}.sd-bg-text-info{color:var(--sd-color-info-text) !important}button.sd-bg-info:focus,button.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}a.sd-bg-info:focus,a.sd-bg-info:hover{background-color:var(--sd-color-info-highlight) !important}.sd-bg-warning{background-color:var(--sd-color-warning) !important}.sd-bg-text-warning{color:var(--sd-color-warning-text) !important}button.sd-bg-warning:focus,button.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}a.sd-bg-warning:focus,a.sd-bg-warning:hover{background-color:var(--sd-color-warning-highlight) !important}.sd-bg-danger{background-color:var(--sd-color-danger) !important}.sd-bg-text-danger{color:var(--sd-color-danger-text) !important}button.sd-bg-danger:focus,button.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}a.sd-bg-danger:focus,a.sd-bg-danger:hover{background-color:var(--sd-color-danger-highlight) !important}.sd-bg-light{background-color:var(--sd-color-light) !important}.sd-bg-text-light{color:var(--sd-color-light-text) !important}button.sd-bg-light:focus,button.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}a.sd-bg-light:focus,a.sd-bg-light:hover{background-color:var(--sd-color-light-highlight) !important}.sd-bg-muted{background-color:var(--sd-color-muted) !important}.sd-bg-text-muted{color:var(--sd-color-muted-text) !important}button.sd-bg-muted:focus,button.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}a.sd-bg-muted:focus,a.sd-bg-muted:hover{background-color:var(--sd-color-muted-highlight) !important}.sd-bg-dark{background-color:var(--sd-color-dark) !important}.sd-bg-text-dark{color:var(--sd-color-dark-text) !important}button.sd-bg-dark:focus,button.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}a.sd-bg-dark:focus,a.sd-bg-dark:hover{background-color:var(--sd-color-dark-highlight) !important}.sd-bg-black{background-color:var(--sd-color-black) !important}.sd-bg-text-black{color:var(--sd-color-black-text) !important}button.sd-bg-black:focus,button.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}a.sd-bg-black:focus,a.sd-bg-black:hover{background-color:var(--sd-color-black-highlight) !important}.sd-bg-white{background-color:var(--sd-color-white) !important}.sd-bg-text-white{color:var(--sd-color-white-text) !important}button.sd-bg-white:focus,button.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}a.sd-bg-white:focus,a.sd-bg-white:hover{background-color:var(--sd-color-white-highlight) !important}.sd-text-primary,.sd-text-primary>p{color:var(--sd-color-primary) !important}a.sd-text-primary:focus,a.sd-text-primary:hover{color:var(--sd-color-primary-highlight) !important}.sd-text-secondary,.sd-text-secondary>p{color:var(--sd-color-secondary) !important}a.sd-text-secondary:focus,a.sd-text-secondary:hover{color:var(--sd-color-secondary-highlight) !important}.sd-text-success,.sd-text-success>p{color:var(--sd-color-success) !important}a.sd-text-success:focus,a.sd-text-success:hover{color:var(--sd-color-success-highlight) !important}.sd-text-info,.sd-text-info>p{color:var(--sd-color-info) !important}a.sd-text-info:focus,a.sd-text-info:hover{color:var(--sd-color-info-highlight) !important}.sd-text-warning,.sd-text-warning>p{color:var(--sd-color-warning) !important}a.sd-text-warning:focus,a.sd-text-warning:hover{color:var(--sd-color-warning-highlight) !important}.sd-text-danger,.sd-text-danger>p{color:var(--sd-color-danger) !important}a.sd-text-danger:focus,a.sd-text-danger:hover{color:var(--sd-color-danger-highlight) !important}.sd-text-light,.sd-text-light>p{color:var(--sd-color-light) !important}a.sd-text-light:focus,a.sd-text-light:hover{color:var(--sd-color-light-highlight) !important}.sd-text-muted,.sd-text-muted>p{color:var(--sd-color-muted) !important}a.sd-text-muted:focus,a.sd-text-muted:hover{color:var(--sd-color-muted-highlight) !important}.sd-text-dark,.sd-text-dark>p{color:var(--sd-color-dark) !important}a.sd-text-dark:focus,a.sd-text-dark:hover{color:var(--sd-color-dark-highlight) !important}.sd-text-black,.sd-text-black>p{color:var(--sd-color-black) !important}a.sd-text-black:focus,a.sd-text-black:hover{color:var(--sd-color-black-highlight) !important}.sd-text-white,.sd-text-white>p{color:var(--sd-color-white) !important}a.sd-text-white:focus,a.sd-text-white:hover{color:var(--sd-color-white-highlight) !important}.sd-outline-primary{border-color:var(--sd-color-primary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-primary:focus,a.sd-outline-primary:hover{border-color:var(--sd-color-primary-highlight) !important}.sd-outline-secondary{border-color:var(--sd-color-secondary) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-secondary:focus,a.sd-outline-secondary:hover{border-color:var(--sd-color-secondary-highlight) !important}.sd-outline-success{border-color:var(--sd-color-success) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-success:focus,a.sd-outline-success:hover{border-color:var(--sd-color-success-highlight) !important}.sd-outline-info{border-color:var(--sd-color-info) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-info:focus,a.sd-outline-info:hover{border-color:var(--sd-color-info-highlight) !important}.sd-outline-warning{border-color:var(--sd-color-warning) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-warning:focus,a.sd-outline-warning:hover{border-color:var(--sd-color-warning-highlight) !important}.sd-outline-danger{border-color:var(--sd-color-danger) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-danger:focus,a.sd-outline-danger:hover{border-color:var(--sd-color-danger-highlight) !important}.sd-outline-light{border-color:var(--sd-color-light) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-light:focus,a.sd-outline-light:hover{border-color:var(--sd-color-light-highlight) !important}.sd-outline-muted{border-color:var(--sd-color-muted) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-muted:focus,a.sd-outline-muted:hover{border-color:var(--sd-color-muted-highlight) !important}.sd-outline-dark{border-color:var(--sd-color-dark) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-dark:focus,a.sd-outline-dark:hover{border-color:var(--sd-color-dark-highlight) !important}.sd-outline-black{border-color:var(--sd-color-black) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-black:focus,a.sd-outline-black:hover{border-color:var(--sd-color-black-highlight) !important}.sd-outline-white{border-color:var(--sd-color-white) !important;border-style:solid !important;border-width:1px !important}a.sd-outline-white:focus,a.sd-outline-white:hover{border-color:var(--sd-color-white-highlight) !important}.sd-bg-transparent{background-color:transparent !important}.sd-outline-transparent{border-color:transparent !important}.sd-text-transparent{color:transparent !important}.sd-p-0{padding:0 !important}.sd-pt-0,.sd-py-0{padding-top:0 !important}.sd-pr-0,.sd-px-0{padding-right:0 !important}.sd-pb-0,.sd-py-0{padding-bottom:0 !important}.sd-pl-0,.sd-px-0{padding-left:0 !important}.sd-p-1{padding:.25rem !important}.sd-pt-1,.sd-py-1{padding-top:.25rem !important}.sd-pr-1,.sd-px-1{padding-right:.25rem !important}.sd-pb-1,.sd-py-1{padding-bottom:.25rem !important}.sd-pl-1,.sd-px-1{padding-left:.25rem !important}.sd-p-2{padding:.5rem !important}.sd-pt-2,.sd-py-2{padding-top:.5rem !important}.sd-pr-2,.sd-px-2{padding-right:.5rem !important}.sd-pb-2,.sd-py-2{padding-bottom:.5rem !important}.sd-pl-2,.sd-px-2{padding-left:.5rem !important}.sd-p-3{padding:1rem !important}.sd-pt-3,.sd-py-3{padding-top:1rem !important}.sd-pr-3,.sd-px-3{padding-right:1rem !important}.sd-pb-3,.sd-py-3{padding-bottom:1rem !important}.sd-pl-3,.sd-px-3{padding-left:1rem !important}.sd-p-4{padding:1.5rem !important}.sd-pt-4,.sd-py-4{padding-top:1.5rem !important}.sd-pr-4,.sd-px-4{padding-right:1.5rem !important}.sd-pb-4,.sd-py-4{padding-bottom:1.5rem !important}.sd-pl-4,.sd-px-4{padding-left:1.5rem !important}.sd-p-5{padding:3rem !important}.sd-pt-5,.sd-py-5{padding-top:3rem !important}.sd-pr-5,.sd-px-5{padding-right:3rem !important}.sd-pb-5,.sd-py-5{padding-bottom:3rem !important}.sd-pl-5,.sd-px-5{padding-left:3rem !important}.sd-m-auto{margin:auto !important}.sd-mt-auto,.sd-my-auto{margin-top:auto !important}.sd-mr-auto,.sd-mx-auto{margin-right:auto !important}.sd-mb-auto,.sd-my-auto{margin-bottom:auto !important}.sd-ml-auto,.sd-mx-auto{margin-left:auto !important}.sd-m-0{margin:0 !important}.sd-mt-0,.sd-my-0{margin-top:0 !important}.sd-mr-0,.sd-mx-0{margin-right:0 !important}.sd-mb-0,.sd-my-0{margin-bottom:0 !important}.sd-ml-0,.sd-mx-0{margin-left:0 !important}.sd-m-1{margin:.25rem !important}.sd-mt-1,.sd-my-1{margin-top:.25rem !important}.sd-mr-1,.sd-mx-1{margin-right:.25rem !important}.sd-mb-1,.sd-my-1{margin-bottom:.25rem !important}.sd-ml-1,.sd-mx-1{margin-left:.25rem !important}.sd-m-2{margin:.5rem !important}.sd-mt-2,.sd-my-2{margin-top:.5rem !important}.sd-mr-2,.sd-mx-2{margin-right:.5rem !important}.sd-mb-2,.sd-my-2{margin-bottom:.5rem !important}.sd-ml-2,.sd-mx-2{margin-left:.5rem !important}.sd-m-3{margin:1rem !important}.sd-mt-3,.sd-my-3{margin-top:1rem !important}.sd-mr-3,.sd-mx-3{margin-right:1rem !important}.sd-mb-3,.sd-my-3{margin-bottom:1rem !important}.sd-ml-3,.sd-mx-3{margin-left:1rem !important}.sd-m-4{margin:1.5rem !important}.sd-mt-4,.sd-my-4{margin-top:1.5rem !important}.sd-mr-4,.sd-mx-4{margin-right:1.5rem !important}.sd-mb-4,.sd-my-4{margin-bottom:1.5rem !important}.sd-ml-4,.sd-mx-4{margin-left:1.5rem !important}.sd-m-5{margin:3rem !important}.sd-mt-5,.sd-my-5{margin-top:3rem !important}.sd-mr-5,.sd-mx-5{margin-right:3rem !important}.sd-mb-5,.sd-my-5{margin-bottom:3rem !important}.sd-ml-5,.sd-mx-5{margin-left:3rem !important}.sd-w-25{width:25% !important}.sd-w-50{width:50% !important}.sd-w-75{width:75% !important}.sd-w-100{width:100% !important}.sd-w-auto{width:auto !important}.sd-h-25{height:25% !important}.sd-h-50{height:50% !important}.sd-h-75{height:75% !important}.sd-h-100{height:100% !important}.sd-h-auto{height:auto !important}.sd-d-none{display:none !important}.sd-d-inline{display:inline !important}.sd-d-inline-block{display:inline-block !important}.sd-d-block{display:block !important}.sd-d-grid{display:grid !important}.sd-d-flex-row{display:-ms-flexbox !important;display:flex !important;flex-direction:row !important}.sd-d-flex-column{display:-ms-flexbox !important;display:flex !important;flex-direction:column !important}.sd-d-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}@media(min-width: 576px){.sd-d-sm-none{display:none !important}.sd-d-sm-inline{display:inline !important}.sd-d-sm-inline-block{display:inline-block !important}.sd-d-sm-block{display:block !important}.sd-d-sm-grid{display:grid !important}.sd-d-sm-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-sm-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 768px){.sd-d-md-none{display:none !important}.sd-d-md-inline{display:inline !important}.sd-d-md-inline-block{display:inline-block !important}.sd-d-md-block{display:block !important}.sd-d-md-grid{display:grid !important}.sd-d-md-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-md-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 992px){.sd-d-lg-none{display:none !important}.sd-d-lg-inline{display:inline !important}.sd-d-lg-inline-block{display:inline-block !important}.sd-d-lg-block{display:block !important}.sd-d-lg-grid{display:grid !important}.sd-d-lg-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-lg-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}@media(min-width: 1200px){.sd-d-xl-none{display:none !important}.sd-d-xl-inline{display:inline !important}.sd-d-xl-inline-block{display:inline-block !important}.sd-d-xl-block{display:block !important}.sd-d-xl-grid{display:grid !important}.sd-d-xl-flex{display:-ms-flexbox !important;display:flex !important}.sd-d-xl-inline-flex{display:-ms-inline-flexbox !important;display:inline-flex !important}}.sd-align-major-start{justify-content:flex-start !important}.sd-align-major-end{justify-content:flex-end !important}.sd-align-major-center{justify-content:center !important}.sd-align-major-justify{justify-content:space-between !important}.sd-align-major-spaced{justify-content:space-evenly !important}.sd-align-minor-start{align-items:flex-start !important}.sd-align-minor-end{align-items:flex-end !important}.sd-align-minor-center{align-items:center !important}.sd-align-minor-stretch{align-items:stretch !important}.sd-text-justify{text-align:justify !important}.sd-text-left{text-align:left !important}.sd-text-right{text-align:right !important}.sd-text-center{text-align:center !important}.sd-font-weight-light{font-weight:300 !important}.sd-font-weight-lighter{font-weight:lighter !important}.sd-font-weight-normal{font-weight:400 !important}.sd-font-weight-bold{font-weight:700 !important}.sd-font-weight-bolder{font-weight:bolder !important}.sd-font-italic{font-style:italic !important}.sd-text-decoration-none{text-decoration:none !important}.sd-text-lowercase{text-transform:lowercase !important}.sd-text-uppercase{text-transform:uppercase !important}.sd-text-capitalize{text-transform:capitalize !important}.sd-text-wrap{white-space:normal !important}.sd-text-nowrap{white-space:nowrap !important}.sd-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sd-fs-1,.sd-fs-1>p{font-size:calc(1.375rem + 1.5vw) !important;line-height:unset !important}.sd-fs-2,.sd-fs-2>p{font-size:calc(1.325rem + 0.9vw) !important;line-height:unset !important}.sd-fs-3,.sd-fs-3>p{font-size:calc(1.3rem + 0.6vw) !important;line-height:unset !important}.sd-fs-4,.sd-fs-4>p{font-size:calc(1.275rem + 0.3vw) !important;line-height:unset !important}.sd-fs-5,.sd-fs-5>p{font-size:1.25rem !important;line-height:unset !important}.sd-fs-6,.sd-fs-6>p{font-size:1rem !important;line-height:unset !important}.sd-border-0{border:0 solid !important}.sd-border-top-0{border-top:0 solid !important}.sd-border-bottom-0{border-bottom:0 solid !important}.sd-border-right-0{border-right:0 solid !important}.sd-border-left-0{border-left:0 solid !important}.sd-border-1{border:1px solid !important}.sd-border-top-1{border-top:1px solid !important}.sd-border-bottom-1{border-bottom:1px solid !important}.sd-border-right-1{border-right:1px solid !important}.sd-border-left-1{border-left:1px solid !important}.sd-border-2{border:2px solid !important}.sd-border-top-2{border-top:2px solid !important}.sd-border-bottom-2{border-bottom:2px solid !important}.sd-border-right-2{border-right:2px solid !important}.sd-border-left-2{border-left:2px solid !important}.sd-border-3{border:3px solid !important}.sd-border-top-3{border-top:3px solid !important}.sd-border-bottom-3{border-bottom:3px solid !important}.sd-border-right-3{border-right:3px solid !important}.sd-border-left-3{border-left:3px solid !important}.sd-border-4{border:4px solid !important}.sd-border-top-4{border-top:4px solid !important}.sd-border-bottom-4{border-bottom:4px solid !important}.sd-border-right-4{border-right:4px solid !important}.sd-border-left-4{border-left:4px solid !important}.sd-border-5{border:5px solid !important}.sd-border-top-5{border-top:5px solid !important}.sd-border-bottom-5{border-bottom:5px solid !important}.sd-border-right-5{border-right:5px solid !important}.sd-border-left-5{border-left:5px solid !important}.sd-rounded-0{border-radius:0 !important}.sd-rounded-1{border-radius:.2rem !important}.sd-rounded-2{border-radius:.3rem !important}.sd-rounded-3{border-radius:.5rem !important}.sd-rounded-pill{border-radius:50rem !important}.sd-rounded-circle{border-radius:50% !important}.shadow-none{box-shadow:none !important}.sd-shadow-sm{box-shadow:0 .125rem .25rem var(--sd-color-shadow) !important}.sd-shadow-md{box-shadow:0 .5rem 1rem var(--sd-color-shadow) !important}.sd-shadow-lg{box-shadow:0 1rem 3rem var(--sd-color-shadow) !important}@keyframes sd-slide-from-left{0%{transform:translateX(-100%)}100%{transform:translateX(0)}}@keyframes sd-slide-from-right{0%{transform:translateX(200%)}100%{transform:translateX(0)}}@keyframes sd-grow100{0%{transform:scale(0);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50{0%{transform:scale(0.5);opacity:.5}100%{transform:scale(1);opacity:1}}@keyframes sd-grow50-rot20{0%{transform:scale(0.5) rotateZ(-20deg);opacity:.5}75%{transform:scale(1) rotateZ(5deg);opacity:1}95%{transform:scale(1) rotateZ(-1deg);opacity:1}100%{transform:scale(1) rotateZ(0);opacity:1}}.sd-animate-slide-from-left{animation:1s ease-out 0s 1 normal none running sd-slide-from-left}.sd-animate-slide-from-right{animation:1s ease-out 0s 1 normal none running sd-slide-from-right}.sd-animate-grow100{animation:1s ease-out 0s 1 normal none running sd-grow100}.sd-animate-grow50{animation:1s ease-out 0s 1 normal none running sd-grow50}.sd-animate-grow50-rot20{animation:1s ease-out 0s 1 normal none running sd-grow50-rot20}.sd-badge{display:inline-block;padding:.35em .65em;font-size:.75em;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.sd-badge:empty{display:none}a.sd-badge{text-decoration:none}.sd-btn .sd-badge{position:relative;top:-1px}.sd-btn{background-color:transparent;border:1px solid transparent;border-radius:.25rem;cursor:pointer;display:inline-block;font-weight:400;font-size:1rem;line-height:1.5;padding:.375rem .75rem;text-align:center;text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;vertical-align:middle;user-select:none;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none}.sd-btn:hover{text-decoration:none}@media(prefers-reduced-motion: reduce){.sd-btn{transition:none}}.sd-btn-primary,.sd-btn-outline-primary:hover,.sd-btn-outline-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-primary:hover,.sd-btn-primary:focus{color:var(--sd-color-primary-text) !important;background-color:var(--sd-color-primary-highlight) !important;border-color:var(--sd-color-primary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-primary{color:var(--sd-color-primary) !important;border-color:var(--sd-color-primary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary,.sd-btn-outline-secondary:hover,.sd-btn-outline-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-secondary:hover,.sd-btn-secondary:focus{color:var(--sd-color-secondary-text) !important;background-color:var(--sd-color-secondary-highlight) !important;border-color:var(--sd-color-secondary-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-secondary{color:var(--sd-color-secondary) !important;border-color:var(--sd-color-secondary) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success,.sd-btn-outline-success:hover,.sd-btn-outline-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-success:hover,.sd-btn-success:focus{color:var(--sd-color-success-text) !important;background-color:var(--sd-color-success-highlight) !important;border-color:var(--sd-color-success-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-success{color:var(--sd-color-success) !important;border-color:var(--sd-color-success) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info,.sd-btn-outline-info:hover,.sd-btn-outline-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-info:hover,.sd-btn-info:focus{color:var(--sd-color-info-text) !important;background-color:var(--sd-color-info-highlight) !important;border-color:var(--sd-color-info-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-info{color:var(--sd-color-info) !important;border-color:var(--sd-color-info) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning,.sd-btn-outline-warning:hover,.sd-btn-outline-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-warning:hover,.sd-btn-warning:focus{color:var(--sd-color-warning-text) !important;background-color:var(--sd-color-warning-highlight) !important;border-color:var(--sd-color-warning-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-warning{color:var(--sd-color-warning) !important;border-color:var(--sd-color-warning) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger,.sd-btn-outline-danger:hover,.sd-btn-outline-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-danger:hover,.sd-btn-danger:focus{color:var(--sd-color-danger-text) !important;background-color:var(--sd-color-danger-highlight) !important;border-color:var(--sd-color-danger-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-danger{color:var(--sd-color-danger) !important;border-color:var(--sd-color-danger) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light,.sd-btn-outline-light:hover,.sd-btn-outline-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-light:hover,.sd-btn-light:focus{color:var(--sd-color-light-text) !important;background-color:var(--sd-color-light-highlight) !important;border-color:var(--sd-color-light-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-light{color:var(--sd-color-light) !important;border-color:var(--sd-color-light) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted,.sd-btn-outline-muted:hover,.sd-btn-outline-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-muted:hover,.sd-btn-muted:focus{color:var(--sd-color-muted-text) !important;background-color:var(--sd-color-muted-highlight) !important;border-color:var(--sd-color-muted-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-muted{color:var(--sd-color-muted) !important;border-color:var(--sd-color-muted) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark,.sd-btn-outline-dark:hover,.sd-btn-outline-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-dark:hover,.sd-btn-dark:focus{color:var(--sd-color-dark-text) !important;background-color:var(--sd-color-dark-highlight) !important;border-color:var(--sd-color-dark-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-dark{color:var(--sd-color-dark) !important;border-color:var(--sd-color-dark) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black,.sd-btn-outline-black:hover,.sd-btn-outline-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-black:hover,.sd-btn-black:focus{color:var(--sd-color-black-text) !important;background-color:var(--sd-color-black-highlight) !important;border-color:var(--sd-color-black-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-black{color:var(--sd-color-black) !important;border-color:var(--sd-color-black) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white,.sd-btn-outline-white:hover,.sd-btn-outline-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-btn-white:hover,.sd-btn-white:focus{color:var(--sd-color-white-text) !important;background-color:var(--sd-color-white-highlight) !important;border-color:var(--sd-color-white-highlight) !important;border-width:1px !important;border-style:solid !important}.sd-btn-outline-white{color:var(--sd-color-white) !important;border-color:var(--sd-color-white) !important;border-width:1px !important;border-style:solid !important}.sd-stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.sd-hide-link-text{font-size:0}.sd-octicon,.sd-material-icon{display:inline-block;fill:currentColor;vertical-align:middle}.sd-avatar-xs{border-radius:50%;object-fit:cover;object-position:center;width:1rem;height:1rem}.sd-avatar-sm{border-radius:50%;object-fit:cover;object-position:center;width:3rem;height:3rem}.sd-avatar-md{border-radius:50%;object-fit:cover;object-position:center;width:5rem;height:5rem}.sd-avatar-lg{border-radius:50%;object-fit:cover;object-position:center;width:7rem;height:7rem}.sd-avatar-xl{border-radius:50%;object-fit:cover;object-position:center;width:10rem;height:10rem}.sd-avatar-inherit{border-radius:50%;object-fit:cover;object-position:center;width:inherit;height:inherit}.sd-avatar-initial{border-radius:50%;object-fit:cover;object-position:center;width:initial;height:initial}.sd-card{background-clip:border-box;background-color:var(--sd-color-card-background);border:1px solid var(--sd-color-card-border);border-radius:.25rem;color:var(--sd-color-card-text);display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;position:relative;word-wrap:break-word}.sd-card>hr{margin-left:0;margin-right:0}.sd-card-hover:hover{border-color:var(--sd-color-card-border-hover);transform:scale(1.01)}.sd-card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem 1rem}.sd-card-title{margin-bottom:.5rem}.sd-card-subtitle{margin-top:-0.25rem;margin-bottom:0}.sd-card-text:last-child{margin-bottom:0}.sd-card-link:hover{text-decoration:none}.sd-card-link+.card-link{margin-left:1rem}.sd-card-header{padding:.5rem 1rem;margin-bottom:0;background-color:var(--sd-color-card-header);border-bottom:1px solid var(--sd-color-card-border)}.sd-card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.sd-card-footer{padding:.5rem 1rem;background-color:var(--sd-color-card-footer);border-top:1px solid var(--sd-color-card-border)}.sd-card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.sd-card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.sd-card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.sd-card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom,.sd-card-img-top{width:100%}.sd-card-img,.sd-card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.sd-card-img,.sd-card-img-bottom{border-bottom-left-radius:calc(0.25rem - 1px);border-bottom-right-radius:calc(0.25rem - 1px)}.sd-cards-carousel{width:100%;display:flex;flex-wrap:nowrap;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;scroll-snap-type:x mandatory}.sd-cards-carousel.sd-show-scrollbar{overflow-x:auto}.sd-cards-carousel:hover,.sd-cards-carousel:focus{overflow-x:auto}.sd-cards-carousel>.sd-card{flex-shrink:0;scroll-snap-align:start}.sd-cards-carousel>.sd-card:not(:last-child){margin-right:3px}.sd-card-cols-1>.sd-card{width:90%}.sd-card-cols-2>.sd-card{width:45%}.sd-card-cols-3>.sd-card{width:30%}.sd-card-cols-4>.sd-card{width:22.5%}.sd-card-cols-5>.sd-card{width:18%}.sd-card-cols-6>.sd-card{width:15%}.sd-card-cols-7>.sd-card{width:12.8571428571%}.sd-card-cols-8>.sd-card{width:11.25%}.sd-card-cols-9>.sd-card{width:10%}.sd-card-cols-10>.sd-card{width:9%}.sd-card-cols-11>.sd-card{width:8.1818181818%}.sd-card-cols-12>.sd-card{width:7.5%}.sd-container,.sd-container-fluid,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container-xl{margin-left:auto;margin-right:auto;padding-left:var(--sd-gutter-x, 0.75rem);padding-right:var(--sd-gutter-x, 0.75rem);width:100%}@media(min-width: 576px){.sd-container-sm,.sd-container{max-width:540px}}@media(min-width: 768px){.sd-container-md,.sd-container-sm,.sd-container{max-width:720px}}@media(min-width: 992px){.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:960px}}@media(min-width: 1200px){.sd-container-xl,.sd-container-lg,.sd-container-md,.sd-container-sm,.sd-container{max-width:1140px}}.sd-row{--sd-gutter-x: 1.5rem;--sd-gutter-y: 0;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-top:calc(var(--sd-gutter-y) * -1);margin-right:calc(var(--sd-gutter-x) * -0.5);margin-left:calc(var(--sd-gutter-x) * -0.5)}.sd-row>*{box-sizing:border-box;flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--sd-gutter-x) * 0.5);padding-left:calc(var(--sd-gutter-x) * 0.5);margin-top:var(--sd-gutter-y)}.sd-col{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-auto>*{flex:0 0 auto;width:auto}.sd-row-cols-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}@media(min-width: 576px){.sd-col-sm{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-sm-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-sm-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-sm-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-sm-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-sm-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-sm-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-sm-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-sm-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-sm-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-sm-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-sm-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-sm-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-sm-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 768px){.sd-col-md{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-md-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-md-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-md-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-md-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-md-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-md-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-md-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-md-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-md-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-md-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-md-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-md-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-md-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 992px){.sd-col-lg{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-lg-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-lg-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-lg-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-lg-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-lg-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-lg-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-lg-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-lg-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-lg-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-lg-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-lg-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-lg-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-lg-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}@media(min-width: 1200px){.sd-col-xl{flex:1 0 0%;-ms-flex:1 0 0%}.sd-row-cols-xl-auto{flex:1 0 auto;-ms-flex:1 0 auto;width:100%}.sd-row-cols-xl-1>*{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-row-cols-xl-2>*{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-row-cols-xl-3>*{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-row-cols-xl-4>*{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-row-cols-xl-5>*{flex:0 0 auto;-ms-flex:0 0 auto;width:20%}.sd-row-cols-xl-6>*{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-row-cols-xl-7>*{flex:0 0 auto;-ms-flex:0 0 auto;width:14.2857142857%}.sd-row-cols-xl-8>*{flex:0 0 auto;-ms-flex:0 0 auto;width:12.5%}.sd-row-cols-xl-9>*{flex:0 0 auto;-ms-flex:0 0 auto;width:11.1111111111%}.sd-row-cols-xl-10>*{flex:0 0 auto;-ms-flex:0 0 auto;width:10%}.sd-row-cols-xl-11>*{flex:0 0 auto;-ms-flex:0 0 auto;width:9.0909090909%}.sd-row-cols-xl-12>*{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}}.sd-col-auto{flex:0 0 auto;-ms-flex:0 0 auto;width:auto}.sd-col-1{flex:0 0 auto;-ms-flex:0 0 auto;width:8.3333333333%}.sd-col-2{flex:0 0 auto;-ms-flex:0 0 auto;width:16.6666666667%}.sd-col-3{flex:0 0 auto;-ms-flex:0 0 auto;width:25%}.sd-col-4{flex:0 0 auto;-ms-flex:0 0 auto;width:33.3333333333%}.sd-col-5{flex:0 0 auto;-ms-flex:0 0 auto;width:41.6666666667%}.sd-col-6{flex:0 0 auto;-ms-flex:0 0 auto;width:50%}.sd-col-7{flex:0 0 auto;-ms-flex:0 0 auto;width:58.3333333333%}.sd-col-8{flex:0 0 auto;-ms-flex:0 0 auto;width:66.6666666667%}.sd-col-9{flex:0 0 auto;-ms-flex:0 0 auto;width:75%}.sd-col-10{flex:0 0 auto;-ms-flex:0 0 auto;width:83.3333333333%}.sd-col-11{flex:0 0 auto;-ms-flex:0 0 auto;width:91.6666666667%}.sd-col-12{flex:0 0 auto;-ms-flex:0 0 auto;width:100%}.sd-g-0,.sd-gy-0{--sd-gutter-y: 0}.sd-g-0,.sd-gx-0{--sd-gutter-x: 0}.sd-g-1,.sd-gy-1{--sd-gutter-y: 0.25rem}.sd-g-1,.sd-gx-1{--sd-gutter-x: 0.25rem}.sd-g-2,.sd-gy-2{--sd-gutter-y: 0.5rem}.sd-g-2,.sd-gx-2{--sd-gutter-x: 0.5rem}.sd-g-3,.sd-gy-3{--sd-gutter-y: 1rem}.sd-g-3,.sd-gx-3{--sd-gutter-x: 1rem}.sd-g-4,.sd-gy-4{--sd-gutter-y: 1.5rem}.sd-g-4,.sd-gx-4{--sd-gutter-x: 1.5rem}.sd-g-5,.sd-gy-5{--sd-gutter-y: 3rem}.sd-g-5,.sd-gx-5{--sd-gutter-x: 3rem}@media(min-width: 576px){.sd-col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-sm-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-sm-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-sm-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-sm-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-sm-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-sm-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-sm-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-sm-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-sm-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-sm-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-sm-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-sm-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-sm-0,.sd-gy-sm-0{--sd-gutter-y: 0}.sd-g-sm-0,.sd-gx-sm-0{--sd-gutter-x: 0}.sd-g-sm-1,.sd-gy-sm-1{--sd-gutter-y: 0.25rem}.sd-g-sm-1,.sd-gx-sm-1{--sd-gutter-x: 0.25rem}.sd-g-sm-2,.sd-gy-sm-2{--sd-gutter-y: 0.5rem}.sd-g-sm-2,.sd-gx-sm-2{--sd-gutter-x: 0.5rem}.sd-g-sm-3,.sd-gy-sm-3{--sd-gutter-y: 1rem}.sd-g-sm-3,.sd-gx-sm-3{--sd-gutter-x: 1rem}.sd-g-sm-4,.sd-gy-sm-4{--sd-gutter-y: 1.5rem}.sd-g-sm-4,.sd-gx-sm-4{--sd-gutter-x: 1.5rem}.sd-g-sm-5,.sd-gy-sm-5{--sd-gutter-y: 3rem}.sd-g-sm-5,.sd-gx-sm-5{--sd-gutter-x: 3rem}}@media(min-width: 768px){.sd-col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-md-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-md-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-md-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-md-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-md-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-md-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-md-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-md-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-md-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-md-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-md-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-md-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-md-0,.sd-gy-md-0{--sd-gutter-y: 0}.sd-g-md-0,.sd-gx-md-0{--sd-gutter-x: 0}.sd-g-md-1,.sd-gy-md-1{--sd-gutter-y: 0.25rem}.sd-g-md-1,.sd-gx-md-1{--sd-gutter-x: 0.25rem}.sd-g-md-2,.sd-gy-md-2{--sd-gutter-y: 0.5rem}.sd-g-md-2,.sd-gx-md-2{--sd-gutter-x: 0.5rem}.sd-g-md-3,.sd-gy-md-3{--sd-gutter-y: 1rem}.sd-g-md-3,.sd-gx-md-3{--sd-gutter-x: 1rem}.sd-g-md-4,.sd-gy-md-4{--sd-gutter-y: 1.5rem}.sd-g-md-4,.sd-gx-md-4{--sd-gutter-x: 1.5rem}.sd-g-md-5,.sd-gy-md-5{--sd-gutter-y: 3rem}.sd-g-md-5,.sd-gx-md-5{--sd-gutter-x: 3rem}}@media(min-width: 992px){.sd-col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-lg-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-lg-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-lg-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-lg-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-lg-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-lg-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-lg-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-lg-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-lg-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-lg-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-lg-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-lg-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-lg-0,.sd-gy-lg-0{--sd-gutter-y: 0}.sd-g-lg-0,.sd-gx-lg-0{--sd-gutter-x: 0}.sd-g-lg-1,.sd-gy-lg-1{--sd-gutter-y: 0.25rem}.sd-g-lg-1,.sd-gx-lg-1{--sd-gutter-x: 0.25rem}.sd-g-lg-2,.sd-gy-lg-2{--sd-gutter-y: 0.5rem}.sd-g-lg-2,.sd-gx-lg-2{--sd-gutter-x: 0.5rem}.sd-g-lg-3,.sd-gy-lg-3{--sd-gutter-y: 1rem}.sd-g-lg-3,.sd-gx-lg-3{--sd-gutter-x: 1rem}.sd-g-lg-4,.sd-gy-lg-4{--sd-gutter-y: 1.5rem}.sd-g-lg-4,.sd-gx-lg-4{--sd-gutter-x: 1.5rem}.sd-g-lg-5,.sd-gy-lg-5{--sd-gutter-y: 3rem}.sd-g-lg-5,.sd-gx-lg-5{--sd-gutter-x: 3rem}}@media(min-width: 1200px){.sd-col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.sd-col-xl-1{-ms-flex:0 0 auto;flex:0 0 auto;width:8.3333333333%}.sd-col-xl-2{-ms-flex:0 0 auto;flex:0 0 auto;width:16.6666666667%}.sd-col-xl-3{-ms-flex:0 0 auto;flex:0 0 auto;width:25%}.sd-col-xl-4{-ms-flex:0 0 auto;flex:0 0 auto;width:33.3333333333%}.sd-col-xl-5{-ms-flex:0 0 auto;flex:0 0 auto;width:41.6666666667%}.sd-col-xl-6{-ms-flex:0 0 auto;flex:0 0 auto;width:50%}.sd-col-xl-7{-ms-flex:0 0 auto;flex:0 0 auto;width:58.3333333333%}.sd-col-xl-8{-ms-flex:0 0 auto;flex:0 0 auto;width:66.6666666667%}.sd-col-xl-9{-ms-flex:0 0 auto;flex:0 0 auto;width:75%}.sd-col-xl-10{-ms-flex:0 0 auto;flex:0 0 auto;width:83.3333333333%}.sd-col-xl-11{-ms-flex:0 0 auto;flex:0 0 auto;width:91.6666666667%}.sd-col-xl-12{-ms-flex:0 0 auto;flex:0 0 auto;width:100%}.sd-g-xl-0,.sd-gy-xl-0{--sd-gutter-y: 0}.sd-g-xl-0,.sd-gx-xl-0{--sd-gutter-x: 0}.sd-g-xl-1,.sd-gy-xl-1{--sd-gutter-y: 0.25rem}.sd-g-xl-1,.sd-gx-xl-1{--sd-gutter-x: 0.25rem}.sd-g-xl-2,.sd-gy-xl-2{--sd-gutter-y: 0.5rem}.sd-g-xl-2,.sd-gx-xl-2{--sd-gutter-x: 0.5rem}.sd-g-xl-3,.sd-gy-xl-3{--sd-gutter-y: 1rem}.sd-g-xl-3,.sd-gx-xl-3{--sd-gutter-x: 1rem}.sd-g-xl-4,.sd-gy-xl-4{--sd-gutter-y: 1.5rem}.sd-g-xl-4,.sd-gx-xl-4{--sd-gutter-x: 1.5rem}.sd-g-xl-5,.sd-gy-xl-5{--sd-gutter-y: 3rem}.sd-g-xl-5,.sd-gx-xl-5{--sd-gutter-x: 3rem}}.sd-flex-row-reverse{flex-direction:row-reverse !important}details.sd-dropdown{position:relative}details.sd-dropdown .sd-summary-title{font-weight:700;padding-right:3em !important;-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}details.sd-dropdown:hover{cursor:pointer}details.sd-dropdown .sd-summary-content{cursor:default}details.sd-dropdown summary{list-style:none;padding:1em}details.sd-dropdown summary .sd-octicon.no-title{vertical-align:middle}details.sd-dropdown[open] summary .sd-octicon.no-title{visibility:hidden}details.sd-dropdown summary::-webkit-details-marker{display:none}details.sd-dropdown summary:focus{outline:none}details.sd-dropdown .sd-summary-icon{margin-right:.5em}details.sd-dropdown .sd-summary-icon svg{opacity:.8}details.sd-dropdown summary:hover .sd-summary-up svg,details.sd-dropdown summary:hover .sd-summary-down svg{opacity:1;transform:scale(1.1)}details.sd-dropdown .sd-summary-up svg,details.sd-dropdown .sd-summary-down svg{display:block;opacity:.6}details.sd-dropdown .sd-summary-up,details.sd-dropdown .sd-summary-down{pointer-events:none;position:absolute;right:1em;top:1em}details.sd-dropdown[open]>.sd-summary-title .sd-summary-down{visibility:hidden}details.sd-dropdown:not([open])>.sd-summary-title .sd-summary-up{visibility:hidden}details.sd-dropdown:not([open]).sd-card{border:none}details.sd-dropdown:not([open])>.sd-card-header{border:1px solid var(--sd-color-card-border);border-radius:.25rem}details.sd-dropdown.sd-fade-in[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out;animation:sd-fade-in .5s ease-in-out}details.sd-dropdown.sd-fade-in-slide-down[open] summary~*{-moz-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;-webkit-animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out;animation:sd-fade-in .5s ease-in-out,sd-slide-down .5s ease-in-out}.sd-col>.sd-dropdown{width:100%}.sd-summary-content>.sd-tab-set:first-child{margin-top:0}@keyframes sd-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes sd-slide-down{0%{transform:translate(0, -10px)}100%{transform:translate(0, 0)}}.sd-tab-set{border-radius:.125rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.sd-tab-set>input{opacity:0;position:absolute}.sd-tab-set>input:checked+label{border-color:var(--sd-color-tabs-underline-active);color:var(--sd-color-tabs-label-active)}.sd-tab-set>input:checked+label+.sd-tab-content{display:block}.sd-tab-set>input:not(:checked)+label:hover{color:var(--sd-color-tabs-label-hover);border-color:var(--sd-color-tabs-underline-hover)}.sd-tab-set>input:focus+label{outline-style:auto}.sd-tab-set>input:not(.focus-visible)+label{outline:none;-webkit-tap-highlight-color:transparent}.sd-tab-set>label{border-bottom:.125rem solid transparent;margin-bottom:0;color:var(--sd-color-tabs-label-inactive);border-color:var(--sd-color-tabs-underline-inactive);cursor:pointer;font-size:var(--sd-fontsize-tabs-label);font-weight:700;padding:1em 1.25em .5em;transition:color 250ms;width:auto;z-index:1}html .sd-tab-set>label:hover{color:var(--sd-color-tabs-label-active)}.sd-col>.sd-tab-set{width:100%}.sd-tab-content{box-shadow:0 -0.0625rem var(--sd-color-tabs-overline),0 .0625rem var(--sd-color-tabs-underline);display:none;order:99;padding-bottom:.75rem;padding-top:.75rem;width:100%}.sd-tab-content>:first-child{margin-top:0 !important}.sd-tab-content>:last-child{margin-bottom:0 !important}.sd-tab-content>.sd-tab-set{margin:0}.sd-sphinx-override,.sd-sphinx-override *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sd-sphinx-override p{margin-top:0}:root{--sd-color-primary: #0071bc;--sd-color-secondary: #6c757d;--sd-color-success: #28a745;--sd-color-info: #17a2b8;--sd-color-warning: #f0b37e;--sd-color-danger: #dc3545;--sd-color-light: #f8f9fa;--sd-color-muted: #6c757d;--sd-color-dark: #212529;--sd-color-black: black;--sd-color-white: white;--sd-color-primary-highlight: #0060a0;--sd-color-secondary-highlight: #5c636a;--sd-color-success-highlight: #228e3b;--sd-color-info-highlight: #148a9c;--sd-color-warning-highlight: #cc986b;--sd-color-danger-highlight: #bb2d3b;--sd-color-light-highlight: #d3d4d5;--sd-color-muted-highlight: #5c636a;--sd-color-dark-highlight: #1c1f23;--sd-color-black-highlight: black;--sd-color-white-highlight: #d9d9d9;--sd-color-primary-text: #fff;--sd-color-secondary-text: #fff;--sd-color-success-text: #fff;--sd-color-info-text: #fff;--sd-color-warning-text: #212529;--sd-color-danger-text: #fff;--sd-color-light-text: #212529;--sd-color-muted-text: #fff;--sd-color-dark-text: #fff;--sd-color-black-text: #fff;--sd-color-white-text: #212529;--sd-color-shadow: rgba(0, 0, 0, 0.15);--sd-color-card-border: rgba(0, 0, 0, 0.125);--sd-color-card-border-hover: hsla(231, 99%, 66%, 1);--sd-color-card-background: transparent;--sd-color-card-text: inherit;--sd-color-card-header: transparent;--sd-color-card-footer: transparent;--sd-color-tabs-label-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-hover: hsla(231, 99%, 66%, 1);--sd-color-tabs-label-inactive: hsl(0, 0%, 66%);--sd-color-tabs-underline-active: hsla(231, 99%, 66%, 1);--sd-color-tabs-underline-hover: rgba(178, 206, 245, 0.62);--sd-color-tabs-underline-inactive: transparent;--sd-color-tabs-overline: rgb(222, 222, 222);--sd-color-tabs-underline: rgb(222, 222, 222);--sd-fontsize-tabs-label: 1rem} diff --git a/html/_static/design-tabs.js b/html/_static/design-tabs.js new file mode 100644 index 00000000..36b38cf0 --- /dev/null +++ b/html/_static/design-tabs.js @@ -0,0 +1,27 @@ +var sd_labels_by_text = {}; + +function ready() { + const li = document.getElementsByClassName("sd-tab-label"); + for (const label of li) { + syncId = label.getAttribute("data-sync-id"); + if (syncId) { + label.onclick = onLabelClick; + if (!sd_labels_by_text[syncId]) { + sd_labels_by_text[syncId] = []; + } + sd_labels_by_text[syncId].push(label); + } + } +} + +function onLabelClick() { + // Activate other inputs with the same sync id. + syncId = this.getAttribute("data-sync-id"); + for (label of sd_labels_by_text[syncId]) { + if (label === this) continue; + label.previousElementSibling.checked = true; + } + window.localStorage.setItem("sphinx-design-last-tab", syncId); +} + +document.addEventListener("DOMContentLoaded", ready, false); diff --git a/html/_static/document.png b/html/_static/document.png new file mode 100644 index 00000000..4a59e8ef Binary files /dev/null and b/html/_static/document.png differ diff --git a/html/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 b/html/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 new file mode 100644 index 00000000..ab301009 Binary files /dev/null and b/html/_static/fonts/0053ba6958e79f26751eabb555bd73d0.woff2 differ diff --git a/html/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 b/html/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 new file mode 100644 index 00000000..09e03c95 Binary files /dev/null and b/html/_static/fonts/029e176ad602329b4434892101db9cf3.woff2 differ diff --git a/html/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 b/html/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 new file mode 100644 index 00000000..d338178b Binary files /dev/null and b/html/_static/fonts/07ff82964967feebb9c96288e0e0df05.woff2 differ diff --git a/html/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 b/html/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 new file mode 100644 index 00000000..6b0b4afe Binary files /dev/null and b/html/_static/fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2 differ diff --git a/html/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 b/html/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 new file mode 100644 index 00000000..f477fda0 Binary files /dev/null and b/html/_static/fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2 differ diff --git a/html/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 b/html/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 new file mode 100644 index 00000000..9a378af0 Binary files /dev/null and b/html/_static/fonts/0b68e8634c96265eb32a0c769416b5b0.woff2 differ diff --git a/html/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 b/html/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 new file mode 100644 index 00000000..48a8c10f Binary files /dev/null and b/html/_static/fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2 differ diff --git a/html/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 b/html/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 new file mode 100644 index 00000000..6aa28456 Binary files /dev/null and b/html/_static/fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2 differ diff --git a/html/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf b/html/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf new file mode 100644 index 00000000..fbb56251 Binary files /dev/null and b/html/_static/fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf differ diff --git a/html/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 b/html/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 new file mode 100644 index 00000000..5b0171c1 Binary files /dev/null and b/html/_static/fonts/0ec3cc19652785204ea2e322330f0f1b.woff2 differ diff --git a/html/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 b/html/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 new file mode 100644 index 00000000..71c9bb7d Binary files /dev/null and b/html/_static/fonts/0f303f31706d39866cced9dcc17b61fb.woff2 differ diff --git a/html/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 b/html/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 new file mode 100644 index 00000000..186d9986 Binary files /dev/null and b/html/_static/fonts/101522bafe9c61c68698ecc784607772.woff2 differ diff --git a/html/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 b/html/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 new file mode 100644 index 00000000..02a27ead Binary files /dev/null and b/html/_static/fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2 differ diff --git a/html/_static/fonts/1181a8e619707033241139715eca64c6.woff2 b/html/_static/fonts/1181a8e619707033241139715eca64c6.woff2 new file mode 100644 index 00000000..59ed385e Binary files /dev/null and b/html/_static/fonts/1181a8e619707033241139715eca64c6.woff2 differ diff --git a/html/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 b/html/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 new file mode 100644 index 00000000..40b9fda9 Binary files /dev/null and b/html/_static/fonts/122802d03aed4bf8cd6a03997a97aca4.woff2 differ diff --git a/html/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 b/html/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 new file mode 100644 index 00000000..d953103e Binary files /dev/null and b/html/_static/fonts/1383417807f7965daaf94e7c497dcddb.woff2 differ diff --git a/html/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 b/html/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 new file mode 100644 index 00000000..508baefb Binary files /dev/null and b/html/_static/fonts/144860ed1e48e186f08997e6388a9c3f.woff2 differ diff --git a/html/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 b/html/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 new file mode 100644 index 00000000..bdad3dfb Binary files /dev/null and b/html/_static/fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2 differ diff --git a/html/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf b/html/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf new file mode 100644 index 00000000..1a6895d1 Binary files /dev/null and b/html/_static/fonts/1512b579343c6b61c7523cdd838d8328.ttf differ diff --git a/html/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 b/html/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 new file mode 100644 index 00000000..cb9bfa71 Binary files /dev/null and b/html/_static/fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2 differ diff --git a/html/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 b/html/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 new file mode 100644 index 00000000..6d458ad0 Binary files /dev/null and b/html/_static/fonts/1f1481679a64a39f3427547aa1b13f0f.woff2 differ diff --git a/html/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf b/html/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf new file mode 100644 index 00000000..2cf147e1 Binary files /dev/null and b/html/_static/fonts/2096d27efc16cbdd79183bf295c8ebde.ttf differ diff --git a/html/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 b/html/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 new file mode 100644 index 00000000..87711c04 Binary files /dev/null and b/html/_static/fonts/20dc200cc43ab904876fb0c1697ebe39.woff2 differ diff --git a/html/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 b/html/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 new file mode 100644 index 00000000..bc7e1b2c Binary files /dev/null and b/html/_static/fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2 differ diff --git a/html/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 b/html/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 new file mode 100644 index 00000000..d4ec1890 Binary files /dev/null and b/html/_static/fonts/21953b998bab09c1f60c599caee56378.woff2 differ diff --git a/html/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 b/html/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 new file mode 100644 index 00000000..2950a77c Binary files /dev/null and b/html/_static/fonts/22aadc77cafa07b2db9ed560d0320616.woff2 differ diff --git a/html/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 b/html/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 new file mode 100644 index 00000000..51c88fde Binary files /dev/null and b/html/_static/fonts/2325b97b584755067ea4f7f56ee05430.woff2 differ diff --git a/html/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 b/html/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 new file mode 100644 index 00000000..81848e2c Binary files /dev/null and b/html/_static/fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2 differ diff --git a/html/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 b/html/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 new file mode 100644 index 00000000..7e931875 Binary files /dev/null and b/html/_static/fonts/255cf41e0317d95e3992683a76ef28a8.woff2 differ diff --git a/html/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 b/html/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 new file mode 100644 index 00000000..544eddca Binary files /dev/null and b/html/_static/fonts/25c52b9af13f0d1b10719f5289e8c803.woff2 differ diff --git a/html/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 b/html/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 new file mode 100644 index 00000000..cf61b889 Binary files /dev/null and b/html/_static/fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2 differ diff --git a/html/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf b/html/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf new file mode 100644 index 00000000..d7455040 Binary files /dev/null and b/html/_static/fonts/28e6b81b1bc1964707edd4179e4268f5.ttf differ diff --git a/html/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 b/html/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 new file mode 100644 index 00000000..c8091bc9 Binary files /dev/null and b/html/_static/fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2 differ diff --git a/html/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf b/html/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf new file mode 100644 index 00000000..64fca947 Binary files /dev/null and b/html/_static/fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf differ diff --git a/html/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 b/html/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 new file mode 100644 index 00000000..8c63b51b Binary files /dev/null and b/html/_static/fonts/2c0f74be498d2da814c0a84dd6833f70.woff2 differ diff --git a/html/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 b/html/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 new file mode 100644 index 00000000..1f579aa4 Binary files /dev/null and b/html/_static/fonts/2e10480d4154762bc7c8fbb40877e104.woff2 differ diff --git a/html/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 b/html/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 new file mode 100644 index 00000000..e0d3c435 Binary files /dev/null and b/html/_static/fonts/2ea7a97b7c976b121112a088eb398561.woff2 differ diff --git a/html/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf b/html/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf new file mode 100644 index 00000000..ea5c8fe0 Binary files /dev/null and b/html/_static/fonts/2f5c32f094829c0278bce28fe2bbe074.ttf differ diff --git a/html/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 b/html/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 new file mode 100644 index 00000000..4b7a373a Binary files /dev/null and b/html/_static/fonts/2f7c3c315334a99574ee4ceb21af654d.woff2 differ diff --git a/html/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf b/html/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf new file mode 100644 index 00000000..d25425d8 Binary files /dev/null and b/html/_static/fonts/302b0425bf5ea66f37a822a61d723adc.ttf differ diff --git a/html/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 b/html/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 new file mode 100644 index 00000000..c5776a5e Binary files /dev/null and b/html/_static/fonts/3177dacffeac1eb4102852811ae4a2c7.woff2 differ diff --git a/html/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf b/html/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf new file mode 100644 index 00000000..9c48d222 Binary files /dev/null and b/html/_static/fonts/3254c528e2ab56454a9f22191035c5fe.ttf differ diff --git a/html/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 b/html/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 new file mode 100644 index 00000000..53d081f3 Binary files /dev/null and b/html/_static/fonts/32c8a74ac0816253d69a7cc68a60986d.woff2 differ diff --git a/html/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 b/html/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 new file mode 100644 index 00000000..45eae25c Binary files /dev/null and b/html/_static/fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2 differ diff --git a/html/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 b/html/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 new file mode 100644 index 00000000..f3c5f6ac Binary files /dev/null and b/html/_static/fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2 differ diff --git a/html/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 b/html/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 new file mode 100644 index 00000000..cb5834ff Binary files /dev/null and b/html/_static/fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2 differ diff --git a/html/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf b/html/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf new file mode 100644 index 00000000..7c38f724 Binary files /dev/null and b/html/_static/fonts/38f3ee1f96b758f95672c632d8759594.ttf differ diff --git a/html/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 b/html/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 new file mode 100644 index 00000000..b1dc168f Binary files /dev/null and b/html/_static/fonts/392ff374142585f7b886ee1fe66e686e.woff2 differ diff --git a/html/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 b/html/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 new file mode 100644 index 00000000..53b8d0dc Binary files /dev/null and b/html/_static/fonts/3a38c967413f7bce36d3baefc321aade.woff2 differ diff --git a/html/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 b/html/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 new file mode 100644 index 00000000..8a8de615 Binary files /dev/null and b/html/_static/fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2 differ diff --git a/html/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 b/html/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 new file mode 100644 index 00000000..63995528 Binary files /dev/null and b/html/_static/fonts/3c505383d37d2078648e37868bbd1fad.woff2 differ diff --git a/html/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 b/html/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 new file mode 100644 index 00000000..59cab0f1 Binary files /dev/null and b/html/_static/fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2 differ diff --git a/html/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 b/html/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 new file mode 100644 index 00000000..99b1da1b Binary files /dev/null and b/html/_static/fonts/3f1918538864f9681d47a4538d48289c.woff2 differ diff --git a/html/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 b/html/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 new file mode 100644 index 00000000..45f222cc Binary files /dev/null and b/html/_static/fonts/4039566f251699c4b421ed1a38a59b24.woff2 differ diff --git a/html/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 b/html/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 new file mode 100644 index 00000000..8ab91719 Binary files /dev/null and b/html/_static/fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2 differ diff --git a/html/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 b/html/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 new file mode 100644 index 00000000..1f384187 Binary files /dev/null and b/html/_static/fonts/43358c04243de546caddd0898dbf0757.woff2 differ diff --git a/html/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 b/html/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 new file mode 100644 index 00000000..0f6e60b8 Binary files /dev/null and b/html/_static/fonts/435e4b7f9f250d9d9243d4754799fc96.woff2 differ diff --git a/html/_static/fonts/437939342255944b82a49f916404c5fc.woff2 b/html/_static/fonts/437939342255944b82a49f916404c5fc.woff2 new file mode 100644 index 00000000..0bb27069 Binary files /dev/null and b/html/_static/fonts/437939342255944b82a49f916404c5fc.woff2 differ diff --git a/html/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 b/html/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 new file mode 100644 index 00000000..b289f002 Binary files /dev/null and b/html/_static/fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2 differ diff --git a/html/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 b/html/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 new file mode 100644 index 00000000..9d7fb7f8 Binary files /dev/null and b/html/_static/fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2 differ diff --git a/html/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 b/html/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 new file mode 100644 index 00000000..47da3629 Binary files /dev/null and b/html/_static/fonts/495d38d4b9741e8aa4204002414069e2.woff2 differ diff --git a/html/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 b/html/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 new file mode 100644 index 00000000..997a45c6 Binary files /dev/null and b/html/_static/fonts/4c815fdc869f885520f7c8eae6730edf.woff2 differ diff --git a/html/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 b/html/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 new file mode 100644 index 00000000..3c450111 Binary files /dev/null and b/html/_static/fonts/4ec57f2a80b91090971b83970230ca09.woff2 differ diff --git a/html/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 b/html/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 new file mode 100644 index 00000000..fb22fec2 Binary files /dev/null and b/html/_static/fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2 differ diff --git a/html/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 b/html/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 new file mode 100644 index 00000000..de10a3cf Binary files /dev/null and b/html/_static/fonts/4f93c2808e3b69e525c118074e5de31f.woff2 differ diff --git a/html/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 b/html/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 new file mode 100644 index 00000000..2e71425c Binary files /dev/null and b/html/_static/fonts/50aacf068f685be0dd903a91d5bab7d8.woff2 differ diff --git a/html/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 b/html/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 new file mode 100644 index 00000000..c0099878 Binary files /dev/null and b/html/_static/fonts/51f3f41805329fb8341beb56ded833ea.woff2 differ diff --git a/html/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 b/html/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 new file mode 100644 index 00000000..a0f44185 Binary files /dev/null and b/html/_static/fonts/52f28cb4d065b4adfa78df4f9559c639.woff2 differ diff --git a/html/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 b/html/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 new file mode 100644 index 00000000..3df1d8a0 Binary files /dev/null and b/html/_static/fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2 differ diff --git a/html/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 b/html/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 new file mode 100644 index 00000000..100e81a6 Binary files /dev/null and b/html/_static/fonts/5989ef3a21d7f252337ab3326f78bde7.woff2 differ diff --git a/html/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 b/html/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 new file mode 100644 index 00000000..a0d68e2b Binary files /dev/null and b/html/_static/fonts/5b6377da4c959db6d4b22738a27f1bee.woff2 differ diff --git a/html/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 b/html/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 new file mode 100644 index 00000000..f496f9e2 Binary files /dev/null and b/html/_static/fonts/5ce47d5195e59af38114d0b70217baf2.woff2 differ diff --git a/html/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 b/html/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 new file mode 100644 index 00000000..dd5a4a2e Binary files /dev/null and b/html/_static/fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2 differ diff --git a/html/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 b/html/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 new file mode 100644 index 00000000..c2862d73 Binary files /dev/null and b/html/_static/fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2 differ diff --git a/html/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 b/html/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 new file mode 100644 index 00000000..6a258ac6 Binary files /dev/null and b/html/_static/fonts/60eb682678bbea5e8ad71f66f2f65536.woff2 differ diff --git a/html/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 b/html/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 new file mode 100644 index 00000000..fecc1855 Binary files /dev/null and b/html/_static/fonts/63111d307c01b52ffccf7b0319cb7917.woff2 differ diff --git a/html/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 b/html/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 new file mode 100644 index 00000000..122ac2c7 Binary files /dev/null and b/html/_static/fonts/638764dc2513deb09c55fc025f6dd36c.woff2 differ diff --git a/html/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 b/html/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 new file mode 100644 index 00000000..00a4a4be Binary files /dev/null and b/html/_static/fonts/63f4b74ebf127dbeb033126ea988f54e.woff2 differ diff --git a/html/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 b/html/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 new file mode 100644 index 00000000..edfc6cd0 Binary files /dev/null and b/html/_static/fonts/64a6b4e954cf84685cbf8de77eb47344.woff2 differ diff --git a/html/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 b/html/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 new file mode 100644 index 00000000..ae1933f3 Binary files /dev/null and b/html/_static/fonts/661d4b208656c006e7aab58acf778485.woff2 differ diff --git a/html/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 b/html/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 new file mode 100644 index 00000000..ece005fc Binary files /dev/null and b/html/_static/fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2 differ diff --git a/html/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 b/html/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 new file mode 100644 index 00000000..1bb7737c Binary files /dev/null and b/html/_static/fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2 differ diff --git a/html/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf b/html/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf new file mode 100644 index 00000000..3e69acbe Binary files /dev/null and b/html/_static/fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf differ diff --git a/html/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf b/html/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf new file mode 100644 index 00000000..563f4493 Binary files /dev/null and b/html/_static/fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf differ diff --git a/html/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 b/html/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 new file mode 100644 index 00000000..a56a6ede Binary files /dev/null and b/html/_static/fonts/6be97ca17228a69c406231d89c003194.woff2 differ diff --git a/html/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf b/html/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf new file mode 100644 index 00000000..604934aa Binary files /dev/null and b/html/_static/fonts/6de03a64aa8100032abc6e836b3ed803.ttf differ diff --git a/html/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 b/html/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 new file mode 100644 index 00000000..cbe564b0 Binary files /dev/null and b/html/_static/fonts/6deb20301c65a96db17c433ad0cf8158.woff2 differ diff --git a/html/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 b/html/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 new file mode 100644 index 00000000..92fe38dd Binary files /dev/null and b/html/_static/fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2 differ diff --git a/html/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 b/html/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 new file mode 100644 index 00000000..0933dfe8 Binary files /dev/null and b/html/_static/fonts/713780d8b30bda5583052ea847cdcb4f.woff2 differ diff --git a/html/_static/fonts/71e06579279fba7436d58a1c49288909.ttf b/html/_static/fonts/71e06579279fba7436d58a1c49288909.ttf new file mode 100644 index 00000000..454e5d05 Binary files /dev/null and b/html/_static/fonts/71e06579279fba7436d58a1c49288909.ttf differ diff --git a/html/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf b/html/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf new file mode 100644 index 00000000..10f8720c Binary files /dev/null and b/html/_static/fonts/765bd4a97597a4d7781193793477a6cd.ttf differ diff --git a/html/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 b/html/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 new file mode 100644 index 00000000..943c5a0a Binary files /dev/null and b/html/_static/fonts/76945c7494c20515bb45d1dedab8f706.woff2 differ diff --git a/html/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 b/html/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 new file mode 100644 index 00000000..9eda94a2 Binary files /dev/null and b/html/_static/fonts/76da333ab59c6d625cabfb0768f82b4a.woff2 differ diff --git a/html/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 b/html/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 new file mode 100644 index 00000000..c0f0f73b Binary files /dev/null and b/html/_static/fonts/770518db51bed1e082feecc532cfcbf8.woff2 differ diff --git a/html/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 b/html/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 new file mode 100644 index 00000000..6284d2e3 Binary files /dev/null and b/html/_static/fonts/77b24796a3d4ab521f66765651875338.woff2 differ diff --git a/html/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 b/html/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 new file mode 100644 index 00000000..dd0851d5 Binary files /dev/null and b/html/_static/fonts/77ff81100e5a1db3d925f713660700ad.woff2 differ diff --git a/html/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 b/html/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 new file mode 100644 index 00000000..be81ddf5 Binary files /dev/null and b/html/_static/fonts/78a9265759e7b861a1639a36f4c01d04.woff2 differ diff --git a/html/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 b/html/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 new file mode 100644 index 00000000..e0d41239 Binary files /dev/null and b/html/_static/fonts/7af61b2367eba2b1852e837c46a75696.woff2 differ diff --git a/html/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 b/html/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 new file mode 100644 index 00000000..ff1f96d3 Binary files /dev/null and b/html/_static/fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2 differ diff --git a/html/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 b/html/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 new file mode 100644 index 00000000..66efc250 Binary files /dev/null and b/html/_static/fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2 differ diff --git a/html/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 b/html/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 new file mode 100644 index 00000000..067cb322 Binary files /dev/null and b/html/_static/fonts/7e262106f82cc52663e403f5b73795bb.woff2 differ diff --git a/html/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 b/html/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 new file mode 100644 index 00000000..68f094cd Binary files /dev/null and b/html/_static/fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2 differ diff --git a/html/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf b/html/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf new file mode 100644 index 00000000..13a7f42e Binary files /dev/null and b/html/_static/fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf differ diff --git a/html/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 b/html/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 new file mode 100644 index 00000000..11c7018c Binary files /dev/null and b/html/_static/fonts/8007dfe835cfb201b8caaa9651098588.woff2 differ diff --git a/html/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 b/html/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 new file mode 100644 index 00000000..e836b518 Binary files /dev/null and b/html/_static/fonts/83614c36460a4a9734968789cb535de7.woff2 differ diff --git a/html/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf b/html/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf new file mode 100644 index 00000000..99c5795f Binary files /dev/null and b/html/_static/fonts/84e959dd07f302392f0ffd86f87db888.ttf differ diff --git a/html/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 b/html/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 new file mode 100644 index 00000000..8a81a2ff Binary files /dev/null and b/html/_static/fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2 differ diff --git a/html/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 b/html/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 new file mode 100644 index 00000000..ef9a2bdd Binary files /dev/null and b/html/_static/fonts/870e5928dd14fcfe0ce9386107666774.woff2 differ diff --git a/html/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 b/html/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 new file mode 100644 index 00000000..6b05020c Binary files /dev/null and b/html/_static/fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2 differ diff --git a/html/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf b/html/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf new file mode 100644 index 00000000..57a6dc38 Binary files /dev/null and b/html/_static/fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf differ diff --git a/html/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 b/html/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 new file mode 100644 index 00000000..9756ba7c Binary files /dev/null and b/html/_static/fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2 differ diff --git a/html/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf b/html/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf new file mode 100644 index 00000000..68ff2a47 Binary files /dev/null and b/html/_static/fonts/8aa562790559d61dd5178a88a296d70f.ttf differ diff --git a/html/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 b/html/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 new file mode 100644 index 00000000..72fc0214 Binary files /dev/null and b/html/_static/fonts/8c3798e37724f71bc0c63c44a5307413.woff2 differ diff --git a/html/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf b/html/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf new file mode 100644 index 00000000..9c039d63 Binary files /dev/null and b/html/_static/fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf differ diff --git a/html/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 b/html/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 new file mode 100644 index 00000000..f8d7a0d4 Binary files /dev/null and b/html/_static/fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2 differ diff --git a/html/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 b/html/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 new file mode 100644 index 00000000..472bf5a5 Binary files /dev/null and b/html/_static/fonts/9095d663e4d450059bcc2260bb75cd62.woff2 differ diff --git a/html/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 b/html/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 new file mode 100644 index 00000000..5fd10290 Binary files /dev/null and b/html/_static/fonts/90ebb29b5cffa197b184773983ba7e91.woff2 differ diff --git a/html/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 b/html/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 new file mode 100644 index 00000000..cb00b8b5 Binary files /dev/null and b/html/_static/fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2 differ diff --git a/html/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 b/html/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 new file mode 100644 index 00000000..ef920e5a Binary files /dev/null and b/html/_static/fonts/9582ced8a675bf267cc7ac392a86413e.woff2 differ diff --git a/html/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 b/html/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 new file mode 100644 index 00000000..3f7f93ab Binary files /dev/null and b/html/_static/fonts/99be4d68845d66c27c7f7d3a48687b66.woff2 differ diff --git a/html/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 b/html/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 new file mode 100644 index 00000000..663ec4c2 Binary files /dev/null and b/html/_static/fonts/99cf36e763be9cce7b4c59b91841af58.woff2 differ diff --git a/html/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 b/html/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 new file mode 100644 index 00000000..d0c5aa5e Binary files /dev/null and b/html/_static/fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2 differ diff --git a/html/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 b/html/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 new file mode 100644 index 00000000..3f060b34 Binary files /dev/null and b/html/_static/fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2 differ diff --git a/html/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 b/html/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 new file mode 100644 index 00000000..2f2cacd3 Binary files /dev/null and b/html/_static/fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2 differ diff --git a/html/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 b/html/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 new file mode 100644 index 00000000..1d173f2a Binary files /dev/null and b/html/_static/fonts/9fdb12ceee3a402d3a54afe354552459.woff2 differ diff --git a/html/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 b/html/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 new file mode 100644 index 00000000..dd587a2b Binary files /dev/null and b/html/_static/fonts/a6933e678530b263486fa7b185a449ca.woff2 differ diff --git a/html/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 b/html/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 new file mode 100644 index 00000000..9213da01 Binary files /dev/null and b/html/_static/fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2 differ diff --git a/html/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 b/html/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 new file mode 100644 index 00000000..c932cd45 Binary files /dev/null and b/html/_static/fonts/a70ff2592da5e3453943f727633aff54.woff2 differ diff --git a/html/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 b/html/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 new file mode 100644 index 00000000..cce41ce7 Binary files /dev/null and b/html/_static/fonts/aa28d99c7db60ad23f96a5c317615c42.woff2 differ diff --git a/html/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 b/html/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 new file mode 100644 index 00000000..c8ab3b2d Binary files /dev/null and b/html/_static/fonts/aab05142e0e2dadf7df633e061e612ad.woff2 differ diff --git a/html/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 b/html/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 new file mode 100644 index 00000000..477887e3 Binary files /dev/null and b/html/_static/fonts/ab03beb9091fa15ce4e783199e076bc6.woff2 differ diff --git a/html/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf b/html/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf new file mode 100644 index 00000000..aa6a46dd Binary files /dev/null and b/html/_static/fonts/ac848474638236e67a64bc654fb18de0.ttf differ diff --git a/html/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 b/html/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 new file mode 100644 index 00000000..c88b8aea Binary files /dev/null and b/html/_static/fonts/acaac043ca238f0e56e61864456777fa.woff2 differ diff --git a/html/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 b/html/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 new file mode 100644 index 00000000..8571683e Binary files /dev/null and b/html/_static/fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2 differ diff --git a/html/_static/fonts/b019538234514166ec7665359d097403.woff2 b/html/_static/fonts/b019538234514166ec7665359d097403.woff2 new file mode 100644 index 00000000..29342a8d Binary files /dev/null and b/html/_static/fonts/b019538234514166ec7665359d097403.woff2 differ diff --git a/html/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 b/html/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 new file mode 100644 index 00000000..91231c9c Binary files /dev/null and b/html/_static/fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2 differ diff --git a/html/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 b/html/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 new file mode 100644 index 00000000..4ccadd18 Binary files /dev/null and b/html/_static/fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2 differ diff --git a/html/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 b/html/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 new file mode 100644 index 00000000..38d4c74d Binary files /dev/null and b/html/_static/fonts/b4d3c40a77fd9e35a881a79077957055.woff2 differ diff --git a/html/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 b/html/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 new file mode 100644 index 00000000..ee64c936 Binary files /dev/null and b/html/_static/fonts/b4e42731e8d667ae87c3450c345754ae.woff2 differ diff --git a/html/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 b/html/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 new file mode 100644 index 00000000..18c3f128 Binary files /dev/null and b/html/_static/fonts/b57a5ada789f195d5d42f4073a6cf313.woff2 differ diff --git a/html/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 b/html/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 new file mode 100644 index 00000000..a4699c78 Binary files /dev/null and b/html/_static/fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2 differ diff --git a/html/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 b/html/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 new file mode 100644 index 00000000..22ddee9c Binary files /dev/null and b/html/_static/fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2 differ diff --git a/html/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 b/html/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 new file mode 100644 index 00000000..fa67bec9 Binary files /dev/null and b/html/_static/fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2 differ diff --git a/html/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 b/html/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 new file mode 100644 index 00000000..22c57b01 Binary files /dev/null and b/html/_static/fonts/bb8007225d94a099cddbade7ea904667.woff2 differ diff --git a/html/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf b/html/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf new file mode 100644 index 00000000..ce5a5252 Binary files /dev/null and b/html/_static/fonts/bc67bba106323289ea3eda0826de1912.ttf differ diff --git a/html/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 b/html/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 new file mode 100644 index 00000000..20eb7ec2 Binary files /dev/null and b/html/_static/fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2 differ diff --git a/html/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 b/html/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 new file mode 100644 index 00000000..2900346b Binary files /dev/null and b/html/_static/fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2 differ diff --git a/html/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 b/html/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 new file mode 100644 index 00000000..0f11176a Binary files /dev/null and b/html/_static/fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2 differ diff --git a/html/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 b/html/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 new file mode 100644 index 00000000..6363b1c7 Binary files /dev/null and b/html/_static/fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2 differ diff --git a/html/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf b/html/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf new file mode 100644 index 00000000..99e1e894 Binary files /dev/null and b/html/_static/fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf differ diff --git a/html/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 b/html/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 new file mode 100644 index 00000000..27773c96 Binary files /dev/null and b/html/_static/fonts/bfd1a0c9c783e84595589f33e1828a57.woff2 differ diff --git a/html/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 b/html/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 new file mode 100644 index 00000000..b2ffb560 Binary files /dev/null and b/html/_static/fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2 differ diff --git a/html/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 b/html/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 new file mode 100644 index 00000000..7148fac7 Binary files /dev/null and b/html/_static/fonts/c22066c14662d6c80415ae04c5dd9d51.woff2 differ diff --git a/html/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 b/html/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 new file mode 100644 index 00000000..fcadc912 Binary files /dev/null and b/html/_static/fonts/c28a41f656599f6694528b5463c6a445.woff2 differ diff --git a/html/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf b/html/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf new file mode 100644 index 00000000..7a8b630b Binary files /dev/null and b/html/_static/fonts/c6dc61b627bbc5af9130518297bd4f17.ttf differ diff --git a/html/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 b/html/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 new file mode 100644 index 00000000..d2f30b58 Binary files /dev/null and b/html/_static/fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2 differ diff --git a/html/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 b/html/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 new file mode 100644 index 00000000..24a1bfd3 Binary files /dev/null and b/html/_static/fonts/ca7eea0cf248d6e8442c01074765bd33.woff2 differ diff --git a/html/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf b/html/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf new file mode 100644 index 00000000..4242da4d Binary files /dev/null and b/html/_static/fonts/cadfb311297a9362b07fab73934b432a.ttf differ diff --git a/html/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 b/html/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 new file mode 100644 index 00000000..65687e73 Binary files /dev/null and b/html/_static/fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2 differ diff --git a/html/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 b/html/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 new file mode 100644 index 00000000..6abf54d0 Binary files /dev/null and b/html/_static/fonts/ccdebed88064e470c15f37c432922e57.woff2 differ diff --git a/html/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 b/html/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 new file mode 100644 index 00000000..b8dff97b Binary files /dev/null and b/html/_static/fonts/cce2217cc8323fe49789adefb3596291.woff2 differ diff --git a/html/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 b/html/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 new file mode 100644 index 00000000..93cd525d Binary files /dev/null and b/html/_static/fonts/cd3d1f17e048e2116f438bd7157baccf.woff2 differ diff --git a/html/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 b/html/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 new file mode 100644 index 00000000..bfa05a0f Binary files /dev/null and b/html/_static/fonts/d07f561ba87d93460742b060727d9e0d.woff2 differ diff --git a/html/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 b/html/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 new file mode 100644 index 00000000..72ce0e98 Binary files /dev/null and b/html/_static/fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2 differ diff --git a/html/_static/fonts/d422317033deb87342a5e56c7be67458.ttf b/html/_static/fonts/d422317033deb87342a5e56c7be67458.ttf new file mode 100644 index 00000000..6a9fc931 Binary files /dev/null and b/html/_static/fonts/d422317033deb87342a5e56c7be67458.ttf differ diff --git a/html/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 b/html/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 new file mode 100644 index 00000000..b9cee29d Binary files /dev/null and b/html/_static/fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2 differ diff --git a/html/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf b/html/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf new file mode 100644 index 00000000..11a1e9fe Binary files /dev/null and b/html/_static/fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf differ diff --git a/html/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 b/html/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 new file mode 100644 index 00000000..0b792b0b Binary files /dev/null and b/html/_static/fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2 differ diff --git a/html/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 b/html/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 new file mode 100644 index 00000000..fe8fcec7 Binary files /dev/null and b/html/_static/fonts/da6cd48e6dad1888fccc91735e7522f7.woff2 differ diff --git a/html/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 b/html/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 new file mode 100644 index 00000000..3d0f604e Binary files /dev/null and b/html/_static/fonts/daf12b5f1889502004bba85ad71f9fa4.woff2 differ diff --git a/html/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 b/html/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 new file mode 100644 index 00000000..fc71d944 Binary files /dev/null and b/html/_static/fonts/daf51ab540602b2d0b87646621637bac.woff2 differ diff --git a/html/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 b/html/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 new file mode 100644 index 00000000..e1b7a79f Binary files /dev/null and b/html/_static/fonts/db0424fb67fb52e7e538490240cc7fb9.woff2 differ diff --git a/html/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 b/html/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 new file mode 100644 index 00000000..75d29cff Binary files /dev/null and b/html/_static/fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2 differ diff --git a/html/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 b/html/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 new file mode 100644 index 00000000..44819272 Binary files /dev/null and b/html/_static/fonts/dd719f1662079ce6a61260f9af972379.woff2 differ diff --git a/html/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 b/html/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 new file mode 100644 index 00000000..a181dfe7 Binary files /dev/null and b/html/_static/fonts/de018865c95896bb57265fc97c48ebd7.woff2 differ diff --git a/html/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 b/html/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 new file mode 100644 index 00000000..b2391b92 Binary files /dev/null and b/html/_static/fonts/e33716333704ab19fdf9989e072ad49a.woff2 differ diff --git a/html/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 b/html/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 new file mode 100644 index 00000000..9997e98d Binary files /dev/null and b/html/_static/fonts/e56cc9fb5272752b78f144b4be43175d.woff2 differ diff --git a/html/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 b/html/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 new file mode 100644 index 00000000..bfcc76fa Binary files /dev/null and b/html/_static/fonts/e704ef18719c08839bc99a32437ef0f8.woff2 differ diff --git a/html/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 b/html/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 new file mode 100644 index 00000000..677de8b5 Binary files /dev/null and b/html/_static/fonts/e99627cd27de169d23ece4573006af2a.woff2 differ diff --git a/html/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 b/html/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 new file mode 100644 index 00000000..064e94b7 Binary files /dev/null and b/html/_static/fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2 differ diff --git a/html/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 b/html/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 new file mode 100644 index 00000000..074504d6 Binary files /dev/null and b/html/_static/fonts/f154d62b4879af7a22895af7a4ef03f0.woff2 differ diff --git a/html/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 b/html/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 new file mode 100644 index 00000000..0bfb07d7 Binary files /dev/null and b/html/_static/fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2 differ diff --git a/html/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 b/html/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 new file mode 100644 index 00000000..f041fde3 Binary files /dev/null and b/html/_static/fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2 differ diff --git a/html/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 b/html/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 new file mode 100644 index 00000000..5b19d60d Binary files /dev/null and b/html/_static/fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2 differ diff --git a/html/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 b/html/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 new file mode 100644 index 00000000..23fcdf30 Binary files /dev/null and b/html/_static/fonts/f534242dea2255c25b9d05c2371986e3.woff2 differ diff --git a/html/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 b/html/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 new file mode 100644 index 00000000..2bfc2cee Binary files /dev/null and b/html/_static/fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2 differ diff --git a/html/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 b/html/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 new file mode 100644 index 00000000..481279c0 Binary files /dev/null and b/html/_static/fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2 differ diff --git a/html/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 b/html/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 new file mode 100644 index 00000000..771fbecc Binary files /dev/null and b/html/_static/fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2 differ diff --git a/html/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 b/html/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 new file mode 100644 index 00000000..d87fe266 Binary files /dev/null and b/html/_static/fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2 differ diff --git a/html/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 b/html/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 new file mode 100644 index 00000000..020729ef Binary files /dev/null and b/html/_static/fonts/f6734f8177112c0839b961f96d813fcb.woff2 differ diff --git a/html/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 b/html/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 new file mode 100644 index 00000000..60681387 Binary files /dev/null and b/html/_static/fonts/f75911313e1c7802c23345ab57e754d8.woff2 differ diff --git a/html/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 b/html/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 new file mode 100644 index 00000000..4487ab7b Binary files /dev/null and b/html/_static/fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2 differ diff --git a/html/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 b/html/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 new file mode 100644 index 00000000..1351aad4 Binary files /dev/null and b/html/_static/fonts/fb1aaa90783b8cb9375265abeb91b153.woff2 differ diff --git a/html/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 b/html/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 new file mode 100644 index 00000000..94ab5fb0 Binary files /dev/null and b/html/_static/fonts/fc66f942651a9fe1a598770d3d896529.woff2 differ diff --git a/html/_static/full_logo.png b/html/_static/full_logo.png new file mode 100644 index 00000000..b2e77b28 Binary files /dev/null and b/html/_static/full_logo.png differ diff --git a/html/_static/js/rtd_search_config.js b/html/_static/js/rtd_search_config.js new file mode 100644 index 00000000..c512b4db --- /dev/null +++ b/html/_static/js/rtd_search_config.js @@ -0,0 +1,2 @@ + +var RTD_SEARCH_CONFIG = {"default_filter": "project:/", "filters": []}; \ No newline at end of file diff --git a/html/_static/js/rtd_sphinx_search.min.js b/html/_static/js/rtd_sphinx_search.min.js new file mode 100644 index 00000000..ee0b3007 --- /dev/null +++ b/html/_static/js/rtd_sphinx_search.min.js @@ -0,0 +1 @@ +"use strict";function _createForOfIteratorHelper(e,t){var r;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(r=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0,t=function(){};return{s:t,n:function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,l=!1;return{s:function(){r=e[Symbol.iterator]()},n:function(){var e=r.next();return o=e.done,e},e:function(e){l=!0,a=e},f:function(){try{o||null==r.return||r.return()}finally{if(l)throw a}}}}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_unsupportedIterableToArray(e,t)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Map"===(r="Object"===r&&e.constructor?e.constructor.name:r)||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);rSearching ....",a.appendChild(e);return debounce(function(){updateUrl(),updateSearchBar();var e=t+"?"+new URLSearchParams(r).toString();fetch(e,{method:"GET"}).then(function(e){if(!e.ok)throw new Error;return e.json()}).then(function(e){var t;00 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/html/_static/logo.png b/html/_static/logo.png new file mode 100644 index 00000000..41573142 Binary files /dev/null and b/html/_static/logo.png differ diff --git a/html/_static/mispr_citation.bib b/html/_static/mispr_citation.bib new file mode 100644 index 00000000..3d60a500 --- /dev/null +++ b/html/_static/mispr_citation.bib @@ -0,0 +1,5 @@ +@article{atwi2022mispr, + title={MISPR: An automated infrastructure for high-throughput DFT and MD simulations}, + author={Atwi, Rasha and Bliss, Matthew and Makeev, Maxim and Rajput, Nav Nidhi}, + year={2022} +} diff --git a/html/_static/nmr_citation.bib b/html/_static/nmr_citation.bib new file mode 100644 index 00000000..af6f0ea5 --- /dev/null +++ b/html/_static/nmr_citation.bib @@ -0,0 +1,10 @@ +@article{atwi2022automated, + title={An automated framework for high-throughput predictions of NMR chemical shifts within liquid solutions}, + author={Atwi, Rasha and Chen, Ying and Han, Kee Sung and Mueller, Karl T and Murugesan, Vijayakumar and Rajput, Nav Nidhi}, + journal={Nature Computational Science}, + volume={2}, + number={2}, + pages={112--122}, + year={2022}, + publisher={Nature Publishing Group} +} diff --git a/html/_static/overview.png b/html/_static/overview.png new file mode 100644 index 00000000..da7be327 Binary files /dev/null and b/html/_static/overview.png differ diff --git a/html/_static/sphinx_immaterial_theme.359ec555e2989f00f.min.css b/html/_static/sphinx_immaterial_theme.359ec555e2989f00f.min.css new file mode 100644 index 00000000..30546992 --- /dev/null +++ b/html/_static/sphinx_immaterial_theme.359ec555e2989f00f.min.css @@ -0,0 +1,4 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root,[data-md-color-scheme=default]{--md-default-fg-color:rgba(0,0,0,.87);--md-default-fg-color--light:rgba(0,0,0,.54);--md-default-fg-color--lighter:rgba(0,0,0,.32);--md-default-fg-color--lightest:rgba(0,0,0,.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,.7);--md-default-bg-color--lighter:hsla(0,0%,100%,.3);--md-default-bg-color--lightest:hsla(0,0%,100%,.12);--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7);--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,.5);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(255,255,0,.5);--md-typeset-del-color:rgba(245,80,61,.15);--md-typeset-ins-color:rgba(11,213,112,.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,.3);--md-footer-bg-color:rgba(0,0,0,.87);--md-footer-bg-color--dark:rgba(0,0,0,.32);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35)}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}.si-icon-inline:before{background-color:var(--md-default-fg-color);content:"";display:inline-flex;height:1.125em;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;vertical-align:text-top;width:1.125em}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family)}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent)}.md-typeset a code{color:currentcolor;transition:background-color 125ms}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr;font-variant-ligatures:none}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset .code-block-caption+.notranslate .highlighttable,.md-typeset .code-block-caption+.notranslate pre{margin-top:0}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:-webkit-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}.md-typeset abbr[title]:-moz-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}[dir=ltr] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:is(:focus,:hover):after{left:0}[dir=rtl] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:is(:focus,:hover):after{right:0}.md-typeset abbr[title]:is(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li :-webkit-any(ul,ol),.md-typeset ul li :-webkit-any(ul,ol){margin-bottom:.5em;margin-top:.5em}.md-typeset ol li :-moz-any(ul,ol),.md-typeset ul li :-moz-any(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset ol li :-webkit-any(ul,ol),[dir=ltr] .md-typeset ul li :-webkit-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :-moz-any(ul,ol),[dir=ltr] .md-typeset ul li :-moz-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :is(ul,ol),[dir=ltr] .md-typeset ul li :is(ul,ol){margin-left:.625em}[dir=rtl] .md-typeset ol li :-webkit-any(ul,ol),[dir=rtl] .md-typeset ul li :-webkit-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :-moz-any(ul,ol),[dir=rtl] .md-typeset ul li :-moz-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :is(ul,ol),[dir=rtl] .md-typeset ul li :is(ul,ol){margin-right:.625em}.md-typeset ol li :is(ul,ol),.md-typeset ul li :is(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset img[src$="#gh-dark-mode-only"],.md-typeset img[src$="#only-dark"]{display:none}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table.data:not(.plain){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto;width:-moz-max-content;width:max-content}@media print{.md-typeset table.data:not(.plain){display:table}}.md-typeset table.data:not(.plain)+*{margin-top:1.5em}.md-typeset table.data:not(.plain) :-webkit-any(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :-moz-any(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :is(th,td)>:first-child{margin-top:0}.md-typeset table.data:not(.plain) :-webkit-any(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :-moz-any(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :is(th,td)>:last-child{margin-bottom:0}.md-typeset table.data:not(.plain) :-webkit-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}.md-typeset table.data:not(.plain) :-moz-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}.md-typeset table.data:not(.plain) :is(th,td):not([align],.align-center,.align-left,.align-right){text-align:left}[dir=rtl] .md-typeset table.data:not(.plain) :-webkit-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}[dir=rtl] .md-typeset table.data:not(.plain) :-moz-any(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}[dir=rtl] .md-typeset table.data:not(.plain) :is(th,td):not([align],.align-center,.align-left,.align-right){text-align:right}.md-typeset table.data:not(.plain) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table.data:not(.plain) tbody tr{transition:background-color 125ms}.md-typeset table.data:not(.plain) tbody tr:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table.data:not(.plain) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.9375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background:var(--md-typeset-mark-color);color:var(--md-default-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}[dir=ltr] .md-banner__button{float:right}[dir=rtl] .md-banner__button{float:left}.md-banner__button{color:inherit;cursor:pointer;transition:opacity .25s}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.9375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:-webkit-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:-moz-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:is(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:rgba(0,0,0,.54);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.9375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{float:right}[dir=rtl] .md-content__button{float:left}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{align-content:baseline;display:flex;flex-wrap:wrap;justify-content:center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{display:flex;flex-grow:0.01;outline-color:var(--md-accent-fg-color);overflow:hidden;padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}.md-footer__link:-webkit-any(:focus,:hover){opacity:.7}.md-footer__link:-moz-any(:focus,:hover){opacity:.7}.md-footer__link:is(:focus,:hover){opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.9375em){.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:-webkit-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:-moz-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:is(:focus,:hover){color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:is(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:-webkit-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:-moz-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:is(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);display:block;left:0;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.1875em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem}[dir=ltr] .md-header__title{margin-left:1rem}[dir=rtl] .md-header__title{margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-hero{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-size:1rem;overflow:hidden;transition:background .25s}.md-hero__inner{margin-top:1rem;padding:.8rem .8rem .4rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s;transition-delay:.1s}@media screen and (max-width:76.1875em){.md-hero__inner{margin-bottom:1.2rem;margin-top:2.4rem}}[data-md-state=hidden] .md-hero__inner{opacity:0;pointer-events:none;transform:translateY(.625rem);transition:transform 0ms .4s,opacity .1s 0ms}.md-hero--expand .md-hero__inner{margin-bottom:1.2rem}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{align-items:center;display:flex;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;-o-object-fit:contain;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}[dir=ltr] .md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0}.md-nav__link{align-items:center;cursor:pointer;display:flex;margin-top:.625em;scroll-snap-align:start;transition:color 125ms}.md-nav__link.md-nav__sticky{box-shadow:0 -.625em var(--md-default-bg-color),0 .625em var(--md-default-bg-color)}.md-nav__link--passed{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__link--in-viewport{position:relative}.md-nav__link--in-viewport:before{background-color:var(--md-primary-fg-color);bottom:0;content:"";height:100%;position:absolute;right:calc(100% + .3rem);top:0;width:.05rem}.md-nav__item .md-nav__link--index [href]{width:100%}.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__link>*{cursor:pointer;display:flex}.md-nav__sticky{background-color:var(--md-default-bg-color);position:sticky;top:var(--md-nav__header-height,0);z-index:var(--md-nav__sticky-zindex)}.md-nav .md-ellipsis{display:block;flex-grow:1;white-space:normal}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.1875em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__sticky{background-color:transparent;box-shadow:none;position:static;z-index:auto}.md-nav--primary :-webkit-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :-moz-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :is(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;line-height:2.4rem;min-height:5.6rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest);padding:0}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}.md-nav .md-nav__title .md-ellipsis{white-space:nowrap}.md-nav .md-nav__title .md-ellipsis wbr{display:none}}@media screen and (max-width:59.9375em){.md-nav__current-nested{display:none}.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav__current-toc{display:none}.md-nav--secondary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);position:sticky;top:0;z-index:1}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon,.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:-webkit-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:-moz-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:is(:checked,:indeterminate)~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700;pointer-events:none}.md-nav__item--section>.md-nav__link--index [href]{pointer-events:auto}.md-nav__item--section>.md-nav__link .md-nav__icon{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;height:.9rem;transition:background-color .25s,transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{transform:rotate(180deg)}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{background:var(--md-default-bg-color);box-shadow:0 0 .4rem .4rem var(--md-default-bg-color);font-weight:700;margin-top:0;padding:0 .6rem;position:sticky;top:0;z-index:var(--md-nav__sticky-zindex,1)}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link:not(.md-nav__link--index){pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link .md-nav__icon{display:none}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}[dir=ltr] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}[dir=rtl] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-left:.6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested){padding:0 .6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested)>.md-nav__link{padding:0}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__inner{float:right}[dir=rtl] .md-search__inner{float:left}.md-search__inner{padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}}@media screen and (min-width:60em) and (max-width:76.1875em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:transparent;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>*{margin-left:.2rem}[dir=rtl] .md-search__options>*{margin-right:.2rem}.md-search__options>*{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more summary{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-right:2.2rem}}.md-search-result__more summary:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::marker{display:none}.md-search-result__more summary::-webkit-details-marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:transparent;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:-webkit-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-webkit-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:-moz-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-moz-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:is(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}.md-header--lifted~.md-container .md-sidebar{top:4.8rem}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{scrollbar-gutter:stable;-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@supports selector(::-webkit-scrollbar){.md-sidebar__scrollwrap{scrollbar-gutter:auto}[dir=ltr] .md-sidebar__inner{padding-right:calc(100% - 11.5rem)}[dir=rtl] .md-sidebar__inner{padding-left:calc(100% - 11.5rem)}}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@keyframes facts{0%{height:0}to{height:.65rem}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;list-style:none;margin:0;padding:0;white-space:nowrap}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link--active,.md-tabs__link:-webkit-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:-moz-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:is(:focus,:hover){color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}:root{--md-tag-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .md-tags{margin-bottom:.75em;margin-top:-.125em}[dir=ltr] .md-typeset .md-tag{margin-right:.5em}[dir=rtl] .md-typeset .md-tag{margin-left:.5em}.md-typeset .md-tag{background:var(--md-default-fg-color--lightest);border-radius:2.4rem;display:inline-block;font-size:.64rem;font-weight:700;letter-spacing:normal;line-height:1.6;margin-bottom:.5em;padding:.3125em .9375em;vertical-align:middle}.md-typeset .md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-typeset .md-tag[href]:focus,.md-typeset .md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-typeset .md-tag{vertical-align:text-top}.md-typeset .md-tag-icon:before{background-color:var(--md-default-fg-color--lighter);content:"";display:inline-block;height:1.2em;margin-right:.4em;-webkit-mask-image:var(--md-tag-icon);mask-image:var(--md-tag-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset .md-tag-icon:-webkit-any(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}.md-typeset .md-tag-icon:-moz-any(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}.md-typeset .md-tag-icon:is(a:focus,a:hover):before{background-color:var(--md-accent-bg-color)}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest);transform:scale(.95)}75%{box-shadow:0 0 0 .625em transparent;transform:scale(1)}to{box-shadow:0 0 0 0 transparent;transform:scale(.95)}}:root{--md-tooltip-width:20rem}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);font-family:var(--md-text-font-family);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}.md-tooltip--active{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,z-index 0ms;z-index:2}:-webkit-any(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}:-moz-any(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}:is(.focus-visible>.md-tooltip,.md-tooltip:target){outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{font-weight:400;outline:none;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}.md-annotation:not([hidden]){display:inline-block;line-height:1.325}.md-annotation__index{cursor:pointer;font-family:var(--md-code-font-family);font-size:.85em;margin:0 1ch;outline:none;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:0}.md-annotation .md-annotation__index{color:#fff;transition:z-index .25s}.md-annotation .md-annotation__index:-webkit-any(:focus,:hover){color:#fff}.md-annotation .md-annotation__index:-moz-any(:focus,:hover){color:#fff}.md-annotation .md-annotation__index:is(:focus,:hover){color:#fff}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);border-radius:2ch;content:"";height:2.2ch;left:-.125em;margin:0 -.4ch;padding:0 .4ch;position:absolute;top:0;transition:color .25s,background-color .25s;width:calc(100% + 1.2ch);width:max(2.2ch,100% + 1.2ch);z-index:-1}@media not all and (prefers-reduced-motion){[data-md-visible]>.md-annotation__index:after{animation:pulse 2s infinite}}.md-tooltip--active+.md-annotation__index:after{animation:none;transition:color .25s,background-color .25s}code .md-annotation__index{font-family:var(--md-code-font-family);font-size:inherit}:-webkit-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:-moz-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:is(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index){color:var(--md-accent-bg-color)}:-webkit-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}:-moz-any(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}:is(.md-tooltip--active+.md-annotation__index,:hover>.md-annotation__index):after{background-color:var(--md-accent-fg-color)}.md-tooltip--active+.md-annotation__index{animation:none;transition:none;z-index:2}.md-annotation__index [data-md-annotation-id]{display:inline-block;line-height:90%}.md-annotation__index [data-md-annotation-id]:before{content:attr(data-md-annotation-id);display:inline-block;padding-bottom:.1em;transform:scale(1.15);transition:transform .4s cubic-bezier(.1,.7,.1,1);vertical-align:.065em}@media not print{.md-annotation__index [data-md-annotation-id]:before{content:"+"}:focus-within>.md-annotation__index [data-md-annotation-id]:before{transform:scale(1.25) rotate(45deg)}}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:is(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:-webkit-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-webkit-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:-moz-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-moz-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:is(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (pointer:coarse){.md-version:hover .md-version__list{animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border:.05rem solid #448aff;border-radius:.2rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}.md-typeset .admonition>*,.md-typeset details>*{box-sizing:border-box}.md-typeset .admonition :-webkit-any(.admonition,details),.md-typeset details :-webkit-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition :-moz-any(.admonition,details),.md-typeset details :-moz-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition :is(.admonition,details),.md-typeset details :is(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{padding-left:2rem;padding-right:.6rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{padding-left:.6rem;padding-right:2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-left-width:.2rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-right-width:.2rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .admonition-title,[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset .admonition-title,.md-typeset summary{background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin:0 -.6rem;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}[dir=ltr] .md-typeset .admonition-title:before,[dir=ltr] .md-typeset summary:before{left:.6rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{right:.6rem}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset .admonition-title code,.md-typeset summary code{box-shadow:0 0 0 .05rem var(--md-default-fg-color--lightest)}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.note){border-color:#448aff}.md-typeset :-moz-any(.admonition,details):-moz-any(.note){border-color:#448aff}.md-typeset :is(.admonition,details):is(.note){border-color:#448aff}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :is(.note)>:is(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):before{background-color:#448aff;mask-image:var(--md-admonition-icon--note)}.md-typeset :is(.note)>:is(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note)}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):after{color:#448aff}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):after{color:#448aff}.md-typeset :is(.note)>:is(.admonition-title,summary):after{color:#448aff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-moz-any(.admonition,details):-moz-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :is(.admonition,details):is(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):before{background-color:#00b0ff;mask-image:var(--md-admonition-icon--abstract)}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract)}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):after{color:#00b0ff}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):after{color:#00b0ff}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):after{color:#00b0ff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.info,.todo){border-color:#00b8d4}.md-typeset :-moz-any(.admonition,details):-moz-any(.info,.todo){border-color:#00b8d4}.md-typeset :is(.admonition,details):is(.info,.todo){border-color:#00b8d4}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):before{background-color:#00b8d4;mask-image:var(--md-admonition-icon--info)}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info)}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):after{color:#00b8d4}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):after{color:#00b8d4}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):after{color:#00b8d4}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-moz-any(.admonition,details):-moz-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :is(.admonition,details):is(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):before{background-color:#00bfa5;mask-image:var(--md-admonition-icon--tip)}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip)}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):after{color:#00bfa5}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):after{color:#00bfa5}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):after{color:#00bfa5}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.success,.check,.done){border-color:#00c853}.md-typeset :-moz-any(.admonition,details):-moz-any(.success,.check,.done){border-color:#00c853}.md-typeset :is(.admonition,details):is(.success,.check,.done){border-color:#00c853}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):before{background-color:#00c853;mask-image:var(--md-admonition-icon--success)}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success)}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):after{color:#00c853}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):after{color:#00c853}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):after{color:#00c853}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :-moz-any(.admonition,details):-moz-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :is(.admonition,details):is(.question,.help,.faq){border-color:#64dd17}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):before{background-color:#64dd17;mask-image:var(--md-admonition-icon--question)}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question)}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):after{color:#64dd17}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):after{color:#64dd17}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):after{color:#64dd17}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-moz-any(.admonition,details):-moz-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :is(.admonition,details):is(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):before{background-color:#ff9100;mask-image:var(--md-admonition-icon--warning)}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning)}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):after{color:#ff9100}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):after{color:#ff9100}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):after{color:#ff9100}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-moz-any(.admonition,details):-moz-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :is(.admonition,details):is(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):before{background-color:#ff5252;mask-image:var(--md-admonition-icon--failure)}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure)}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):after{color:#ff5252}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):after{color:#ff5252}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):after{color:#ff5252}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.danger,.error){border-color:#ff1744}.md-typeset :-moz-any(.admonition,details):-moz-any(.danger,.error){border-color:#ff1744}.md-typeset :is(.admonition,details):is(.danger,.error){border-color:#ff1744}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):before{background-color:#ff1744;mask-image:var(--md-admonition-icon--danger)}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger)}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):after{color:#ff1744}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):after{color:#ff1744}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):after{color:#ff1744}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.bug){border-color:#f50057}.md-typeset :-moz-any(.admonition,details):-moz-any(.bug){border-color:#f50057}.md-typeset :is(.admonition,details):is(.bug){border-color:#f50057}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :is(.bug)>:is(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):before{background-color:#f50057;mask-image:var(--md-admonition-icon--bug)}.md-typeset :is(.bug)>:is(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug)}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):after{color:#f50057}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):after{color:#f50057}.md-typeset :is(.bug)>:is(.admonition-title,summary):after{color:#f50057}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.example){border-color:#7c4dff}.md-typeset :-moz-any(.admonition,details):-moz-any(.example){border-color:#7c4dff}.md-typeset :is(.admonition,details):is(.example){border-color:#7c4dff}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :is(.example)>:is(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):before{background-color:#7c4dff;mask-image:var(--md-admonition-icon--example)}.md-typeset :is(.example)>:is(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example)}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):after{color:#7c4dff}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):after{color:#7c4dff}.md-typeset :is(.example)>:is(.admonition-title,summary):after{color:#7c4dff}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :-moz-any(.admonition,details):-moz-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :is(.admonition,details):is(.quote,.cite){border-color:#9e9e9e}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):before{background-color:#9e9e9e;mask-image:var(--md-admonition-icon--quote)}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote)}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):after{color:#9e9e9e}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):after{color:#9e9e9e}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):after{color:#9e9e9e}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:-webkit-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:-moz-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:is(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :-webkit-any(:hover,:target)>.headerlink{opacity:1;-webkit-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :-moz-any(:hover,:target)>.headerlink{opacity:1;-moz-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :is(:hover,:target)>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:-webkit-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:-moz-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:is(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset :-webkit-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :-moz-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :is(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto;width:-moz-min-content;width:min-content}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset :-webkit-any(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset :-moz-any(del,ins,.comment).critic{box-decoration-break:clone}.md-typeset :is(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :is(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :is(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.highlight :-webkit-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :-moz-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :is(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight :-webkit-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-moz-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :is(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-webkit-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-moz-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :is(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-webkit-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-moz-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :is(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-webkit-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :is(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.n){color:var(--md-code-hl-name-color)}.highlight :-moz-any(.n){color:var(--md-code-hl-name-color)}.highlight :is(.n){color:var(--md-code-hl-name-color)}.highlight :-webkit-any(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-moz-any(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :is(.kc,.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-webkit-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-moz-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :is(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-webkit-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :is(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-moz-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :is(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-webkit-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-moz-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :is(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-webkit-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-moz-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :is(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-webkit-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :-moz-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :is(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:sticky;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable :-webkit-any(tbody,td){display:block;padding:0}.highlighttable :-moz-any(tbody,td){display:block;padding:0}.highlighttable :is(tbody,td){display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset :-webkit-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-moz-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :is(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset :-webkit-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset :-moz-any(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset :is(.highlight,.highlighttable,.literal-block-wrapper,div[class^=highlight-],.results-prefix)+.result:after{clear:both;content:"";display:block}.md-typeset .results .results-prefix+.result{margin-top:0}.md-typeset .results .results-prefix{background-color:var(--md-code-bg-color);font-size:.85em;font-weight:700;margin-top:-1em;padding:.6617647059em 1.1764705882em}@media screen and (max-width:44.9375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:-webkit-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:-moz-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:is(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"βŽ‡";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"βŒƒ";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"β—†";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"βŒ₯";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"β†’";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇀";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"β‡ͺ";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"–";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"βŽ‹";padding-right:.4em}.md-typeset .keys .key-home:before{content:"β€’";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"βŽ€";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"β‡Ÿ";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"β‡ž";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"βŽ™";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"β‡₯";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌀";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-accent-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-accent-fg-color)}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,transparent);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,transparent);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.9375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-accent-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){background-color:var(--md-accent-fg-color--transparent)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}.rst-versions{font-family:var(--md-text-font-family)}.rst-versions.rst-badge{bottom:inherit!important;font-size:.85rem;height:auto;top:50px}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color)}.mermaid{line-height:normal;margin:1em 0}:root>*{--md-graphviz-edge-color:var(--md-default-fg-color);--md-graphviz-node-bg-color:var(--md-accent-fg-color--transparent);--md-graphviz-node-fg-color:var(--md-accent-fg-color);--md-graphviz-label-bg-color:var(--md-default-bg-color);--md-graphviz-label-fg-color:var(--md-code-fg-color);--md-graphviz-a-hover-color:var(--md-primary-fg-color)}.graphviz{margin:1em 0}.graphviz a:hover>text{fill:var(--md-graphviz-hover-color)!important}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{float:left}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=ltr] .md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}}.md-typeset .align-left{text-align:left}.md-typeset .align-right{text-align:right}.md-typeset .align-center{clear:both;text-align:center}.md-typeset .align-top{vertical-align:top}.md-typeset .align-middle{vertical-align:middle}.md-typeset .align-bottom{vertical-align:bottom}.md-typeset .figure.align-left,.md-typeset figure.align-left,.md-typeset img.align-left,.md-typeset object.align-left,.md-typeset table.align-left{margin-right:auto}.md-typeset .figure.align-center,.md-typeset figure.align-center,.md-typeset img.align-center,.md-typeset object.align-center,.md-typeset table.align-center{margin-left:auto;margin-right:auto}.md-typeset .figure.align-right,.md-typeset figure.align-right,.md-typeset img.align-right,.md-typeset object.align-right,.md-typeset table.align-right{margin-left:auto}.md-typeset .figure.align-center,.md-typeset .figure.align-right,.md-typeset figure.align-center,.md-typeset figure.align-right,.md-typeset img.align-center,.md-typeset img.align-right,.md-typeset object.align-center,.md-typeset object.align-right{display:block}.md-typeset .figure.align-left,.md-typeset .figure.align-right,.md-typeset figure.align-left,.md-typeset figure.align-right,.md-typeset table.align-center,.md-typeset table.align-left,.md-typeset table.align-right{text-align:inherit}.md-typeset .rubric{font-weight:700}.md-typeset .viewcode-block .viewcode-back{float:right}.md-typeset .versionmodified{font-style:italic}.md-typeset div.line-block{display:block}.md-typeset div.line-block div.line-block{margin-left:1.5em}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :is(dl.objdesc,dl.api-field)>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :is(dl.objdesc,dl.api-field)>dt code{border-radius:0;padding:0}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-name:not(.sig-name-nonprimary){color:var(--md-code-hl-name-color);font-weight:700;padding:0}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param{font-style:normal}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param .n:not(.desctype){color:var(--md-default-fg-color--light)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :is(dl.objdesc,dl.api-field)>dt .sig-param a.reference .n:not(.desctype):hover{color:var(--md-accent-fg-color)}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :is(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-param-decl:before{content:"\a ";white-space:pre}.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset :is(dl.objdesc,dl.api-field)>dt.sig-wrap .sig-paren~.sig-paren:before{content:"\a";white-space:pre}.md-typeset dl.objdesc>dd>dl.field-list>dt>.colon{display:none}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name,.md-typeset .sig-inline a.reference:not(.desctype)>.n,.md-typeset .sig-inline a.reference>.sig-name,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference.sig-name,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference>.sig-name{color:var(--md-typeset-a-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline a.reference.sig-name:hover,.md-typeset .sig-inline a.reference:not(.desctype)>.n:hover,.md-typeset .sig-inline a.reference>.sig-name:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference.sig-name:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference:not(.desctype)>.n:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt a.reference>.sig-name:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype,.md-typeset .sig-inline .desctype>a.reference,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference{color:var(--md-code-hl-special-color)}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype .n,.md-typeset .sig-inline .desctype>a.reference .n,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype .n,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference .n{color:inherit}.md-typeset .sig-inline .desctype:-webkit-any(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype:-webkit-any(a.reference):hover,.md-typeset :-webkit-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype:-moz-any(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype:-moz-any(a.reference):hover,.md-typeset :-moz-any(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset .sig-inline .desctype:is(a.reference):hover,.md-typeset .sig-inline .desctype>a.reference:hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype:is(a.reference):hover,.md-typeset :is(dl.objdesc,dl.api-field)>dt .desctype>a.reference:hover{color:var(--md-accent-fg-color)}.md-typeset dl.objdesc>dt{background:var(--md-code-bg-color);font-family:var(--md-code-font-family);padding-left:.5em;padding-right:.5em;padding-top:.5em}.md-typeset dl.objdesc>dt,.md-typeset dl.objdesc>dt code{font-size:.75rem}.md-typeset dl.objdesc>dt .property{color:var(--md-code-hl-keyword-color);font-style:normal;font-weight:700}.md-typeset dl.objdesc>dt .sig-prename{color:var(--md-code-hl-name-color);padding:0}.md-typeset dl.objdesc>dt .viewcode-back,.md-typeset dl.objdesc>dt .viewcode-link{float:right;text-align:right}.md-typeset dl.objdesc>dt.api-include-path,.md-typeset dl.objdesc>dt.api-include-path code{font-size:.65rem}.md-typeset dl.objdesc>dt:first-child{padding-top:.5em}.md-typeset dl.objdesc>dt:last-of-type{padding-bottom:.5em}.md-typeset dl.objdesc>dd dl.field-list>dt{font-size:1em;font-weight:700;margin-bottom:1em}.md-typeset dl.objdesc>dd dd.noindent{margin-left:0}.md-typeset dl.api-field>dt{display:table}.md-typeset dl.api-field>dt a.headerlink{left:.5em;margin-left:0;position:relative;width:0}.md-typeset dl.api-field>dt,.md-typeset dl.api-field>dt code{font-size:.65rem}.md-typeset dl.api-field>dt.api-parameter-kind{float:right;font-family:var(--md-text-font-family)}.md-typeset dl.api-field>dt.api-parameter-kind:before{content:"["}.md-typeset dl.api-field>dt.api-parameter-kind:after{content:"]"}.md-typeset dl.objdesc.summary>dd,.md-typeset dl.objdesc.summary>dd>p:first-child{margin-top:0}.md-typeset .sig-inline:-webkit-any(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-typeset .sig-inline:-moz-any(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-typeset .sig-inline:is(.c-texpr,.cpp-texpr){background-color:unset;font-family:unset}.md-nav__link{white-space:nowrap}:root>*{--objinfo-icon-fg-alias:#e65100;--objinfo-icon-fg-default:#424242;--objinfo-icon-fg-data:#1565c0;--objinfo-icon-fg-procedure:#6a1b9a;--objinfo-icon-fg-sub-data:#2e7d32;--objinfo-icon-bg-default:var(--md-default-bg-color)}@media screen{[data-md-color-scheme=slate]{--objinfo-icon-fg-alias:#ffb74d;--objinfo-icon-fg-default:#e0e0e0;--objinfo-icon-fg-data:#64b5f6;--objinfo-icon-fg-procedure:#ce93d8;--objinfo-icon-fg-sub-data:#81c784}}.objinfo-icon{background-color:var(--objinfo-icon-bg-default);border:1px solid var(--objinfo-icon-fg-default);border-radius:2px;color:var(--objinfo-icon-fg-default);display:inline-table;flex-shrink:0;font-family:var(--md-text-font-family);font-weight:500;height:16px;line-height:16px;margin-right:8px;text-align:center;vertical-align:middle;width:16px}.objinfo-icon__alias{background-color:var(--objinfo-icon-fg-alias);border:1px solid var(--objinfo-icon-fg-alias);color:var(--objinfo-icon-bg-default)}.objinfo-icon__procedure{background-color:var(--objinfo-icon-fg-procedure);border:1px solid var(--objinfo-icon-fg-procedure);color:var(--objinfo-icon-bg-default)}.objinfo-icon__data{background-color:var(--objinfo-icon-fg-data);border:1px solid var(--objinfo-icon-fg-data);color:var(--objinfo-icon-bg-default)}.objinfo-icon__sub-data{background-color:var(--objinfo-icon-fg-sub-data);border:1px solid var(--objinfo-icon-fg-sub-data);color:var(--objinfo-icon-bg-default)}.search-result-objlabel{border:1px solid var(--md-default-fg-color--light);border-radius:2px;float:right;padding:2px}table.longtable.docutils.data.align-default tbody>tr>td>p>a.reference.internal>code.xref.py.py-obj.docutils.literal.notranslate>span.pre{word-break:normal} +@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(66,135,255,.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.3),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.4),0 0 0.05rem rgba(0,0,0,.35)}[data-md-color-scheme=slate] img[src$="#gh-light-mode-only"],[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=slate] img[src$="#only-dark"]{display:initial}[data-md-color-scheme=slate][data-md-color-primary=pink]{--md-typeset-a-color:#ed5487}[data-md-color-scheme=slate][data-md-color-primary=purple]{--md-typeset-a-color:#bd78c9}[data-md-color-scheme=slate][data-md-color-primary=deep-purple]{--md-typeset-a-color:#a682e3}[data-md-color-scheme=slate][data-md-color-primary=indigo]{--md-typeset-a-color:#6c91d5}[data-md-color-scheme=slate][data-md-color-primary=teal]{--md-typeset-a-color:#00ccb8}[data-md-color-scheme=slate][data-md-color-primary=green]{--md-typeset-a-color:#71c174}[data-md-color-scheme=slate][data-md-color-primary=deep-orange]{--md-typeset-a-color:#ff9575}[data-md-color-scheme=slate][data-md-color-primary=brown]{--md-typeset-a-color:#c7846b}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=blue-grey],[data-md-color-scheme=slate][data-md-color-primary=grey],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#6c91d5}[data-md-color-switching] *,[data-md-color-switching] :after,[data-md-color-switching] :before{transition-duration:0ms!important}}[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=light-green]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#72ad2e}[data-md-color-primary=lime]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#8b990a}[data-md-color-primary=yellow]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#b8a500}[data-md-color-primary=amber]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#d19d00}[data-md-color-primary=orange]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#e68a00}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,.7);--md-primary-fg-color--dark:rgba(0,0,0,.07);--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54);--md-typeset-a-color:#4051b5}[data-md-color-primary=white] .md-hero--expand{border-bottom:.05rem solid rgba(0,0,0,.07)}@media screen and (max-width:76.1875em){[data-md-color-primary=white] .md-hero{border-bottom:.05rem solid rgba(0,0,0,.07)}}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header,[data-md-color-primary=black] .md-hero{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}} +@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/2aadfad5aee7ceeaf4eb0924efabe5b4.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8e48cf20cf9f9e5feb7197c79028132b.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/638764dc2513deb09c55fc025f6dd36c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8007dfe835cfb201b8caaa9651098588.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/8c3798e37724f71bc0c63c44a5307413.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/ca7eea0cf248d6e8442c01074765bd33.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/10b31f4cad9ea78d43449886bfbb88ac.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 100;src: url(fonts/0f303f31706d39866cced9dcc17b61fb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/6de03a64aa8100032abc6e836b3ed803.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/0ec3cc19652785204ea2e322330f0f1b.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/b57a5ada789f195d5d42f4073a6cf313.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/4f17f22fc6bff4f3333ccf7ed7126e6d.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/daf12b5f1889502004bba85ad71f9fa4.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/7b63598dcc2a26583b82594bd0e36d5b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/64a6b4e954cf84685cbf8de77eb47344.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 100;src: url(fonts/b19ac4e57f2a56639eebd1c35319e5a7.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/8c49ed8b472d38d3985ec9bbbccea601.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/435e4b7f9f250d9d9243d4754799fc96.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/47aa3bfad6cb9e2d63abdd58f4e6ce4f.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/20dc200cc43ab904876fb0c1697ebe39.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/455c2c1af0a2bf20047a1864d7d7c174.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/51f3f41805329fb8341beb56ded833ea.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/b076e86301cbee8c5c9aef51863a9c0a.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 300;src: url(fonts/f75911313e1c7802c23345ab57e754d8.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/28e6b81b1bc1964707edd4179e4268f5.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/e704ef18719c08839bc99a32437ef0f8.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/76945c7494c20515bb45d1dedab8f706.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/b5b4146d87e5d22d0a4e0d04f3ee5626.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/21953b998bab09c1f60c599caee56378.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/e33716333704ab19fdf9989e072ad49a.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/f53f3b5a15d717b6d21d7885285e90ed.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 300;src: url(fonts/bb8007225d94a099cddbade7ea904667.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/3254c528e2ab56454a9f22191035c5fe.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/b7ef2cd1159a8cbfd271ff2abe07f237.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/495d38d4b9741e8aa4204002414069e2.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/d368cf5bed7856dbafa2af36b51acb9c.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/daf51ab540602b2d0b87646621637bac.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/77b24796a3d4ab521f66765651875338.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/3c23eb02de6b34e30f18cfb7167abd81.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 400;src: url(fonts/f6734f8177112c0839b961f96d813fcb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/0e326670106c8eb6a11a8c30734ecfc8.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/a6caf7b9888eb0c382948c1ca5e8bebb.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/a6933e678530b263486fa7b185a449ca.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/144860ed1e48e186f08997e6388a9c3f.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/2ea7a97b7c976b121112a088eb398561.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/0b68e8634c96265eb32a0c769416b5b0.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/9582ced8a675bf267cc7ac392a86413e.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 400;src: url(fonts/db0424fb67fb52e7e538490240cc7fb9.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/2096d27efc16cbdd79183bf295c8ebde.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/aeed0e51b0bac7c89e5c7e6cf086d7e0.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/3728fbdd191d75bad5b83a838dfe2fc1.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/ef8f0236a7e8b46bc9d642ecf4ab0cb7.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/713780d8b30bda5583052ea847cdcb4f.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/0948409a22b5979aa7e1ec20da9e61f1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/7f1c829b0c90fd664a03bb714a74f7d3.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 500;src: url(fonts/b019538234514166ec7665359d097403.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/38f3ee1f96b758f95672c632d8759594.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/4c815fdc869f885520f7c8eae6730edf.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/6deb20301c65a96db17c433ad0cf8158.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/63111d307c01b52ffccf7b0319cb7917.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/e56cc9fb5272752b78f144b4be43175d.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/2e10480d4154762bc7c8fbb40877e104.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/7af61b2367eba2b1852e837c46a75696.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 500;src: url(fonts/661d4b208656c006e7aab58acf778485.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/ac848474638236e67a64bc654fb18de0.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/3c505383d37d2078648e37868bbd1fad.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/6a84eeee6a25e7c9a8a03191007a6720.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/5b6377da4c959db6d4b22738a27f1bee.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/1c9cc76fd52238330f0aabac35acd2ca.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/4ec57f2a80b91090971b83970230ca09.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/fc66f942651a9fe1a598770d3d896529.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 700;src: url(fonts/f5aebdfea35d1e7656ef4acc5db1f243.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/8aa562790559d61dd5178a88a296d70f.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/ccdebed88064e470c15f37c432922e57.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/c8a9fd4eab4e83382cc66fde70911b41.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/5d7ff31ac7bf945e8d61878f8a941239.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/2a8c422bef4a7099e99dbf0e61ed5e49.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/bdbb6b52604c2451fdcba9cdfd44f4e1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/acaac043ca238f0e56e61864456777fa.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 700;src: url(fonts/6be97ca17228a69c406231d89c003194.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/84e959dd07f302392f0ffd86f87db888.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/f265cee675c0e5b2d6ab263d0edcc754.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/9fdb12ceee3a402d3a54afe354552459.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/76da333ab59c6d625cabfb0768f82b4a.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/2550c2e2d8495c3ed2d4d52f824374f1.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/3a38c967413f7bce36d3baefc321aade.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/2781e9e7c3f369b8fc7965e679b17b60.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: normal;font-weight: 900;src: url(fonts/7e262106f82cc52663e403f5b73795bb.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/2f5c32f094829c0278bce28fe2bbe074.ttf) format('truetype');}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/0d1b73eee266eabb2cff35dfa4ce25a3.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/da6cd48e6dad1888fccc91735e7522f7.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/50aacf068f685be0dd903a91d5bab7d8.woff2) format('woff2');unicode-range: U+1F00-1FFF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/1383417807f7965daaf94e7c497dcddb.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/3f1918538864f9681d47a4538d48289c.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/bfd1a0c9c783e84595589f33e1828a57.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto';font-style: italic;font-weight: 900;src: url(fonts/3cf78ad3bcd1324e10a4acdc34bfc4a1.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/c6dc61b627bbc5af9130518297bd4f17.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/78a9265759e7b861a1639a36f4c01d04.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/2f7c3c315334a99574ee4ceb21af654d.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/870e5928dd14fcfe0ce9386107666774.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/36e39c6463ae1c71c71e69c05e593e1b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/cbfd26d5bcf084ee407a0b2b7599e84b.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 100;src: url(fonts/cce2217cc8323fe49789adefb3596291.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/302b0425bf5ea66f37a822a61d723adc.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/c22066c14662d6c80415ae04c5dd9d51.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/de018865c95896bb57265fc97c48ebd7.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/3177dacffeac1eb4102852811ae4a2c7.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/5989ef3a21d7f252337ab3326f78bde7.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/dd719f1662079ce6a61260f9af972379.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 100;src: url(fonts/07ff82964967feebb9c96288e0e0df05.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/7fa86b886bee5d6ab420a8e89b9f3052.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/4f93c2808e3b69e525c118074e5de31f.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/99be4d68845d66c27c7f7d3a48687b66.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/029e176ad602329b4434892101db9cf3.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/9095d663e4d450059bcc2260bb75cd62.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/1181a8e619707033241139715eca64c6.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 200;src: url(fonts/22aadc77cafa07b2db9ed560d0320616.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/765bd4a97597a4d7781193793477a6cd.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/bd0efe13f0d9d591b337ddc7f289f494.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/ab03beb9091fa15ce4e783199e076bc6.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/a70ff2592da5e3453943f727633aff54.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/0a0ad0eae50e549ecd713b9ad417f1a1.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/d07f561ba87d93460742b060727d9e0d.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 200;src: url(fonts/43358c04243de546caddd0898dbf0757.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/6ad3f6bbe6220cc476a0d3c731d3fb04.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/5dc0e4b14e903ba7f45c581df7402b3f.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/63f4b74ebf127dbeb033126ea988f54e.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/f5f971e9640a9eb86ef553a7e7e999c7.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/0053ba6958e79f26751eabb555bd73d0.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/4207cbc8cb7bc2cbd0bcce565298cbbc.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 300;src: url(fonts/90ebb29b5cffa197b184773983ba7e91.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/71e06579279fba7436d58a1c49288909.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/fb1aaa90783b8cb9375265abeb91b153.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/2325b97b584755067ea4f7f56ee05430.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/f534242dea2255c25b9d05c2371986e3.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/9c9be791a58af8a04c611ca1d13f51c6.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/f2f69e8cd15fdd15a4244c95ec8a8514.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 300;src: url(fonts/555ceea3a65ffbbecf8b7e6d04966c7f.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/6ac1ee292434fac2313c42b0dfb7897c.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/aa28d99c7db60ad23f96a5c317615c42.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/52f28cb4d065b4adfa78df4f9559c639.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/122802d03aed4bf8cd6a03997a97aca4.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/4039566f251699c4b421ed1a38a59b24.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/93b6c99d936df38895a0d95e3ffea2fd.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 400;src: url(fonts/32c8a74ac0816253d69a7cc68a60986d.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/d98f35e926c11f3d5c0c8e3205d43907.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/b93199bb6f964f190f4da04ecdbaf5a4.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/99cf36e763be9cce7b4c59b91841af58.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/1488146d8b2e9859d6c90e6c2b48f7ef.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/255cf41e0317d95e3992683a76ef28a8.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/f154d62b4879af7a22895af7a4ef03f0.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 400;src: url(fonts/dc25cbf4baaf778bd8ae78fbc0e79479.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/1512b579343c6b61c7523cdd838d8328.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/d6f9cdf1a40893111566fcdee3bbe5a9.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/25c52b9af13f0d1b10719f5289e8c803.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/b4e42731e8d667ae87c3450c345754ae.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/214adfc289a2f2af8b0008c59ed0c7f2.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/f55dac651a40fce74a5cf5728d9f8ffc.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 500;src: url(fonts/0e1f73c6737cdf273efb4b79504e4c0a.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/bc67bba106323289ea3eda0826de1912.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/33c5d27ca0eaeb12ebe728ae2fc7106d.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/c13b34dd5b6a35b309944b61c91b2ace.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/392ff374142585f7b886ee1fe66e686e.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/1f1481679a64a39f3427547aa1b13f0f.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/f17ee050ada0453f3bd07bc466c2dde2.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 500;src: url(fonts/6725a7e91680edd1cdc9ed5c26ac05fd.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/bf2ad3287f13eb7076cccb516ec2986f.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/aab05142e0e2dadf7df633e061e612ad.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/8a8dca39f24b52e89e6fd6dcd8b6dd32.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/7b8c2179b6b778308d2ff39bdb82e926.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/77ff81100e5a1db3d925f713660700ad.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/101522bafe9c61c68698ecc784607772.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 600;src: url(fonts/c28a41f656599f6694528b5463c6a445.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/cadfb311297a9362b07fab73934b432a.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/e99627cd27de169d23ece4573006af2a.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/bd51fb0ca67e64c809ffcf7e1370f969.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/437939342255944b82a49f916404c5fc.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/83614c36460a4a9734968789cb535de7.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/d9e6a498dac7e9e91f6e0b4f8930eba0.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 600;src: url(fonts/b4d3c40a77fd9e35a881a79077957055.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/89b4f174a5a728d2d8c85b87990c9ab4.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/bcd47c2f3649cfcaa86a08fb741255d6.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/770518db51bed1e082feecc532cfcbf8.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/85a41b80c5fdc14e3dc48636a30d87dd.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/fb17f56622e45dd4ecee00bb5c63cd2b.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/cd3d1f17e048e2116f438bd7157baccf.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: normal;font-weight: 700;src: url(fonts/6f8d857c5a8545e67de6b60aa0fe5c33.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/d422317033deb87342a5e56c7be67458.ttf) format('truetype');}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/2c0f74be498d2da814c0a84dd6833f70.woff2) format('woff2');unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/9bcbc88b33b2efc2aee821b831499f1c.woff2) format('woff2');unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/8898c4b754d5d96c1a5e1b1d54100554.woff2) format('woff2');unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/9a9bf2d91ebbb1b96eab8eb0b0514bcc.woff2) format('woff2');unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/60eb682678bbea5e8ad71f66f2f65536.woff2) format('woff2');unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;}@font-face {font-family: 'Roboto Mono';font-style: italic;font-weight: 700;src: url(fonts/5ce47d5195e59af38114d0b70217baf2.woff2) format('woff2');unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;} +:root{--si-icon--material_alert-circle:url('data:image/svg+xml;charset=utf-8,');--si-icon--material_delete:url('data:image/svg+xml;charset=utf-8,');}.md-typeset .si-icon-inline.material_alert-circle::before{-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .si-icon-inline.material_delete::before{-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);}.md-typeset .admonition.versionadded{border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title{background-color:rgba(72,138,87,0.1);border-color:rgb(72,138,87);}.md-typeset .versionadded>.admonition-title::before{background-color:rgb(72,138,87);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.versionchanged{border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title{background-color:rgba(238,144,64,0.1);border-color:rgb(238,144,64);}.md-typeset .versionchanged>.admonition-title::before{background-color:rgb(238,144,64);-webkit-mask-image:var(--si-icon--material_alert-circle);mask-image:var(--si-icon--material_alert-circle);}.md-typeset .admonition.deprecated{border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title{background-color:rgba(203,70,83,0.1);border-color:rgb(203,70,83);}.md-typeset .deprecated>.admonition-title::before{background-color:rgb(203,70,83);-webkit-mask-image:var(--si-icon--material_delete);mask-image:var(--si-icon--material_delete);} diff --git a/html/_static/sphinx_immaterial_theme.f9d9eeeb247ace16c.min.js b/html/_static/sphinx_immaterial_theme.f9d9eeeb247ace16c.min.js new file mode 100644 index 00000000..8334adf7 --- /dev/null +++ b/html/_static/sphinx_immaterial_theme.f9d9eeeb247ace16c.min.js @@ -0,0 +1,27 @@ +"use strict";(()=>{var aa=Object.create;var wr=Object.defineProperty;var sa=Object.getOwnPropertyDescriptor;var ca=Object.getOwnPropertyNames,Rt=Object.getOwnPropertySymbols,fa=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,dn=Object.prototype.propertyIsEnumerable;var mn=(e,t,r)=>t in e?wr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,N=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&mn(e,r,t[r]);if(Rt)for(var r of Rt(t))dn.call(t,r)&&mn(e,r,t[r]);return e};var hn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Rt)for(var n of Rt(e))t.indexOf(n)<0&&dn.call(e,n)&&(r[n]=e[n]);return r};var vt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var la=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ca(t))!Er.call(e,o)&&o!==r&&wr(e,o,{get:()=>t[o],enumerable:!(n=sa(t,o))||n.enumerable});return e};var Je=(e,t,r)=>(r=e!=null?aa(fa(e)):{},la(t||!e||!e.__esModule?wr(r,"default",{value:e,enumerable:!0}):r,e));var ze=(e,t,r)=>new Promise((n,o)=>{var i=s=>{try{c(r.next(s))}catch(f){o(f)}},a=s=>{try{c(r.throw(s))}catch(f){o(f)}},c=s=>s.done?n(s.value):Promise.resolve(s.value).then(i,a);c((r=r.apply(e,t)).next())});var vn=vt((Sr,bn)=>{(function(e,t){typeof Sr=="object"&&typeof bn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Sr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function c(x){return!!(x&&x!==document&&x.nodeName!=="HTML"&&x.nodeName!=="BODY"&&"classList"in x&&"contains"in x.classList)}function s(x){var Te=x.type,Le=x.tagName;return!!(Le==="INPUT"&&a[Te]&&!x.readOnly||Le==="TEXTAREA"&&!x.readOnly||x.isContentEditable)}function f(x){x.classList.contains("focus-visible")||(x.classList.add("focus-visible"),x.setAttribute("data-focus-visible-added",""))}function u(x){!x.hasAttribute("data-focus-visible-added")||(x.classList.remove("focus-visible"),x.removeAttribute("data-focus-visible-added"))}function l(x){x.metaKey||x.altKey||x.ctrlKey||(c(r.activeElement)&&f(r.activeElement),n=!0)}function p(x){n=!1}function m(x){!c(x.target)||(n||s(x.target))&&f(x.target)}function h(x){!c(x.target)||(x.target.classList.contains("focus-visible")||x.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(x.target))}function b(x){document.visibilityState==="hidden"&&(o&&(n=!0),v())}function v(){document.addEventListener("mousemove",$),document.addEventListener("mousedown",$),document.addEventListener("mouseup",$),document.addEventListener("pointermove",$),document.addEventListener("pointerdown",$),document.addEventListener("pointerup",$),document.addEventListener("touchmove",$),document.addEventListener("touchstart",$),document.addEventListener("touchend",$)}function V(){document.removeEventListener("mousemove",$),document.removeEventListener("mousedown",$),document.removeEventListener("mouseup",$),document.removeEventListener("pointermove",$),document.removeEventListener("pointerdown",$),document.removeEventListener("pointerup",$),document.removeEventListener("touchmove",$),document.removeEventListener("touchstart",$),document.removeEventListener("touchend",$)}function $(x){x.target.nodeName&&x.target.nodeName.toLowerCase()==="html"||(n=!1,V())}document.addEventListener("keydown",l,!0),document.addEventListener("mousedown",p,!0),document.addEventListener("pointerdown",p,!0),document.addEventListener("touchstart",p,!0),document.addEventListener("visibilitychange",b,!0),v(),r.addEventListener("focus",m,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var gn=vt(Or=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(f){return!1}},r=t(),n=function(f){var u={next:function(){var l=f.shift();return{done:l===void 0,value:l}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(f){return encodeURIComponent(f).replace(/%20/g,"+")},i=function(f){return decodeURIComponent(String(f).replace(/\+/g," "))},a=function(){var f=function(l){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var p=typeof l;if(p!=="undefined")if(p==="string")l!==""&&this._fromString(l);else if(l instanceof f){var m=this;l.forEach(function(V,$){m.append($,V)})}else if(l!==null&&p==="object")if(Object.prototype.toString.call(l)==="[object Array]")for(var h=0;hm[0]?1:0}),f._entries&&(f._entries={});for(var l=0;l1?i(m[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Or);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(s,f){typeof s!="string"&&(s=String(s)),f&&typeof f!="string"&&(f=String(f));var u=document,l;if(f&&(e.location===void 0||f!==e.location.href)){f=f.toLowerCase(),u=document.implementation.createHTMLDocument(""),l=u.createElement("base"),l.href=f,u.head.appendChild(l);try{if(l.href.indexOf(f)!==0)throw new Error(l.href)}catch(x){throw new Error("URL unable to set base "+f+" due to "+x)}}var p=u.createElement("a");p.href=s,l&&(u.body.appendChild(p),p.href=p.href);var m=u.createElement("input");if(m.type="url",m.value=s,p.protocol===":"||!/:/.test(p.href)||!m.checkValidity()&&!f)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:p});var h=new e.URLSearchParams(this.search),b=!0,v=!0,V=this;["append","delete","set"].forEach(function(x){var Te=h[x];h[x]=function(){Te.apply(h,arguments),b&&(v=!1,V.search=h.toString(),v=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var $=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==$&&($=this.search,v&&(b=!1,this.searchParams._fromString(this.search),b=!0))}})},a=i.prototype,c=function(s){Object.defineProperty(a,s,{get:function(){return this._anchorElement[s]},set:function(f){this._anchorElement[s]=f},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(s){c(s)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(s){this._anchorElement.search=s,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var s=this;return function(){return s.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(s){this._anchorElement.href=s,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(s){this._anchorElement.pathname=s},enumerable:!0},origin:{get:function(){var s={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],f=this._anchorElement.port!=s&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(f?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(s){},enumerable:!0},username:{get:function(){return""},set:function(s){},enumerable:!0}}),i.createObjectURL=function(s){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(s){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Or)});var Un=vt((tc,Pt)=>{/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */var yn,xn,wn,En,Sn,On,_n,Tn,Ln,Ht,_r,Mn,An,Cn,it,Rn,Hn,kn,Pn,$n,In,jn,Fn,kt;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(n){e(r(t,r(n)))}):typeof Pt=="object"&&typeof Pt.exports=="object"?e(r(t,r(Pt.exports))):e(r(t));function r(n,o){return n!==t&&(typeof Object.create=="function"?Object.defineProperty(n,"__esModule",{value:!0}):n.__esModule=!0),function(i,a){return n[i]=o?o(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,o){n.__proto__=o}||function(n,o){for(var i in o)Object.prototype.hasOwnProperty.call(o,i)&&(n[i]=o[i])};yn=function(n,o){if(typeof o!="function"&&o!==null)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");t(n,o);function i(){this.constructor=n}n.prototype=o===null?Object.create(o):(i.prototype=o.prototype,new i)},xn=Object.assign||function(n){for(var o,i=1,a=arguments.length;i=0;u--)(f=n[u])&&(s=(c<3?f(s):c>3?f(o,i,s):f(o,i))||s);return c>3&&s&&Object.defineProperty(o,i,s),s},Sn=function(n,o){return function(i,a){o(i,a,n)}},On=function(n,o){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,o)},_n=function(n,o,i,a){function c(s){return s instanceof i?s:new i(function(f){f(s)})}return new(i||(i=Promise))(function(s,f){function u(m){try{p(a.next(m))}catch(h){f(h)}}function l(m){try{p(a.throw(m))}catch(h){f(h)}}function p(m){m.done?s(m.value):c(m.value).then(u,l)}p((a=a.apply(n,o||[])).next())})},Tn=function(n,o){var i={label:0,sent:function(){if(s[0]&1)throw s[1];return s[1]},trys:[],ops:[]},a,c,s,f;return f={next:u(0),throw:u(1),return:u(2)},typeof Symbol=="function"&&(f[Symbol.iterator]=function(){return this}),f;function u(p){return function(m){return l([p,m])}}function l(p){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,c&&(s=p[0]&2?c.return:p[0]?c.throw||((s=c.return)&&s.call(c),0):c.next)&&!(s=s.call(c,p[1])).done)return s;switch(c=0,s&&(p=[p[0]&2,s.value]),p[0]){case 0:case 1:s=p;break;case 4:return i.label++,{value:p[1],done:!1};case 5:i.label++,c=p[1],p=[0];continue;case 7:p=i.ops.pop(),i.trys.pop();continue;default:if(s=i.trys,!(s=s.length>0&&s[s.length-1])&&(p[0]===6||p[0]===2)){i=0;continue}if(p[0]===3&&(!s||p[1]>s[0]&&p[1]=n.length&&(n=void 0),{value:n&&n[a++],done:!n}}};throw new TypeError(o?"Object is not iterable.":"Symbol.iterator is not defined.")},_r=function(n,o){var i=typeof Symbol=="function"&&n[Symbol.iterator];if(!i)return n;var a=i.call(n),c,s=[],f;try{for(;(o===void 0||o-- >0)&&!(c=a.next()).done;)s.push(c.value)}catch(u){f={error:u}}finally{try{c&&!c.done&&(i=a.return)&&i.call(a)}finally{if(f)throw f.error}}return s},Mn=function(){for(var n=[],o=0;o1||u(b,v)})})}function u(b,v){try{l(a[b](v))}catch(V){h(s[0][3],V)}}function l(b){b.value instanceof it?Promise.resolve(b.value.v).then(p,m):h(s[0][2],b)}function p(b){u("next",b)}function m(b){u("throw",b)}function h(b,v){b(v),s.shift(),s.length&&u(s[0][0],s[0][1])}},Hn=function(n){var o,i;return o={},a("next"),a("throw",function(c){throw c}),a("return"),o[Symbol.iterator]=function(){return this},o;function a(c,s){o[c]=n[c]?function(f){return(i=!i)?{value:it(n[c](f)),done:c==="return"}:s?s(f):f}:s}},kn=function(n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var o=n[Symbol.asyncIterator],i;return o?o.call(n):(n=typeof Ht=="function"?Ht(n):n[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(s){i[s]=n[s]&&function(f){return new Promise(function(u,l){f=n[s](f),c(u,l,f.done,f.value)})}}function c(s,f,u,l){Promise.resolve(l).then(function(p){s({value:p,done:u})},f)}},Pn=function(n,o){return Object.defineProperty?Object.defineProperty(n,"raw",{value:o}):n.raw=o,n};var r=Object.create?function(n,o){Object.defineProperty(n,"default",{enumerable:!0,value:o})}:function(n,o){n.default=o};$n=function(n){if(n&&n.__esModule)return n;var o={};if(n!=null)for(var i in n)i!=="default"&&Object.prototype.hasOwnProperty.call(n,i)&&kt(o,n,i);return r(o,n),o},In=function(n){return n&&n.__esModule?n:{default:n}},jn=function(n,o){if(!o.has(n))throw new TypeError("attempted to get private field on non-instance");return o.get(n)},Fn=function(n,o,i){if(!o.has(n))throw new TypeError("attempted to set private field on non-instance");return o.set(n,i),i},e("__extends",yn),e("__assign",xn),e("__rest",wn),e("__decorate",En),e("__param",Sn),e("__metadata",On),e("__awaiter",_n),e("__generator",Tn),e("__exportStar",Ln),e("__createBinding",kt),e("__values",Ht),e("__read",_r),e("__spread",Mn),e("__spreadArrays",An),e("__spreadArray",Cn),e("__await",it),e("__asyncGenerator",Rn),e("__asyncDelegator",Hn),e("__asyncValues",kn),e("__makeTemplateObject",Pn),e("__importStar",$n),e("__importDefault",In),e("__classPrivateFieldGet",jn),e("__classPrivateFieldSet",Fn)})});var Qr=vt((Lt,Jr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT Β© Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Jr=="object"?Jr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ia}});var a=i(279),c=i.n(a),s=i(370),f=i.n(s),u=i(817),l=i.n(u);function p(F){try{return document.execCommand(F)}catch(S){return!1}}var m=function(S){var E=l()(S);return p("cut"),E},h=m;function b(F){var S=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[S?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=F,E}var v=function(S,E){var H=b(S);E.container.appendChild(H);var j=l()(H);return p("copy"),H.remove(),j},V=function(S){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof S=="string"?H=v(S,E):S instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(S==null?void 0:S.type)?H=v(S.value,E):(H=l()(S),p("copy")),H},$=V;function x(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?x=function(E){return typeof E}:x=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},x(F)}var Te=function(){var S=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=S.action,H=E===void 0?"copy":E,j=S.container,K=S.target,Me=S.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(K!==void 0)if(K&&x(K)==="object"&&K.nodeType===1){if(H==="copy"&&K.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(K.hasAttribute("readonly")||K.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return $(Me,{container:j});if(K)return H==="cut"?h(K):$(K,{container:j})},Le=Te;function we(F){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?we=function(E){return typeof E}:we=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},we(F)}function Mt(F,S){if(!(F instanceof S))throw new TypeError("Cannot call a class as a function")}function ot(F,S){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof j.action=="function"?j.action:this.defaultAction,this.target=typeof j.target=="function"?j.target:this.defaultTarget,this.text=typeof j.text=="function"?j.text:this.defaultText,this.container=we(j.container)==="object"?j.container:document.body}},{key:"listenClick",value:function(j){var K=this;this.listener=f()(j,"click",function(Me){return K.onClick(Me)})}},{key:"onClick",value:function(j){var K=j.delegateTarget||j.currentTarget,Me=this.action(K)||"copy",Ct=Le({action:Me,container:this.container,target:this.target(K),text:this.text(K)});this.emit(Ct?"success":"error",{action:Me,text:Ct,trigger:K,clearSelection:function(){K&&K.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(j){return xr("action",j)}},{key:"defaultTarget",value:function(j){var K=xr("target",j);if(K)return document.querySelector(K)}},{key:"defaultText",value:function(j){return xr("text",j)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(j){var K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return $(j,K)}},{key:"cut",value:function(j){return h(j)}},{key:"isSupported",value:function(){var j=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],K=typeof j=="string"?[j]:j,Me=!!document.queryCommandSupported;return K.forEach(function(Ct){Me=Me&&!!document.queryCommandSupported(Ct)}),Me}}]),E}(c()),ia=oa},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(c,s){for(;c&&c.nodeType!==o;){if(typeof c.matches=="function"&&c.matches(s))return c;c=c.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function c(u,l,p,m,h){var b=f.apply(this,arguments);return u.addEventListener(p,b,h),{destroy:function(){u.removeEventListener(p,b,h)}}}function s(u,l,p,m,h){return typeof u.addEventListener=="function"?c.apply(null,arguments):typeof p=="function"?c.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(b){return c(b,l,p,m,h)}))}function f(u,l,p,m){return function(h){h.delegateTarget=a(h.target,l),h.delegateTarget&&m.call(u,h)}}n.exports=s},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),c=i(438);function s(p,m,h){if(!p&&!m&&!h)throw new Error("Missing required arguments");if(!a.string(m))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(p))return f(p,m,h);if(a.nodeList(p))return u(p,m,h);if(a.string(p))return l(p,m,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function f(p,m,h){return p.addEventListener(m,h),{destroy:function(){p.removeEventListener(m,h)}}}function u(p,m,h){return Array.prototype.forEach.call(p,function(b){b.addEventListener(m,h)}),{destroy:function(){Array.prototype.forEach.call(p,function(b){b.removeEventListener(m,h)})}}}function l(p,m,h){return c(document.body,p,m,h)}n.exports=s},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var c=i.hasAttribute("readonly");c||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),c||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var s=window.getSelection(),f=document.createRange();f.selectNodeContents(i),s.removeAllRanges(),s.addRange(f),a=s.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,c){var s=this.e||(this.e={});return(s[i]||(s[i]=[])).push({fn:a,ctx:c}),this},once:function(i,a,c){var s=this;function f(){s.off(i,f),a.apply(c,arguments)}return f._=a,this.on(i,f,c)},emit:function(i){var a=[].slice.call(arguments,1),c=((this.e||(this.e={}))[i]||[]).slice(),s=0,f=c.length;for(s;s{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Ls=/["'&<>]/;Ti.exports=Ms;function Ms(e){var t=""+e,r=Ls.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,c=o.observers;return i||a?Tr:(this.currentObservers=null,c.push(r),new $e(function(){n.currentObservers=null,Ve(c,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new Xn(r,n)},t}(U);var Xn=function(e){re(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Tr},t}(L);var yt={now:function(){return(yt.delegate||Date).now()},delegate:void 0};var xt=function(e){re(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=yt);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,c=n._timestampProvider,s=n._windowTime;o||(i.push(r),!a&&i.push(c.now()+s)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,c=a.slice(),s=0;s0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ft.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ft.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Dt);var to=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var fe=new to(eo);var k=new U(function(e){return e.complete()});function zt(e){return e&&T(e.schedule)}function kr(e){return e[e.length-1]}function qe(e){return T(kr(e))?e.pop():void 0}function Ee(e){return zt(kr(e))?e.pop():void 0}function qt(e,t){return typeof kr(e)=="number"?e.pop():t}var lt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Kt(e){return T(e==null?void 0:e.then)}function Bt(e){return T(e[ct])}function Yt(e){return Symbol.asyncIterator&&T(e==null?void 0:e[Symbol.asyncIterator])}function Gt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function ya(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Jt=ya();function Qt(e){return T(e==null?void 0:e[Jt])}function Xt(e){return Dn(this,arguments,function(){var r,n,o,i;return $t(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,It(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,It(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,It(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Zt(e){return T(e==null?void 0:e.getReader)}function D(e){if(e instanceof U)return e;if(e!=null){if(Bt(e))return xa(e);if(lt(e))return wa(e);if(Kt(e))return Ea(e);if(Yt(e))return ro(e);if(Qt(e))return Sa(e);if(Zt(e))return Oa(e)}throw Gt(e)}function xa(e){return new U(function(t){var r=e[ct]();if(T(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function wa(e){return new U(function(t){for(var r=0;r=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new L}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,c=e.resetOnRefCountZero,s=c===void 0?!0:c;return function(f){var u,l,p,m=0,h=!1,b=!1,v=function(){l==null||l.unsubscribe(),l=void 0},V=function(){v(),u=p=void 0,h=b=!1},$=function(){var x=u;V(),x==null||x.unsubscribe()};return y(function(x,Te){m++,!b&&!h&&v();var Le=p=p!=null?p:r();Te.add(function(){m--,m===0&&!b&&!h&&(l=Dr($,s))}),Le.subscribe(Te),!u&&m>0&&(u=new Xe({next:function(we){return Le.next(we)},error:function(we){b=!0,v(),l=Dr(V,o,we),Le.error(we)},complete:function(){h=!0,v(),l=Dr(V,a),Le.complete()}}),D(x).subscribe(u))})(f)}}function Dr(e,t){for(var r=[],n=2;ne.next(document)),e}function W(e,t=document){return Array.from(t.querySelectorAll(e))}function B(e,t=document){let r=ie(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ie(e,t=document){return t.querySelector(e)||void 0}function Fe(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function nr(e){return P(w(document.body,"focusin"),w(document.body,"focusout")).pipe(He(1),d(()=>{let t=Fe();return typeof t!="undefined"?e.contains(t):!1}),q(e===Fe()),Q())}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function Oo(e){return P(w(window,"load"),w(window,"resize")).pipe(Re(0,fe),d(()=>Be(e)),q(Be(e)))}function or(e){return{x:e.scrollLeft,y:e.scrollTop}}function _t(e){return P(w(e,"scroll"),w(window,"resize")).pipe(Re(0,fe),d(()=>or(e)),q(or(e)))}var To=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Br||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Ka?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Br||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=qa.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Lo=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Ao=typeof WeakMap!="undefined"?new WeakMap:new To,Co=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ba.getInstance(),n=new ns(t,r,this);Ao.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Co.prototype[e]=function(){var t;return(t=Ao.get(this))[e].apply(t,arguments)}});var os=function(){return typeof ir.ResizeObserver!="undefined"?ir.ResizeObserver:Co}(),Ro=os;var Ho=new L,is=I(()=>C(new Ro(e=>{for(let t of e)Ho.next(t)}))).pipe(_(e=>P(je,C(e)).pipe(R(()=>e.disconnect()))),X(1));function Se(e){return{width:e.offsetWidth,height:e.offsetHeight}}function de(e){return is.pipe(M(t=>t.observe(e)),_(t=>Ho.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),d(()=>Se(e)))),q(Se(e)))}function Tt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ko(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Po=new L,as=I(()=>C(new IntersectionObserver(e=>{for(let t of e)Po.next(t)},{threshold:0}))).pipe(_(e=>P(je,C(e)).pipe(R(()=>e.disconnect()))),X(1));function cr(e){return as.pipe(M(t=>t.observe(e)),_(t=>Po.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),d(({isIntersecting:r})=>r))))}var fr={drawer:B("[data-md-toggle=drawer]"),search:B("[data-md-toggle=search]")};function $o(e){return fr[e].checked}function Ye(e,t){fr[e].checked!==t&&fr[e].click()}function ht(e){let t=fr[e];return w(t,"change").pipe(d(()=>t.checked),q(t.checked))}function ss(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Io(){return w(window,"keydown").pipe(A(e=>!(e.metaKey||e.ctrlKey)),d(e=>({mode:$o("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),A(({mode:e,type:t})=>{if(e==="global"){let r=Fe();if(typeof r!="undefined")return!ss(r,t)}return!0}),pe())}function Oe(){return new URL(location.href)}function lr(e){location.href=e.href}function jo(){return new L}function Fo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Fo(e,r)}function O(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)Fo(n,o);return n}function Uo(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function ur(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Vo(){return location.hash.substring(1)}function No(e){let t=O("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function cs(){return w(window,"hashchange").pipe(d(Vo),q(Vo()),A(e=>e.length>0),X(1))}function Do(){return cs().pipe(d(e=>ie(`[id="${e}"]`)),A(e=>typeof e!="undefined"))}function Yr(e){let t=matchMedia(e);return tr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function Wo(){let e=matchMedia("print");return P(w(window,"beforeprint").pipe(d(()=>!0)),w(window,"afterprint").pipe(d(()=>!1))).pipe(q(e.matches))}function Gr(e,t){return e.pipe(_(r=>r?t():k))}function pr(e,t={credentials:"same-origin"}){return be(fetch(`${e}`,t)).pipe(le(()=>k),_(r=>r.status!==200?Et(()=>new Error(r.statusText)):C(r)))}function Ge(e,t){return pr(e,t).pipe(_(r=>r.json()),X(1))}function zo(e,t){let r=new DOMParser;return pr(e,t).pipe(_(n=>n.text()),d(n=>r.parseFromString(n,"text/xml")),X(1))}function qo(e){let t=O("script",{src:e});return I(()=>(document.head.appendChild(t),P(w(t,"load"),w(t,"error").pipe(_(()=>Et(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(d(()=>{}),R(()=>document.head.removeChild(t)),ve(1))))}function Ko(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function Bo(){return P(w(window,"scroll",{passive:!0}),w(window,"resize",{passive:!0})).pipe(d(Ko),q(Ko()))}function Yo(){return{width:innerWidth,height:innerHeight}}function Go(){return w(window,"resize",{passive:!0}).pipe(d(Yo),q(Yo()))}function Jo(){return G([Bo(),Go()]).pipe(d(([e,t])=>({offset:e,size:t})),X(1))}function mr(e,{viewport$:t,header$:r}){let n=t.pipe(J("size")),o=G([n,r]).pipe(d(()=>Be(e)));return G([r,t,o]).pipe(d(([{height:i},{offset:a,size:c},{x:s,y:f}])=>({offset:{x:a.x-s,y:a.y-f+i},size:c})))}var fs=B("#__config"),bt=JSON.parse(fs.textContent);bt.base=`${new URL(bt.base,Oe())}`;function ce(){return bt}function Z(e){return bt.features.includes(e)}function ae(e,t){return typeof t!="undefined"?bt.translations[e].replace("#",t.toString()):bt.translations[e]}function _e(e,t=document){return B(`[data-md-component=${e}]`,t)}function ee(e,t=document){return W(`[data-md-component=${e}]`,t)}function ls(e){let t=B(".md-typeset > :first-child",e);return w(t,"click",{once:!0}).pipe(d(()=>B(".md-typeset",e)),d(r=>({hash:__md_hash(r.innerHTML)})))}function Qo(e){return!Z("announce.dismiss")||!e.childElementCount?k:I(()=>{let t=new L;return t.pipe(q({hash:__md_get("__announce")})).subscribe(({hash:r})=>{var n;r&&r===((n=__md_get("__announce"))!=null?n:r)&&(e.hidden=!0,__md_set("__announce",r))}),ls(e).pipe(M(r=>t.next(r)),R(()=>t.complete()),d(r=>N({ref:e},r)))})}function us(e,{target$:t}){return t.pipe(d(r=>({hidden:r!==e})))}function Xo(e,t){let r=new L;return r.subscribe(({hidden:n})=>{e.hidden=n}),us(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>N({ref:e},n)))}var fi=Je(Qr());function Xr(e){return O("div",{class:"md-tooltip",id:e},O("div",{class:"md-tooltip__inner md-typeset"}))}function Zo(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return O("aside",{class:"md-annotation",tabIndex:0},Xr(t),O("a",{href:r,class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}else return O("aside",{class:"md-annotation",tabIndex:0},Xr(t),O("span",{class:"md-annotation__index",tabIndex:-1},O("span",{"data-md-annotation-id":e})))}function ei(e){return O("button",{class:"md-clipboard md-icon",title:ae("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Zr(e,t){let r=t&2,n=t&1,o=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,s)=>[...c,O("del",null,s)," "],[]).slice(0,-1),i=new URL(e.location);Z("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[s])=>`${c} ${s}`.trim(),""));let{tags:a}=ce();return O("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},O("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&O("div",{class:"md-search-result__icon md-icon"}),O("h1",{class:"md-search-result__title"},e.title),n>0&&e.text.length>0&&O("p",{class:"md-search-result__teaser"},Uo(e.text,320)),e.tags&&O("div",{class:"md-typeset"},e.tags.map(c=>{let s=c.replace(/<[^>]+>/g,""),f=a?s in a?`md-tag-icon md-tag-icon--${a[s]}`:"md-tag-icon":"";return O("span",{class:`md-tag ${f}`},c)})),n>0&&o.length>0&&O("p",{class:"md-search-result__terms"},ae("search.result.term.missing"),": ",...o)))}function ti(e){let t=e[0].score,r=[...e],n=r.findIndex(f=>!f.location.includes("#")),[o]=r.splice(n===-1?0:n,1),i=r.findIndex(f=>f.scoreZr(f,1)),...c.length?[O("details",{class:"md-search-result__more"},O("summary",{tabIndex:-1},c.length>0&&c.length===1?ae("search.result.more.one"):ae("search.result.more.other",c.length)),...c.map(f=>Zr(f,1)))]:[]];return O("li",{class:"md-search-result__item"},s)}function ri(e){return O("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>O("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ur(r):r)))}function en(e){let t=`tabbed-control tabbed-control--${e}`;return O("div",{class:t,hidden:!0},O("button",{class:"tabbed-button",tabIndex:-1}))}function ni(e){return O("div",{class:"md-typeset__scrollwrap"},O("div",{class:"md-typeset__table"},e))}function ps(e){let t=ce(),r=new URL(`${e.version}/`,new URL("../",t.base));return O("li",{class:"md-version__item"},O("a",{href:`${r}`,class:"md-version__link"},e.title))}function oi(e,t){return O("div",{class:"md-version"},O("button",{class:"md-version__current","aria-label":ae("select.version.title")},t.title),O("ul",{class:"md-version__list"},e.map(ps)))}function ms(e,t){let r=I(()=>G([Oo(e),_t(t)])).pipe(d(([{x:n,y:o},i])=>{let{width:a,height:c}=Se(e);return{x:n-i.x+a/2,y:o-i.y+c/2}}));return nr(e).pipe(_(n=>r.pipe(d(o=>({active:n,offset:o})),ve(+!n||1/0))))}function ii(e,t,{target$:r}){let[n,o]=Array.from(e.children);return I(()=>{let i=new L,a=i.pipe(ue(1));return i.subscribe({next({offset:c}){e.style.setProperty("--md-tooltip-x",`${c.x}px`),e.style.setProperty("--md-tooltip-y",`${c.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),cr(e).pipe(te(a)).subscribe(c=>{e.toggleAttribute("data-md-visible",c)}),P(i.pipe(A(({active:c})=>c)),i.pipe(He(250),A(({active:c})=>!c))).subscribe({next({active:c}){c?e.prepend(n):n.remove()},complete(){e.prepend(n)}}),i.pipe(Re(16,fe)).subscribe(({active:c})=>{n.classList.toggle("md-tooltip--active",c)}),i.pipe(Kr(125,fe),A(()=>!!e.offsetParent),d(()=>e.offsetParent.getBoundingClientRect()),d(({x:c})=>c)).subscribe({next(c){c?e.style.setProperty("--md-tooltip-0",`${-c}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),w(o,"click").pipe(te(a),A(c=>!(c.metaKey||c.ctrlKey))).subscribe(c=>c.preventDefault()),w(o,"mousedown").pipe(te(a),me(i)).subscribe(([c,{active:s}])=>{var f;if(c.button!==0||c.metaKey||c.ctrlKey)c.preventDefault();else if(s){c.preventDefault();let u=e.parentElement.closest(".md-annotation");u instanceof HTMLElement?u.focus():(f=Fe())==null||f.blur()}}),r.pipe(te(a),A(c=>c===n),ke(125)).subscribe(()=>e.focus()),ms(e,t).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>N({ref:e},c)))})}function ds(e){let t=[];for(let r of W(".c, .c1, .cm",e)){let n=[],o=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=o.nextNode();i;i=o.nextNode())n.push(i);for(let i of n){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,c,s]=a;if(typeof s=="undefined"){let f=i.splitText(a.index);i=f.splitText(c.length),t.push(f)}else{i.textContent=c,t.push(i);break}}}}return t}function ai(e,t){t.append(...Array.from(e.childNodes))}function si(e,t,{target$:r,print$:n}){let o=t.closest("[id]"),i=o==null?void 0:o.id,a=new Map;for(let c of ds(t)){let[,s]=c.textContent.match(/\((\d+)\)/);ie(`li:nth-child(${s})`,e)&&(a.set(s,Zo(s,i)),c.replaceWith(a.get(s)))}return a.size===0?k:I(()=>{let c=new L,s=[];for(let[f,u]of a)s.push([B(".md-typeset",u),B(`li:nth-child(${f})`,e)]);return n.pipe(te(c.pipe(ue(1)))).subscribe(f=>{e.hidden=!f;for(let[u,l]of s)f?ai(u,l):ai(l,u)}),P(...[...a].map(([,f])=>ii(f,t,{target$:r}))).pipe(R(()=>c.complete()),pe())})}var hs=0;function li(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return li(t)}}function ci(e){return de(e).pipe(d(({width:t})=>({scrollable:Tt(e).width>t})),J("scrollable"))}function ui(e,t){let{matches:r}=matchMedia("(hover)"),n=I(()=>{let o=new L;if(o.subscribe(({scrollable:a})=>{a&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")}),fi.default.isSupported()){let a=e.closest("pre");a.id=`__code_${++hs}`,a.insertBefore(ei(a.id),e)}let i=e.closest(".highlight");if(i instanceof HTMLElement){let a=li(i);if(typeof a!="undefined"&&(i.classList.contains("annotate")||Z("content.code.annotate"))){let c=si(a,e,t);return ci(e).pipe(M(s=>o.next(s)),R(()=>o.complete()),d(s=>N({ref:e},s)),tt(de(i).pipe(d(({width:s,height:f})=>s&&f),Q(),_(s=>s?c:k))))}}return ci(e).pipe(M(a=>o.next(a)),R(()=>o.complete()),d(a=>N({ref:e},a)))});return Z("content.lazy")?cr(e).pipe(A(o=>o),ve(1),_(()=>n)):n}var pi=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:transparent}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}defs #flowchart-circleEnd,defs #flowchart-circleStart,defs #flowchart-crossEnd,defs #flowchart-crossStart,defs #flowchart-pointEnd,defs #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}.actor,defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{stroke:var(--md-mermaid-node-fg-color)}text.actor>tspan{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-default-fg-color--lighter)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-edge-color)}.loopText>tspan,.messageText,.noteText>tspan{font-family:var(--md-mermaid-font-family)!important}#arrowhead path,.loopText>tspan,.messageText,.noteText>tspan{fill:var(--md-mermaid-edge-color);stroke:none}.loopLine{stroke:var(--md-mermaid-node-fg-color)}.labelBox,.loopLine{fill:var(--md-mermaid-node-bg-color)}.labelBox{stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-node-fg-color);font-family:var(--md-mermaid-font-family)}";var tn,vs=0,gs=ce();function ys(){return typeof mermaid=="undefined"||mermaid instanceof Element?qo(`${gs.base}_static/mermaid/mermaid.min.js`):C(void 0)}function mi(e){return e.classList.remove("mermaid"),tn||(tn=ys().pipe(M(()=>mermaid.initialize({startOnLoad:!1,themeCSS:pi,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),d(()=>{}),X(1))),tn.subscribe(()=>{e.classList.add("mermaid");let t=`__mermaid_${vs++}`,r=O("div",{class:"mermaid"});mermaid.mermaidAPI.render(t,e.textContent,n=>{let o=r.attachShadow({mode:"closed"});o.innerHTML=n,e.replaceWith(r)})}),tn.pipe(d(()=>({ref:e})))}function xs(e,{target$:t,print$:r}){let n=!0;return P(t.pipe(d(o=>o.closest("details:not([open])")),A(o=>e===o),d(()=>({action:"open",reveal:!0}))),r.pipe(A(o=>o||!n),M(()=>n=e.open),d(o=>({action:o?"open":"close"}))))}function di(e,t){return I(()=>{let r=new L;return r.subscribe(({action:n,reveal:o})=>{e.toggleAttribute("open",n==="open"),o&&e.scrollIntoView()}),xs(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>N({ref:e},n)))})}var hi=O("table");function bi(e){return e.replaceWith(hi),hi.replaceWith(ni(e)),C({ref:e})}function ws(e){let t=W(":scope > input",e),r=t.find(n=>n.checked)||t[0];return P(...t.map(n=>w(n,"change").pipe(d(()=>B(`label[for="${n.id}"]`))))).pipe(q(B(`label[for="${r.id}"]`)),d(n=>({active:n})))}function vi(e,{viewport$:t}){let r=en("prev");e.append(r);let n=en("next");e.append(n);let o=B(".tabbed-labels",e);return I(()=>{let i=new L,a=i.pipe(ue(1));return G([i,de(e)]).pipe(Re(1,fe),te(a)).subscribe({next([{active:c},s]){let f=Be(c),{width:u}=Se(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let l=or(o);(f.xl.x+s.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),G([_t(o),de(o)]).pipe(te(a)).subscribe(([c,s])=>{let f=Tt(o);r.hidden=c.x<16,n.hidden=c.x>f.width-s.width-16}),P(w(r,"click").pipe(d(()=>-1)),w(n,"click").pipe(d(()=>1))).pipe(te(a)).subscribe(c=>{let{width:s}=Se(o);o.scrollBy({left:s*c,behavior:"smooth"})}),Z("content.tabs.link")&&i.pipe(Pe(1),me(t)).subscribe(([{active:c},{offset:s}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-s.y;for(let p of W("[data-tabs]"))for(let m of W(":scope > input",p)){let h=B(`label[for="${m.id}"]`);if(h!==c&&h.innerText.trim()===f){h.setAttribute("data-md-switching",""),m.click();break}}window.scrollTo({top:e.offsetTop-u});let l=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...l])])}}),ws(e).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>N({ref:e},c)))}).pipe(Ze(se))}function gi(e,{viewport$:t,target$:r,print$:n}){return P(...W("pre:not(.mermaid) > code",e).map(o=>ui(o,{target$:r,print$:n})),...W("pre.mermaid",e).map(o=>mi(o)),...W("table:not([class])",e).map(o=>bi(o)),...W("details",e).map(o=>di(o,{target$:r,print$:n})),...W("[data-tabs]",e).map(o=>vi(o,{viewport$:t})))}function Es(e,{alert$:t}){return t.pipe(_(r=>P(C(!0),C(!1).pipe(ke(2e3))).pipe(d(n=>({message:r,active:n})))))}function yi(e,t){let r=B(".md-typeset",e);return I(()=>{let n=new L;return n.subscribe(({message:o,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=o}),Es(e,t).pipe(M(o=>n.next(o)),R(()=>n.complete()),d(o=>N({ref:e},o)))})}function Ss({viewport$:e}){if(!Z("header.autohide"))return C(!1);let t=e.pipe(d(({offset:{y:o}})=>o),Ne(2,1),d(([o,i])=>[oMath.abs(i-o.y)>100),d(([,[o]])=>o),Q()),n=ht("search");return G([e,n]).pipe(d(([{offset:o},i])=>o.y>400&&!i),Q(),_(o=>o?r:C(!1)),q(!1))}function xi(e,t){return I(()=>G([de(e),Ss(t)])).pipe(d(([{height:r},n])=>({height:r,hidden:n})),Q((r,n)=>r.height===n.height&&r.hidden===n.hidden),X(1))}function wi(e,{header$:t,main$:r}){return I(()=>{let n=new L,o=n.pipe(ue(1));return n.pipe(J("active"),St(t)).subscribe(([{active:i},{hidden:a}])=>{e.classList.toggle("md-header--shadow",i&&!a),e.hidden=a}),r.subscribe(n),t.pipe(te(o),d(i=>N({ref:e},i)))})}function Os(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(d(({offset:{y:n}})=>{let{height:o}=Se(e);return{active:n>=o}}),J("active"))}function Ei(e,t){return I(()=>{let r=new L;r.subscribe(({active:o})=>{e.classList.toggle("md-header__title--active",o)});let n=ie("article h1, .objdesc > dt .descname");return typeof n=="undefined"?k:Os(n,t).pipe(M(o=>r.next(o)),R(()=>r.complete()),d(o=>N({ref:e},o)))})}function Si(e,{viewport$:t,header$:r}){let n=r.pipe(d(({height:i})=>i),Q()),o=n.pipe(_(()=>de(e).pipe(d(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),J("bottom"))));return G([n,o,t]).pipe(d(([i,{top:a,bottom:c},{offset:{y:s},size:{height:f}}])=>(f=Math.max(0,f-Math.max(0,a-s,i)-Math.max(0,f+s-c)),{offset:a-i,height:f,active:a-i<=s})),Q((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function _s(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return C(...e).pipe(oe(r=>w(r,"change").pipe(d(()=>r))),q(e[Math.max(0,t.index)]),d(r=>({index:e.indexOf(r),color:{scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),X(1))}function Oi(e){return I(()=>{let t=new L;t.subscribe(n=>{document.body.setAttribute("data-md-color-switching","");for(let[o,i]of Object.entries(n.color))document.body.setAttribute(`data-md-color-${o}`,i);for(let o=0;o{document.body.removeAttribute("data-md-color-switching")});let r=W("input",e);return _s(r).pipe(M(n=>t.next(n)),R(()=>t.complete()),d(n=>N({ref:e},n)))})}function Ts(e){let t=a=>a.trim(),{searchParams:r}=Oe(),n;if(r.has("q")){Ye("search",!0);let a=r.get("q");n=C(a)}else n=C();ht("search").pipe(A(a=>!a),ve(1)).subscribe(()=>{let a=new URL(location.href);a.searchParams.delete("q"),history.replaceState({},"",`${a}`)}),n.subscribe(a=>{a&&(e.value=a,e.focus())});let o=nr(e),i=P(w(e,"keyup"),w(e,"focus").pipe(ke(1)),n).pipe(d(()=>t(e.value)),q(""),Q());return G([i,o]).pipe(d(([a,c])=>({value:a,focus:c})),X(1))}function _i(e){let t=new L,r=t.pipe(ue(1));return t.pipe(J("focus")).subscribe(({focus:n})=>{n?(Ye("search",n),e.placeholder=""):e.placeholder=ae("search.placeholder")}),w(e.form,"reset").pipe(te(r)).subscribe(()=>e.focus()),Ts(e).pipe(M(n=>t.next(n)),R(()=>t.complete()),d(n=>N({ref:e},n)),pe())}var on=Je(rn());var As=ce();function nn(e){return`${As.base}${e}`}var dr;function Li(e){return new Promise((t,r)=>{let n=document.createElement("script"),o=nn(e);n.src=o,n.addEventListener("load",()=>t()),n.addEventListener("error",()=>{console.error(`Failed to load search data: ${o}`),r()}),document.body.appendChild(n)})}function Cs(){return dr!==void 0||(dr=Promise.all([Li("_static/language_data.js"),Li("searchindex.js")]).then(()=>{})),dr}var Ue={objNameMatch:11,objPartialMatch:6,objPrio:{0:15,1:5,2:-5},objPrioDefault:0,title:15,partialTitle:7,term:5,partialTerm:2},an;window.Search={setIndex:e=>{an=e}};var Rs=!1;function Hs(e,t){let{docurls:r,objects:n,objnames:o,titles:i}=an,a=[];function c(s,f,u,l,p,m,h){var V;let b=(s?`${s}.`:"")+m,v=b.toLowerCase();if(v.indexOf(e)>-1){let $=0,x=v.split(".");v===e||x[x.length-1]===e?$+=Ue.objNameMatch:x[x.length-1].indexOf(e)>-1&&($+=Ue.objPartialMatch);let Te=o[u][2],Le=i[f];if(t.length>0){let we=`${s} ${m} ${Te} ${Le} ${h!=null?h:""}`.toLowerCase(),Mt=!0;for(let ot=0;ot2){let m=sn(u);if(!o[u])for(let h in o)h.match(m)&&p.push({files:o[h],score:Ue.partialTerm});if(!i[u])for(let h in i)h.match(m)&&p.push({files:i[h],score:Ue.partialTitle})}if(p.every(m=>m.files===void 0))break;p.forEach(m=>{let h=m.files;if(h!==void 0){Array.isArray(h)||(h=[h]),l.push(...h);for(let b=0;bm.length>2).length;if(!(a[u].length!==e.length&&a[u].length!==p)){for(let m=0;mc[f][h]));s.push({docurl:r[f],title:n[f],anchor:"",objectLabel:null,synopsis:null,score:m})}}}return s}function $s(e){let t=new DOMParser().parseFromString(e,"text/html");t.querySelectorAll(".headerlink").forEach(s=>{var f;(f=s.parentNode)==null||f.removeChild(s)});let r=t.querySelector("[role=main]");if(r===null)return console.warn("Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template."),[];let n=r.querySelectorAll("h1, h2, h3, h4, h5, h6"),o,i=[],a=t.createRange(),c=(s,f)=>{var m;s!==void 0?a.setStartAfter(s):a.setStartBefore(r),f!==void 0?a.setEndBefore(f):a.setEndAfter(r);let u=a.toString().trim(),l=(m=s==null?void 0:s.textContent)==null?void 0:m.trim();if(!l&&!u)return;let p=s!==void 0?`#${s.id}`:"";i.push({title:l!=null?l:"",anchor:p,text:u})};return n.forEach(s=>{if(!s.id)return;let u=o;o=s,c(u,s)}),c(o,void 0),i}function Is(e,t){let r=$s(e),n=t.map(i=>new RegExp(sn(i),"im")),o=[];for(let i=0;ii.score!==a.score?a.score-i.score:i.sectionIndex-a.sectionIndex),o.length!==0)return o.map(i=>{let c=r[i.sectionIndex],s=Math.max(i.snippetIndex-240/2,0);return{snippet:(s>0?"\u2026":"")+c.text.substr(s,240).trim()+(s+240${(0,on.default)(e.objectLabel)}`,text:r(e.synopsis)}];let a=nn(e.docurl),c;if(window.location.protocol!=="file:")try{let l=yield(yield fetch(a)).text();c=Is(l,t)}catch(u){console.warn("Failed to retrieve search result document: ",u)}c===void 0&&(c=[{score:-1,title:"",anchor:"",snippet:"",terms:i}]);let s=[];c[0].score!==-1&&s.push({location:n,score:e.score,terms:i,title:r(o),text:""});let f;for(let u of c)f===void 0&&(f=u.score),s.push({location:n+u.anchor,score:u.score===f?e.score:0,terms:u.terms,title:r(u.title||o),text:r(u.snippet)});return s})}function Fs(e){return new DOMParser().parseFromString(e,"text/html").body.textContent||""}function Mi(e){return ze(this,null,function*(){yield Cs();let t=new Stemmer,r=[],n=[],o=[],i=[];for(let u of ks(e)){let l=!1;u[0]==="-"&&(l=!0,u=u.substr(1));let p=u.toLowerCase();if(p.length===0)continue;i.push(p);let m=!1;for(let h of p.matchAll(/\w+/g)){let b=h[0];if(stopwords.indexOf(b)!==-1)continue;let v=t.stemWord(b);v.length<3&&b.length>=3&&(v=b);let V;l?V=n:(V=r,m=!0),V.indexOf(v)===-1&&V.push(v)}!l&&m&&o.push(p)}let a=[];for(let u=0;u{let p=u.score,m=l.score;if(p!==m)return m-p;let h=u.title.toLowerCase(),b=l.title.toLowerCase();return h>b?1:h`${u}`,f=u=>(0,on.default)(u).replace(c,s).replace(/<\/mark>(\s+)]*>/gim,"$1");return{count:a.length,get:u=>js(a[u],o,f)}})}function Ai(e,{query$:t}){let r=B(":scope > :first-child",e),n=B(":scope > :last-child",e),o,i,a=e.parentElement,c=16,s=()=>a.scrollTop+a.clientHeight+c>a.scrollHeight,f=()=>{i!==void 0&&s()&&(i(),i=void 0)};a.addEventListener("scroll",f,{passive:!0}),window.addEventListener("resize",f,{passive:!0});let u=l=>ze(this,null,function*(){o=l;let p=4,m=p;for(let h=0;h{i=()=>v(void 0)})),m+=p),o!==l)return;let b=yield l.get(h);if(o!==l)return;n.appendChild(ti(b))}});return t.pipe(J("value"),Fr(()=>$r(250)),mt(l=>ze(this,null,function*(){if(!!l.value)return Mi(l.value)})),Ce(fe)).subscribe(l=>{if(n.innerHTML="",l){switch(l.count){case 0:r.textContent=ae("search.result.none");break;case 1:r.textContent=ae("search.result.one");break;default:r.textContent=ae("search.result.other",ur(l.count))}u(l)}else r.textContent=ae("search.result.placeholder")}),C()}function Us(e,{query$:t}){return t.pipe(d(({value:r})=>{let n=Oe();return n.hash="",n.searchParams.delete("h"),n.searchParams.set("q",r),{url:n}}))}function Ci(e,t){let r=new L;return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),w(e,"click").subscribe(n=>n.preventDefault()),Us(e,t).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>N({ref:e},n)))}function Ri(e,{keyboard$:t}){let r=_e("search-query");return t.pipe(A(({mode:n})=>n==="search")).subscribe(n=>{switch(n.type){case"ArrowRight":e.innerText.length&&r.selectionStart===r.value.length&&(r.value=e.innerText);break}}),C()}function Hi(e,{keyboard$:t}){try{let r=_e("search-query",e),n=_e("search-result",e);t.pipe(A(({mode:a})=>a==="search")).subscribe(a=>{let c=Fe();switch(a.type){case"Enter":if(c===r){let s=new Map;for(let f of W(":first-child [href]",n)){let u=f.firstElementChild;s.set(f,parseFloat(u.getAttribute("data-md-score")))}if(s.size){let[[f]]=[...s].sort(([,u],[,l])=>l-u);f.click()}a.claim()}break;case"Escape":case"Tab":Ye("search",!1),r.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")r.focus();else{let s=[r,...W(":not(details) > [href], summary, details[open] [href]",n)],f=Math.max(0,(Math.max(0,s.indexOf(c))+s.length+(a.type==="ArrowUp"?-1:1))%s.length);s[f].focus()}a.claim();break;default:r!==Fe()&&r.focus()}}),t.pipe(A(({mode:a})=>a==="global")).subscribe(a=>{switch(a.type){case"f":case"s":case"/":r.focus(),r.select(),a.claim();break}});let o=_i(r),i=Ai(n,{query$:o});return P(o,i).pipe(tt(...ee("search-share",e).map(a=>Ci(a,{query$:o})),...ee("search-suggest",e).map(a=>Ri(a,{keyboard$:t}))))}catch(r){return e.hidden=!0,je}}var cn=Je(Qr());function Vs(e){e.setAttribute("data-md-copying","");let t=e.innerText;return e.removeAttribute("data-md-copying"),t}function ki({alert$:e}){cn.default.isSupported()&&new U(t=>{new cn.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Vs(B(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(M(t=>{t.trigger.focus()}),d(()=>ae("clipboard.copied"))).subscribe(e)}function Ns(e){if(e.length<2)return[""];let[t,r]=[...e].sort((o,i)=>o.length-i.length).map(o=>o.replace(/[^/]+$/,"")),n=0;if(t===r)n=t.length;else for(;t.charCodeAt(n)===r.charCodeAt(n);)n++;return e.map(o=>o.replace(t.slice(0,n),""))}function hr(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return C(t);{let r=ce();return zo(new URL("sitemap.xml",e||r.base)).pipe(d(n=>Ns(W("loc",n).map(o=>o.textContent))),le(()=>k),De([]),M(n=>__md_set("__sitemap",n,sessionStorage,e)))}}function Pi({document$:e,location$:t,viewport$:r}){let n=ce();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",w(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let o=ie("link[rel=icon]");typeof o!="undefined"&&(o.href=o.href);let i=hr().pipe(d(l=>l.map(p=>`${new URL(p,n.base)}`)),_(l=>w(document.body,"click").pipe(A(p=>!p.metaKey&&!p.ctrlKey),_(p=>{if(p.target instanceof Element){let m=p.target.closest("a");if(m&&!m.target){let h=new URL(m.href);if(h.search="",h.hash="",h.pathname!==location.pathname&&l.includes(h.toString()))return p.preventDefault(),C({url:new URL(m.href)})}}return je}))),pe()),a=w(window,"popstate").pipe(A(l=>l.state!==null),d(l=>({url:new URL(location.href),offset:l.state})),pe());P(i,a).pipe(Q((l,p)=>l.url.href===p.url.href),d(({url:l})=>l)).subscribe(t);let c=t.pipe(J("pathname"),_(l=>pr(l.href).pipe(le(()=>(lr(l),je)))),pe());i.pipe(rr(c)).subscribe(({url:l})=>{history.pushState({},"",`${l}`)});let s=new DOMParser;c.pipe(_(l=>l.text()),d(l=>s.parseFromString(l,"text/html"))).subscribe(e);let f=new Set,u=new Set;for(let l of W("script",document))l.src?f.add(new URL(l.src,document.baseURI).toString()):u.add(l.outerHTML);e.pipe(Pe(1),mt(l=>ze(this,null,function*(){var p;for(let m of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...Z("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let h=ie(m),b=ie(m,l);typeof h!="undefined"&&typeof b!="undefined"&&h.replaceWith(b)}((p=window.MathJax)==null?void 0:p.typesetPromise)!==void 0&&(yield window.MathJax.typesetPromise());for(let m of W("script",l))if(m.src){let h=new URL(m.src,document.baseURI).toString();if(!f.has(h)){let b=document.createElement("script");for(let V of m.getAttributeNames())b.setAttribute(V,m.getAttribute(V));let v;b.src=h,b.async||(v=new Promise(V=>b.addEventListener("load",()=>V()))),document.body.appendChild(b),f.add(h),v!==void 0&&(yield v)}}else{let h=m.outerHTML;if(!u.has(h)){let b=document.createElement("script");for(let v of m.getAttributeNames())b.setAttribute(v,m.getAttribute(v));b.textContent=m.textContent,document.body.appendChild(b),u.add(h)}}}))).subscribe(),e.pipe(Pe(1),d(()=>_e("container")),_(l=>W("script",l)),mt(l=>{let p=O("script");if(l.src){for(let m of l.getAttributeNames())p.setAttribute(m,l.getAttribute(m));return l.replaceWith(p),new U(m=>{p.onload=()=>m.complete()})}else return p.textContent=l.textContent,l.replaceWith(p),k})).subscribe(),P(i,a).pipe(rr(e)).subscribe(({url:l,offset:p})=>{l.hash&&!p?No(l.hash):window.scrollTo(0,(p==null?void 0:p.y)||0)}),r.pipe(Wr(i),He(250),J("offset")).subscribe(({offset:l})=>{history.replaceState(l,"")}),P(i,a).pipe(Ne(2,1),A(([l,p])=>l.url.pathname===p.url.pathname),d(([,l])=>l)).subscribe(({offset:l})=>{window.scrollTo(0,(l==null?void 0:l.y)||0)})}var $i=Je(rn());function Ii(e,t){let r=new RegExp(e.separator,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${o.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,$i.default)(a):a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ji({document$:e}){var a;let t=ce(),r=t.version.staticVersions?C(t.version.staticVersions):Ge(new URL((a=t.version.versionPath)!=null?a:"../versions.json",t.base)),n=new URL("..",t.base),o=c=>new URL(c,n).toString().replace(/\/*$/,""),i=r.pipe(d(c=>{let s=t.base.toString().replace(/\/*$/,"");return c.find(({version:f,aliases:u})=>o(f)===s||u.find(l=>o(l)===s))||c[0]}));r.pipe(d(c=>new Map(c.map(s=>[`${new URL(`../${s.version}/`,t.base)}`,s]))),_(c=>w(document.body,"click").pipe(A(s=>!s.metaKey&&!s.ctrlKey),me(i),_(([s,f])=>{if(s.target instanceof Element){let u=s.target.closest("a");if(u&&!u.target&&c.has(u.href)){let l=u.href;return!s.target.closest(".md-version")&&c.get(l)===f?k:(s.preventDefault(),C(l))}}return k}),_(s=>{let{version:f}=c.get(s);return hr(new URL(s)).pipe(d(u=>{let p=Oe().href.replace(t.base,"");return u.includes(p.split("#")[0])?new URL(`../${f}/${p}`,t.base):new URL(s)}))})))).subscribe(c=>lr(c)),G([r,i]).subscribe(([c,s])=>{B(".md-header__topic").appendChild(oi(c,s))}),e.pipe(_(()=>i)).subscribe(c=>{var f;let s=__md_get("__outdated",sessionStorage);if(s===null){let u=((f=t.version)==null?void 0:f.default)||"latest";s=!c.aliases.includes(u),__md_set("__outdated",s,sessionStorage)}if(s)for(let u of ee("outdated"))u.hidden=!1})}function Fi(e,{location$:t}){let r={lang:[],separator:"\\s+"};return G([t.pipe(q(Oe()),A(n=>!!n.searchParams.get("h")))]).pipe(d(([n])=>Ii(r,!0)(n.searchParams.get("h"))),d(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let c=i.nextNode();c;c=i.nextNode())if((a=c.parentElement)!=null&&a.offsetHeight){let s=c.textContent,f=n(s);f.length>s.length&&o.set(c,f)}for(let[c,s]of o){let{childNodes:f}=O("span",null,s);c.replaceWith(...Array.from(f))}return{ref:e,nodes:o}}))}function Ds(e,{viewport$:t,main$:r}){let n=e.parentElement,o=n.offsetTop-n.parentElement.offsetTop;return G([r,t]).pipe(d(([{offset:i,height:a},{offset:{y:c}}])=>(a=a+Math.min(o,Math.max(0,c-i))-o,{height:a,locked:c>=i+o})),Q((i,a)=>i.height===a.height&&i.locked===a.locked))}function fn(e,n){var o=n,{header$:t}=o,r=hn(o,["header$"]);let i=B(".md-sidebar__scrollwrap",e),{y:a}=Be(i);return I(()=>{let c=new L;return c.pipe(Re(0,fe),me(t)).subscribe({next([{height:s},{height:f}]){i.style.height=`${s-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ce(fe),ve(1)).subscribe(()=>{for(let s of W(".md-nav__link--active[href]",e)){let f=ko(s);if(typeof f!="undefined"){let u=s.offsetTop-f.offsetTop,{height:l}=Se(f);f.scrollTo({top:u-l/2})}}}),Ds(e,r).pipe(M(s=>c.next(s)),R(()=>c.complete()),d(s=>N({ref:e},s)))})}function Ui(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Ir(Ge(`${r}/releases/latest`).pipe(le(()=>k),d(n=>({version:n.tag_name})),De({})),Ge(r).pipe(le(()=>k),d(n=>({stars:n.stargazers_count,forks:n.forks_count})),De({}))).pipe(d(([n,o])=>N(N({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return Ge(r).pipe(d(n=>({repositories:n.public_repos})),De({}))}}function Vi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ge(r).pipe(le(()=>k),d(({star_count:n,forks_count:o})=>({stars:n,forks:o})),De({}))}function Ni(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Ui(r,n);case"gitlab":let[,o,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return Vi(o,i);default:return k}}var Ws;function zs(e){return Ws||(Ws=I(()=>{let t=__md_get("__source",sessionStorage);if(t)return C(t);if(ee("consent").length){let n=__md_get("__consent");if(!(n&&n.github))return k}return Ni(e.href).pipe(M(n=>__md_set("__source",n,sessionStorage)))}).pipe(le(()=>k),A(t=>Object.keys(t).length>0),d(t=>({facts:t})),X(1)))}function Di(e){let t=B(":scope > :last-child",e);return I(()=>{let r=new L;return r.subscribe(({facts:n})=>{t.appendChild(ri(n)),t.classList.add("md-source__repository--active")}),zs(e).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>N({ref:e},n)))})}function qs(e,{viewport$:t,header$:r}){return de(document.body).pipe(_(()=>mr(e,{header$:r,viewport$:t})),d(({offset:{y:n}})=>({hidden:n>=10})),J("hidden"))}function Wi(e,t){return I(()=>{let r=new L;return r.subscribe({next({hidden:n}){e.hidden=n},complete(){e.hidden=!1}}),(Z("navigation.tabs.sticky")?C({hidden:!1}):qs(e,t)).pipe(M(n=>r.next(n)),R(()=>r.complete()),d(n=>N({ref:e},n)))})}function Ks(e,{viewport$:t,header$:r,excludedLinks:n}){let o=new Map,i=W("a[href]",e);for(let s of i){if(n!=null&&n.has(s))continue;let f=s.getAttribute("href"),u;if(f.startsWith("#")){let l=decodeURIComponent(s.hash.substring(1));u=ie(`[id="${l}"]`)}else u=ie(`a.pseudo-toc-entry[href=${CSS.escape(f)}]`);if(typeof u!="undefined"){let l=s.closest(".md-nav__link");l!==null&&o.set(l,u)}}let a=r.pipe(J("height"),d(({height:s})=>{let f=_e("main"),u=B(":scope > :first-child",f);return s+.8*(u.offsetTop-f.offsetTop)}),pe());return de(document.body).pipe(J("height"),_(s=>I(()=>{let f=[];return C([...o].reduce((u,[l,p])=>{for(;f.length&&o.get(f[f.length-1]).tagName>=p.tagName;)f.pop();let m=p.offsetTop;for(;!m&&p.parentElement;)p=p.parentElement,m=p.offsetTop;return u.set([...f=[...f,l]].reverse(),m)},new Map))}).pipe(d(f=>new Map([...f].sort(([,u],[,l])=>u-l))),St(a),_(([f,u])=>t.pipe(Nr(([l,p],{offset:{y:m},size:h})=>{let b=m+h.height>=Math.floor(s.height);for(;p.length;){let[,v]=p[0];if(v-u=m&&!b)p=[l.pop(),...p];else break}return[l,p]},[[],[...f]]),Q((l,p)=>l[0]===p[0]&&l[1]===p[1])))))).pipe(d(([s,f])=>({prev:s.map(([u])=>u),next:f.map(([u])=>u)})),q({prev:[],next:[]}),Ne(2,1),d(([s,f])=>s.prev.length{let i=new L,a=o?"md-nav__link--active":"md-nav__link--in-viewport";if(i.subscribe(({prev:s,next:f})=>{for(let[u]of f)u.classList.remove("md-nav__link--passed"),u.classList.remove(a);for(let[u,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle(a,u===s.length-1)}),Z("toc.follow")&&(o||!Z("toc.integrate"))){let s=!o||Z("toc.integrate");i.pipe(He(1)).subscribe(({prev:f})=>{var m;let u;if(f.length===0&&s&&(u=(m=e.querySelector("a[href='#']"))!=null?m:e),s=!1,f.length!==0&&(u=f[f.length-1][0]),u===void 0||!u.offsetHeight)return;let l=u.parentElement,p=5;for(;l!==null&&l.scrollHeight-p<=l.clientHeight;)l=l.parentElement;if(l!==null&&l!==document.body&&l!==document.documentElement){let h=u.getBoundingClientRect(),b=l.getBoundingClientRect();l.scrollTo({top:l.scrollTop+(h.y-b.height/2-b.y)})}})}o&&Z("navigation.tracking")&&t.pipe(te(i.pipe(ue(1))),J("offset"),He(250),Pe(1),te(n.pipe(Pe(1))),Ot({delay:250}),me(i)).subscribe(([,{prev:s}])=>{let f=Oe(),u=s[s.length-1];if(u&&u.length){let[l]=u,{hash:p}=new URL(l.href);f.hash!==p&&(f.hash=p,history.replaceState({},"",`${f}`))}else f.hash="",history.replaceState({},"",`${f}`)}),Z("toc.sticky")&&de(document.body).pipe(J("width"),He(0)).subscribe(()=>{let s=new Map,f="--md-nav__header-height";for(let u of W(".md-nav__link",e)){let l=u.nextElementSibling;if(!(l instanceof HTMLElement)||l.tagName!=="NAV")continue;let p="",m=NaN,h=l.parentElement.closest("nav");if(h!==null){let b=s.get(h);b!==void 0&&(p=`${b.height} + `,m=b.zindex-1)}isNaN(m)&&(m=100),p+=`${u.offsetHeight}px + 0.625em`,u.classList.add("md-nav__sticky"),u.style.setProperty("--md-nav__sticky-zindex",m.toString()),l.style.setProperty(f,`calc(${p})`),s.set(l,{height:p,zindex:m})}});let c=o?void 0:new Set(W("[data-md-component='toc'] a[href]",e));return Ks(e,{viewport$:t,header$:r,excludedLinks:c}).pipe(M(s=>i.next(s)),R(()=>i.complete()),d(s=>N({ref:e},s)))})}function Bs(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(d(({offset:{y:a}})=>a),Ne(2,1),d(([a,c])=>a>c&&c>0),Q()),i=r.pipe(d(({active:a})=>a));return G([i,o]).pipe(d(([a,c])=>!(a&&c)),Q(),te(n.pipe(Pe(1))),Vr(!0),Ot({delay:250}),d(a=>({hidden:a})))}function zi(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new L,a=i.pipe(ue(1));return i.subscribe({next({hidden:c}){e.hidden=c,c?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(te(a),J("height")).subscribe(({height:c})=>{e.style.top=`${c+16}px`}),Bs(e,{viewport$:t,main$:n,target$:o}).pipe(M(c=>i.next(c)),R(()=>i.complete()),d(c=>N({ref:e},c)))}function qi({document$:e,tablet$:t}){e.pipe(_(()=>W(".md-toggle--indeterminate, [data-md-state=indeterminate]")),M(r=>{r.indeterminate=!0,r.checked=!1}),oe(r=>w(r,"change").pipe(zr(()=>r.classList.contains("md-toggle--indeterminate")),d(()=>r))),me(t)).subscribe(([r,n])=>{r.classList.remove("md-toggle--indeterminate"),n&&(r.checked=!1)})}function Ys(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Ki({document$:e}){e.pipe(_(()=>W("[data-md-scrollfix]")),M(t=>t.removeAttribute("data-md-scrollfix")),A(Ys),oe(t=>w(t,"touchstart").pipe(d(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Bi({viewport$:e,tablet$:t}){G([ht("search"),t]).pipe(d(([r,n])=>r&&!n),_(r=>C(r).pipe(ke(r?400:100))),me(e)).subscribe(([r,{offset:{y:n}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${n}px`;else{let o=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",o&&window.scrollTo(0,o)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var nt=So(),vr=jo(),rt=Do(),un=Io(),ge=Jo(),gr=Yr("(min-width: 960px)"),Gi=Yr("(min-width: 1220px)"),Ji=Wo(),Gs=ce(),pn=new L;ki({alert$:pn});Z("navigation.instant")&&Pi({document$:nt,location$:vr,viewport$:ge});var Yi;((Yi=Gs.version)==null?void 0:Yi.provider)==="mike"&&ji({document$:nt});P(vr,rt).pipe(ke(125)).subscribe(()=>{Ye("drawer",!1),Ye("search",!1)});un.pipe(A(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ie("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=ie("[href][rel=next]");typeof r!="undefined"&&r.click();break}});qi({document$:nt,tablet$:gr});Ki({document$:nt});Bi({viewport$:ge,tablet$:gr});var We=xi(_e("header"),{viewport$:ge}),br=nt.pipe(d(()=>_e("main")),_(e=>Si(e,{viewport$:ge,header$:We})),X(1)),Js=P(...ee("consent").map(e=>Xo(e,{target$:rt})),...ee("dialog").map(e=>yi(e,{alert$:pn})),...ee("header").map(e=>wi(e,{viewport$:ge,header$:We,main$:br})),...ee("palette").map(e=>Oi(e)),...ee("search").map(e=>Hi(e,{keyboard$:un})),...ee("source").map(e=>Di(e))),Qs=I(()=>P(...ee("announce").map(e=>Qo(e)),...ee("content").map(e=>gi(e,{viewport$:ge,target$:rt,print$:Ji})),...ee("content").map(e=>Z("search.highlight")?Fi(e,{location$:vr}):k),...ee("header-title").map(e=>Ei(e,{viewport$:ge,header$:We})),...ee("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Gr(Gi,()=>fn(e,{viewport$:ge,header$:We,main$:br})):Gr(gr,()=>fn(e,{viewport$:ge,header$:We,main$:br}))),...ee("tabs").map(e=>Wi(e,{viewport$:ge,header$:We})),...ee("toc").map(e=>ln(e,{viewport$:ge,header$:We,target$:rt,localToc:!0})),...ee("sidebar").filter(e=>e.getAttribute("data-md-type")==="navigation").map(e=>ln(e,{viewport$:ge,header$:We,target$:rt,localToc:!1})),...ee("top").map(e=>zi(e,{viewport$:ge,header$:We,main$:br,target$:rt})))),Qi=nt.pipe(_(()=>Qs),tt(Js),X(1));Qi.subscribe();window.document$=nt;window.location$=vr;window.target$=rt;window.keyboard$=un;window.viewport$=ge;window.tablet$=gr;window.screen$=Gi;window.print$=Ji;window.alert$=pn;window.component$=Qi;})(); diff --git a/html/_static/style.css b/html/_static/style.css new file mode 100644 index 00000000..6610cf47 --- /dev/null +++ b/html/_static/style.css @@ -0,0 +1,3 @@ +.mermaid text { + font-size: 90%; +} diff --git a/html/_static/summary.jpeg b/html/_static/summary.jpeg new file mode 100644 index 00000000..e4ae3800 Binary files /dev/null and b/html/_static/summary.jpeg differ diff --git a/html/_static/tabs.css b/html/_static/tabs.css new file mode 100644 index 00000000..957ba60d --- /dev/null +++ b/html/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/html/_static/tabs.js b/html/_static/tabs.js new file mode 100644 index 00000000..48dc303c --- /dev/null +++ b/html/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/html/_static/togglebutton.css b/html/_static/togglebutton.css new file mode 100644 index 00000000..54a67879 --- /dev/null +++ b/html/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/html/_static/togglebutton.js b/html/_static/togglebutton.js new file mode 100644 index 00000000..215a7eef --- /dev/null +++ b/html/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/html/_static/workflow.png b/html/_static/workflow.png new file mode 100644 index 00000000..e124bfdb Binary files /dev/null and b/html/_static/workflow.png differ diff --git a/html/changelog.html b/html/changelog.html new file mode 100644 index 00000000..e19e7881 --- /dev/null +++ b/html/changelog.html @@ -0,0 +1,787 @@ + + + + + + + + + + + + + + + + Changelog - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

ChangelogΒΆ

+

v0.0.1

+
    +
  • Initial release (R. Atwi and M. Bliss)

  • +
+

v0.0.4

+
    +
  • Support for retrieving molecules from pubchem directly and using them in the workflows

  • +
  • Support for OPLS 2005 ff by running Maestro in the backend

  • +
  • Option for charge scaling of ionic species when preparing the lammps data file

  • +
  • Automatic identification of system element types when creating dump files in lammps simulations

  • +
  • Addition of MDPropTools package for analysis of MD trajectories as dependency

  • +
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/citing.html b/html/citing.html new file mode 100644 index 00000000..4117e727 --- /dev/null +++ b/html/citing.html @@ -0,0 +1,799 @@ + + + + + + + + + + + + + + + + Citing MISPR - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Citing MISPRΒΆ

+

If you find MISPR useful in your research, please consider citing the following papers:

+

Paper 1 (MISPR):

+
@article{atwi2022mispr,
+  title        = {MISPR: An automated infrastructure for high-throughput DFT and MD simulations},
+  author       = {Atwi, Rasha and Bliss, Matthew and Makeev, Maxim and Rajput, Nav Nidhi},
+  year         = {2022}
+}
+
+
+

Download as BibTeX

+

Paper 2 (Hybrid NMR Workflow):

+
@article{atwi2022automated,
+  title        = {An automated framework for high-throughput predictions of NMR chemical shifts within liquid solutions},
+  author       = {Atwi, Rasha and Chen, Ying and Han, Kee Sung and Mueller, Karl T and Murugesan, Vijayakumar and Rajput, Nav Nidhi},
+  journal      = {Nature Computational Science},
+  volume       = {2},
+  number       = {2},
+  pages        = {112--122},
+  year         = {2022},
+  publisher    = {Nature Publishing Group}
+}
+
+
+

Download as BibTeX

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/genindex.html b/html/genindex.html new file mode 100644 index 00000000..d67171c6 --- /dev/null +++ b/html/genindex.html @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + None - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +None + + + + + + +
+
+ + +
+ +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/index.html b/html/index.html new file mode 100644 index 00000000..844597ba --- /dev/null +++ b/html/index.html @@ -0,0 +1,890 @@ + + + + + + + + + + + + + + + + Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+

MISPR 0.0.4 DocumentationΒΆ

+

MISPR is a Python library for computational materials science and contains +preset workflows for running complex hierarchical density functional +theory (DFT) and classical molecular dynamics (MD) simulations to compute +properties of materials.

+
+_images/summary.jpeg +
+

InstallationΒΆ

+
+
+
+

Install using pip:

+
pip install mispr
+
+
+
+
+
+
+

Important

+

Before you can start using MISPR, there are additional steps you need to follow. +Please refer to the installation guide for complete setup instructions, +including any dependencies or configuration files required.

+
+

Learning ResourcesΒΆ

+
+
+
+
+
+

About MISPR

+
+ +
+
+ +
+
+
+

How-tos

+
+ +
+
+
+
+
+

Code documentation

+
+
+ +
+
+
+
+
+

Contributing / Reporting / SupportΒΆ

+

Contirbuting to MISPR can be in the form of:

+
    +
  • Requesting or adding new workflows and features

  • +
  • Reporting or fixing bugs and issues

  • +
  • Contributing to the documentation and/or examples

  • +
+

If you want to add or change something in the code, you can do this by +forking MISPR on GitHub and +submitting a pull request.

+

If you submit a bug report, we will review it and move it to GitHub issues, +where its progress can be tracked.

+

For other inquiries, please contact us at rasha.atwi@stonybrook.edu.

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/installation/configuration.html b/html/installation/configuration.html new file mode 100644 index 00000000..365c9961 --- /dev/null +++ b/html/installation/configuration.html @@ -0,0 +1,1011 @@ + + + + + + + + + + + + + + + + Configuration Files - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Configuration FilesΒΆ

+

After setting up the environment and installing the software, you will +need to configure the software to work with your system. This is done by +creating the following set of configuration files.

+
+

Note

+

This page is intended to help you get set-up for the first time using +FireWorks and MISPR so you can learn how these software work. Please +refer to the FireWorks +documentation for more information on these files and how FireWorks works. +Here, we will only discuss the basic configuration options which are +sufficient for using MISPR as in this tutorial.

+
+

Writing the Configuration FilesΒΆ

+
+ +
+

This file contains the basic MongoDB information like the +credentials required to connect to the database where the +calculation outputs will be stored. Note that +JSON strings require double quotes except for the value of +β€œport” which is an integer.

+
{
+    "admin_user": "|ADMIN_USERNAME|",
+    "admin_password": "|ADMIN_PASSWORD|",
+    "aliases": {},
+    "collection": "|COLLECTION|",
+    "database": "|DB_NAME|",
+    "host": "|HOSTNAME|",
+    "port": |PORT|,
+}
+
+
+
+ +
+

This file stores your FireWorker’s credentials. In +the FireWorks, a +FireWorker can be as simple as the workstation used to host the +LaunchPad or complicated like a supercomputing center with a +queueing system.

+
name: |WORKER_NAME|
+category: ''
+query: '{}'
+env:
+    db_file: |CODES_DIR|/config/db.json
+    scratch_dir: null
+
+
+

The following parameters are defined in the file:

+
    +
  • name: the name of the worker where your job will be run; +this is helpful when you have multiple workers; see +FireWorks documentation on controlling the Worker +if you need more information on setting up this file if you are +using more than one worker.

  • +
  • category and queue: these parameters can control which +calculations are run on which worker; the default settings will +allow all calculations to be run

  • +
  • env: defines worker-specific settings like the path to the +db file and the scratch directory for fast disk access

  • +
+
+ +
+

This is the FireWorks LaunchPad file that contains the MongoDB +credentials required to connect to the database for storing +and managing workflows within FireWorks. Note that the db.json +file we created earlier is used to connect to the database +where the results are stored and is used by MISPR while +my_launchpad.yaml is used by FireWorks. The two databases +can be the same or different databases. If they are the same databases, +then the information here will be mostly the same as that in the +db.json file.

+
host: |HOSTNAME|
+port: |PORT|
+name: |LAUNCHPAD_NAME|
+username: |ADMIN_USERNAME|
+password: |ADMIN_PASSWORD|
+logdir: null
+strm_lvl: INFO
+user_indices: []
+wf_user_indices: []
+authsource: null
+uri_mode: |URI_MODE|
+mongoclient_kwargs: {}
+
+
+

The following parameters need to be defined in the file:

+
    +
  • host: the hostname of the MongoDB server

  • +
  • port: the port number of the MongoDB server

  • +
  • name: the name of the MongoDB server

  • +
  • username: the username to connect to the MongoDB server

  • +
  • password: the password to connect to the MongoDB server

  • +
+

Note that if the uri_mode is set to true, the host +should be the full URI string. +In this case, the username and password are not used.

+

If you want to pass other custom keyword arguments +(e.g., SSL/TLS arguments) to the MongoClient connection, you +can do that via mongoclient_kwargs. See +pymongo documentation +for more details.

+
+ +
+

This is the queue adapter file required by FireWorks to +automatically communicate with the queueing system. +The example provided here is for SLURM machines and does not +include a full list of possible parameters, but you can +check the rest of the parameters or parameters that can be +specified for other queue systems (e.g., PBS, SGE, etc.) +here.

+
_fw_name: CommonAdapter
+_fw_q_type: SLURM
+rocket_launch: rlaunch -w |CODES_DIR|/config singleshot
+nodes: 1
+walltime: 24:00:00
+queue: null
+account: null
+job_name: null
+pre_rocket: null
+post_rocket: null
+logdir: |CODES_DIR|/logs
+
+
+

The following parameters are defined in the file:

+
    +
  • _fw_name: CommonAdapter means that the queue is one of +the built-in queue systems

  • +
  • _fw_q_type: the queue system type (e.g., SLURM, PBS, SGE, etc.)

  • +
  • rocket_launch: the method to use for launching Rockets

  • +
  • nodes, walltime, queue, account, job_name: +parameters you normally specify in your SLURM script for +allocating resources

  • +
  • pre_rocket and post_rocket: the commands to run +before and after launching the Rocket (e.g., module load +packages)

  • +
  • logdir: path to the log directory

  • +
+
+

Note

+

Specifying singleshot in the file will limit each +reserved job to running only one firework at a time even if other +fireworks are waiting to be run. This can be changed to rapidfire +to run all fireworks in parallel. You can go over the FireWorks +documentation to learn the difference between these launching modes.

+
+
+ +
+

This file contains the commands to run Gaussian, LAMMPS, and AmberTools. +These commands are specific to your computing resources you are +running on. The example provided here is meant to show how these +commands should be defined, but you need to change them to match your +system.

+
[RunCalc]
+gcmd: g16 < "$input_path$" > "$output_path$"
+formchkcmd: formchk "$input_path$" "$output_path$"
+
+[LammpsRunCalc]
+lcmd: mpirun -np $SLURM_NTASKS lmp_mpi -in $control_path$
+lammps_gpu_cmd: null
+
+[AmbertoolsRunCalc]
+acmd: antechamber -i $input_file$ -fi $input_type$ -o $output_file$ -fo $output_type$ -c $charge_method$ -s 2
+pcmd: parmchk2 -i $input_file$ -f mol2 -o $output_file$
+tcmd: tleap -f $input_file$
+
+[MaestroCalc]
+mae_cmd: $SCHRODINGER/utilities/structconvert $input_file$ $output_file$
+ffld_cmd: $SCHRODINGER/utilities/ffld_server -imae $input_file$ -version 14 -print_parameters -out_file $output_file$
+
+
+

The following commands are defined in the file:

+
    +
  • gcmd: the command to run Gaussian

  • +
  • formchkcmd: the command to run Gaussian formchk to convert +a Gaussian checkpoint file into formatted forms

  • +
  • lcmd: the command to run LAMMPS

  • +
  • lammps_gpu_cmd: the command to run LAMMPS on a GPU

  • +
  • acmd: the command to run Antechamber

  • +
  • pcmd: the command to run Parmchk2

  • +
  • tcmd: the command to run tleap

  • +
+
+

Note

+

Anything between two dollar signs ($ $) is a placeholder for +a variable and should not be changed.

+

Anything between the square brackets ([]), e.g., [RunCalc], +or before the colons (:), e.g., gmcd, should not be changed +since these are used to point MISPR to the commands to run.

+
+
+ +
+

This is the master FireWorks configuration file that controls +FireWorks settings and points to the location of the other +configuration files.

+
CONFIG_FILE_DIR: |CODES_DIR|/config
+
+
+

The CONFIG_FILE_DIR is expected to contain the +other configuration files. For a list of control settings that +can be added to this file, check +FireWorks documentation on modifying the FW config.

+
+
+

Configuring Bash ProfileΒΆ

+

After creating the above six configuration files and replacing the +placeholders with your specific settings, create a directory in +your |CODES_DIR| (see Definition) called config +and move the above configuration files into it. The |CODES_DIR|/config +should look like:

+
config
+β”œβ”€β”€ config.ini
+β”œβ”€β”€ db.json
+β”œβ”€β”€ FW_config.yaml
+β”œβ”€β”€ my_fworker.yaml
+β”œβ”€β”€ my_launchpad.yaml
+└── my_qadapter.yaml
+
+
+

Now, append the following lines to your .bash_profile or .bashrc +file in order to set an environment variable that tells FireWorks where +to find the FW_config.yaml file, which will in turn tell FireWorks +where the rest of the configuration files are:

+
export FW_CONFIG_FILE=|CODES_DIR|/config/FW_config.yaml
+
+
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/installation/dependencies.html b/html/installation/dependencies.html new file mode 100644 index 00000000..bdc8df46 --- /dev/null +++ b/html/installation/dependencies.html @@ -0,0 +1,935 @@ + + + + + + + + + + + + + + + + Prerequisites - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

PrerequisitesΒΆ

+

Virtual python environmentΒΆ

+

MISPR depends on a number of third party Python packages, and usually on +specific versions of those packages. In order not to interfere with third +party packages needed by other software on your machine or cluster, we +strongly recommend isolating MISPR in a virtual python environment. In the +following, we describe how to create a virtual python environment using +the virtualenv tool, but +feel free to use your preferred environment manager +(e.g. conda).

+
+

Recommendation

+

We recommend that you use Python version 3.7 since this is the version that we have +tested MISPR with.

+
+

Creating the virtual environmentΒΆ

+

To create and activate a new virtual environment, go to your +|CODES_DIR| (see Definition), and run the following commands:

+
pip install --user --upgrade virtualenv     # install virtualenv tool
+python -m virtualenv mispr_env              # create "mispr_env" environment
+source mispr_env/bin/activate               # activate "mispr_env" environment
+
+
+

This will create a directory in your |CODES_DIR| named mispr_env, +where all the packages will be installed. After activation, your prompt +should have (mispr_env) in front of it, indicating that you are +working inside the virtual environment. The activation script ensures +that python programs have access only to packages installed inside the +virtualenv. +To deactivate the enviornment, simply run:

+
deactivate
+
+
+
+

Note

+

You may need to install pip and setuptools in your virtual +enviornment in case the system or user version of these tools is old:

+
pip install -U setuptools pip
+
+
+
+

Computational chemistry softwareΒΆ

+

At the backend, MISPR uses:

+
    +
  • Gaussian software to perform DFT calculations

  • +
  • AmberTools to generate GAFF parameters

  • +
  • LAMMPS to run MD simulations

  • +
  • Packmol to +create initial configurations for MD simulations. To install packmol, +follow their user guide

  • +
+

Ensure that you have access to the executables of these software +before using MISPR. Gaussian is a commercial software +that requires a license while AmberTools, LAMMPS, and Packmol are open source. +If Gaussian, AmberTools, and LAMMPS are already installed on supercomputing +resources, the user typically needs to load their corresponding modules +before their use.

+

Materials Project base librariesΒΆ

+
    +
  • pymatgen: MISPR uses pymatgen for handling +different molecule representations and i/o operations specific to +Gaussian and LAMMPS. We have made changes to the pymatgen library to +make it compatible with our needs in MISPR. These changes have not +been merged yet with the main pymatgen library. Therefore, in order +to use MISPR, you need to install the MolMD version of pymatgen by +running the following commands in your |CODES_DIR|:

    +
    git clone https://github.com/molmd/pymatgen.git
    +cd pymatgen
    +python setup.py install
    +
    +
    +
  • +
  • FireWorks: MISPR +uses FireWorks to design, manage, and execute workflows. To install, +simply type:

    +
    pip install FireWorks
    +
    +
    +

    Further details can be found in the FireWorks documentation.

    +
    +

    Note

    +

    While FireWorks is used in MISPR for managing the DFT and MD +workflows due to its many advantages, it takes some time to learn +and get used to it.

    +
    +
  • +
  • custodian: MISPR uses +custodian for handling errors that occur during the simulations and +correcting them according to predefined rules. We have added a Gaussian +plug-in to the custodian library, but similar to the pymatgen changes, +these changes have not been merged yet with the main custodian library. +Therefore, in order to use MISPR, you need to install the MolMD version +of custodian by running the following commands in your |CODES_DIR|:

    +
    git clone https://github.com/molmd/custodian.git
    +cd custodian
    +python setup.py install
    +
    +
    +
  • +
+

MongoDBΒΆ

+

Following the design decisions of the Materials Project, MISPR uses +MongoDB as the backend database. +MongoDB is a NoSQL database that is designed to store and retrieve +data in a highly efficient and scalable manner. It stores data in the +form of documents represented in the JSON (JavaScript Object Notation) +format, which is similar to a Python dictionary.

+

MISPR uses MongoDB to:

+
    +
  • Add, remove, and search the status of workflows - feature of +FireWorks (required)

  • +
  • Create computational databases of DFT and MD predicted properties - +Feature of MISPR (optional but strongly recommended)

  • +
+

Setting up MongoDBΒΆ

+

Options for getting MongoDB are:

+
    +
  • Install it yourself locally by following the instructions at +MongoDB. +This is pretty simple and typically works well if you are starting out +with MISPR and want to learn how to use a database. However, with this +option, you are limited with the storage space on your local machine and +you do not have the option to share the database with other users. You +also need to have the necessary privileges to install mongo on your machine.

  • +
  • Set up an account using a commercial service, which is typically +the simplest and easiest to use but is not free of charge for databases +with large size. Examples of such services include Atlas and MongoDB Atlas, +which offer 500 MB databases for free. This is typically enough to get +started for small projects.

  • +
  • Self-host a MongoDB server or ask your supercomputing center to offer +MongoDB hosting. This is more complicated than the other options and +will require continuous maintenance of the server.

  • +
+

After creating a new database, you need to keep record of your credentials. +These will be used later in setting up the configuration files required +by FireWorks.

+
+

Note

+

MongoDB must be accessible from the computers you are using to run +the workflows.

+
+

Testing your MongoDB connectionΒΆ

+

Establishing a Connection to MongoDB Using Pymongo:

+

You need to import MongoClient from pymongo and then create a new MongoClient instance. +This instance is used to connect to your MongoDB instance:

+
from pymongo import MongoClient
+
+client = MongoClient("mongodb://localhost:27017/")
+
+
+

In this example, we’re connecting to a MongoDB instance that runs on the same machine +(localhost) on port 27017, which is the default port for MongoDB.

+

Testing the Connection to MongoDB:

+

We can check the connection by listing all the databases:

+
print(client.list_database_names())
+
+
+

If the connection is successful, this command will return a list of names of the databases that are present in the +MongoDB instance.

+

Remember, for you to connect to a MongoDB instance, the MongoDB server needs to be installed and running. +If it’s not running on localhost:27017, you will need to provide the appropriate connection string.

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/installation/index.html b/html/installation/index.html new file mode 100644 index 00000000..86497e35 --- /dev/null +++ b/html/installation/index.html @@ -0,0 +1,843 @@ + + + + + + + + + + + + + + + + Installation - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

InstallationΒΆ

+

Before installing MISPR, you need to follow the steps below in order:

+
    +
  1. (Optional) Create a Virtual python environment

  2. +
  3. Make sure you have access to the Computational chemistry software +needed to run the DFT and MD simulations

  4. +
  5. Install Materials Project base libraries

  6. +
  7. Set up MongoDB database

  8. +
  9. Install MISPR and MDPropTools

  10. +
  11. Prepare the configuration files

  12. +
  13. Run a test workflow

  14. +
+
+

Note

+

Throughout the installation instructions, it is assumed that you are +familiar with Python and with basic Linux shell commands. If not, +Linux Journey and +Python For Beginners +are some recommended starting points.

+
+

Installing MISPR and MDPropToolsΒΆ

+

MISPR and MDPropTools can be installed either from the python package +index (good for most users) or directly from their GitHub +repositories (good for developers).

+

Installation Method 1: Using pipΒΆ

+

To install, simply type:

+
pip install mispr
+pip install mdproptools
+
+
+

Installation Method 2: Development modeΒΆ

+

To make changes directly to the source and contribute to the development +of MISPR, you can install MISPR and MDPropTools in development mode.

+
+

Note

+

If you had already installed MISPR via pip or conda, you +should uninstall that first before starting the installation in +development mode. This ensures that you will not have any conflicts +resulting from two different code installations.

+
+

The steps for installing the packages in development mode are below.

+
    +
  1. Activate your conda environment or virtual environment

  2. +
  3. Create a codes directory in |CODES_DIR|

  4. +
  5. cd to your newly created |CODES_DIR|/codes directory

  6. +
  7. Clone the packages you want to install in development mode using git:

    +
    git clone https://github.com/molmd/mdproptools.git
    +git clone https://github.com/molmd/mispr.git
    +
    +
    +

    Now you should have mdproptools and mispr directories in your codes +directory.

    +
  8. +
  9. For each of these packages, cd into their folders and run +pip install -e . or use the conda equivalent. Once installed, +if you make changes to the code in these packages, the changes +will take effect immediately without having to reinstall the package.

  10. +
+

Post-installationΒΆ

+
    +
  1. Before you go any further, confirm your package installations are correct. +First start IPython by typing ipython in your terminal, then confirm that +the commands import mdproptools and import mispr execute +without any errors

  2. +
  3. To update these codes later on, execute git pull followed by +pip install -e . or the conda equivalent in the corresponding +folder if you installed in development mode. If you installed via pip, +you can simply execute pip install --upgrade mispr.

  4. +
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/installation/test.html b/html/installation/test.html new file mode 100644 index 00000000..58b858b8 --- /dev/null +++ b/html/installation/test.html @@ -0,0 +1,908 @@ + + + + + + + + + + + + + + + + Running a Test Workflow - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Running a Test WorkflowΒΆ

+

After installing MISPR and its dependencies and setting up the configuration +files, it is important to make sure everything is working correctly. +Therefore, we will now run a very simple test workflow that optimizes the +structure of a molecule. Later in Workflow Tutorials, +we will show how to run more complex workflows.

+
+

Note

+

lpad and qlaunch that are used in this tutorial are part of +FireWorks software. You can refer to FireWorks documentation if you +need additional information.

+
+

Initialize the databaseΒΆ

+

Initialize the database by running the following command:

+
lpad reset
+
+
+
+

Warning

+

This command should only be executed one time when you are first +initializing the database set-up. If you reset your LaunchPad at a +later time, you will erase all existing entries in your FireWorks +database, which includes your fireworks, workflows, and launches +collections.

+
+
+

Note

+

Your Python environment where FireWorks is installed must be active +before you run this command.

+
+

Running the above command will return something like this:

+
Are you sure? This will RESET 0 workflows and all data. (Y/N)y
+2022-08-15 17:04:42,224 INFO Performing db tune-up
+2022-08-15 17:04:42,683 INFO LaunchPad was RESET.
+
+
+

Add a workflowΒΆ

+

The next step is to add a workflow to the database. We will run a +workflow that optimizes the geometry of a monoglyme molecule starting +from its xyz file. Note that you need to have the monoglyme.xyz file in +your working directory. You will need to run the following Python code +by creating a file called optimize_geometry.py:

+
from mispr.gaussian.fireworks.core import CalcFromMolFW
+from fireworks import LaunchPad, Workflow
+
+lpad = LaunchPad.auto_load()
+wf = Workflow([CalcFromMolFW("monoglyme.xyz", "get_from_file",
+                              gaussian_input_params={"route_parameters": {"opt": None}},
+                              save_to_file=True, save_to_db=True)])
+lpad.add_wf(wf)
+
+
+

and then running the following command in terminal:

+
python optimize_geometry.py
+
+
+

This will add a structure optimization workflow to the database.

+

Verify the workflowΒΆ

+

To check the status of this workflow in the database, run the following +command in terminal:

+
lpad get_fws -s READY
+
+
+

It will return something like this:

+
{
+    "fw_id": 1,
+    "created_on": "2022-08-16T20:32:54.554404",
+    "updated_on": "2022-08-16T20:32:54.554716",
+    "state": "READY",
+    "name": "calc_from_mol"
+}
+
+
+

Alternatively, you can query your fireworks collection in the MongoDB +database directly or start FireWorks’ LaunchPad +web gui from your local machine (assuming you have also set up +configuration files there):

+
lpad webgui
+
+
+

Submit the workflowΒΆ

+

To launch this job through queue, use the qlaunch command from FireWorks. +qlaunch has 3 modes: singleshot, rapidfire, and multi:

+
    +
  • singleshot: launches one job at a time

  • +
  • rapidfire: launches multiple jobs at once; you’ll most likely +want to use this mode where it is important to add the -m +flag to specify how many jobs to launch at once to prevent submitting +too many jobs at once.

  • +
  • multi: creates one job with multiple fireworks runs

  • +
+

Here is an example command for launching one job from the terminal in the +same working directory as before:

+
qlaunch singleshot
+
+
+

If you are not running your jobs through a queue, replace the +qlaunch command with rlaunch.

+

Monitor the workflowΒΆ

+

If all went well, you can determine the status of your running jobs by +using the following command in the terminal:

+
lpad get_fws -s RUNNING
+
+
+

or:

+
lpad get_fws -s COMPLETED
+
+
+

If your job has failed, your can rerun it using the following command +(replacing fw_id with 1, which is the id of your firework, since +you only have one firework in your launchpad at this point):

+
lpad rerun_fws -i <fw_id>
+
+
+

Query the database for the resultsΒΆ

+

Once this workflow is completed, you will see the generated Gaussian +input and output files as well as a run.json file that contains a +summary of the job in the same working directory.

+

Additionally, you can query the database for the results of your jobs +by using the InChI representation of the monoglyme molecule as a query +criteria:

+
from mispr.gaussian.utilities.db_utilities import get_db
+
+db = get_db()
+db.retrieve_run(inchi="InChI=1S/C4H10O2/c1-5-3-4-6-2/h3-4H2,1-2H3")[0]
+
+
+

This will return a dictionary of the results as they are saved in the +database. Alternatively, you can the view the results using MongoDB +Compass, and the generated documents from the run will appear like the +following in the runs collection of the gaussian database:

+
+../_images/document.png +
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/keywords.html b/html/keywords.html new file mode 100644 index 00000000..9e68d1d9 --- /dev/null +++ b/html/keywords.html @@ -0,0 +1,798 @@ + + + + + + + + + + + + + + + + Keywords - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

KeywordsΒΆ

+ ++++ + + + + + + + + + + + + + + + + + + + +

Keyword

Definition

|CODES_DIR|

Main directory where the virtual python environment is created and the configuration files are stored

LaunchPad

FireWorks database that controls the workflows. It stores all the tasks to be run and their status (e.g., RUNNING, WAITING, COMPLETED, etc.)

FireTask

Computing task to be performed

FireWork

A list of FireTasks that are to be run in sequence

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/license.html b/html/license.html new file mode 100644 index 00000000..f5c07d9c --- /dev/null +++ b/html/license.html @@ -0,0 +1,784 @@ + + + + + + + + + + + + + + + + License - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

LicenseΒΆ

+

MISPR is released under the MIT License.

+
The MIT License (MIT)
+
+Copyright (c) 2022 Stony Brook University
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.common.html b/html/mispr.common.html new file mode 100644 index 00000000..f389b82a --- /dev/null +++ b/html/mispr.common.html @@ -0,0 +1,956 @@ + + + + + + + + + + + + + + + + mispr.common package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.common packageΒΆ

+

SubmodulesΒΆ

+

mispr.common.pubchem moduleΒΆ

+

Implement a core class PubChemRunner for retrieving molecules from the PubChem +database using a molecule name as a query criteria.

+
+
+class mispr.common.pubchem.PubChemRunner(abbreviation, working_dir=None)[source]ΒΆ
+

Bases: object

+

Wrapper for retrieving molecules from PubChem database.

+
+
Parameters:ΒΆ
+
+
abbreviation : strΒΆ

Abbreviation to be used when saving molecule file.

+
+
working_dir : str, optionalΒΆ

Working directory for saving the molecule file +in; will use the current working directory if not specified.

+
+
+
+
+
+
+cleanup()[source]ΒΆ
+

Delete the sdf file downloaded from PubChem.

+
+ +
+
+convert_sdf_to_mol(save_to_file, fmt)[source]ΒΆ
+

Convert an SDF file to a pymatgen Molecule object.

+
+
Parameters:ΒΆ
+
+
save_to_file : boolΒΆ

Whether to save the Molecule object to a file.

+
+
fmt : strΒΆ

Molecule file format if save_to_file is True.

+
+
+
+
Returns:ΒΆ
+

pymatgen Molecule object.

+
+
Return type:ΒΆ
+

Molecule

+
+
+
+ +
+
+download_sdf(name)[source]ΒΆ
+

Download an SDF file from PubChem using a common name for the molecule as an +identifier.

+
+
Parameters:ΒΆ
+
+
name : strΒΆ

Name of the molecule to use for searching PubChem.

+
+
+
+
+
+ +
+
+get_mol(name, save_to_file=True, fmt='pdb', cleanup=True)[source]ΒΆ
+

Wrapper function that searches for a molecule in the PubChem database, downloads +it in the form of an SDF file, and converts the file to a pymatgen Molecule +object.

+
+
Parameters:ΒΆ
+
+
name : strΒΆ

Name of the molecule to use for searching PubChem.

+
+
save_to_file : bool, optionalΒΆ

Whether to save the Molecule object to a +file. Defaults to True.

+
+
fmt : str, optionalΒΆ

Molecule file format if save_to_file is True; +defaults to β€œpdb”.

+
+
cleanup : bool, optionalΒΆ

Whether to remove the intermediate sdf file.

+
+
+
+
Returns:ΒΆ
+

pymatgen Molecule object.

+
+
Return type:ΒΆ
+

Molecule

+
+
+
+ +
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.firetasks.html b/html/mispr.gaussian.firetasks.html new file mode 100644 index 00000000..e9a15d9b --- /dev/null +++ b/html/mispr.gaussian.firetasks.html @@ -0,0 +1,2188 @@ + + + + + + + + + + + + + + + + mispr.gaussian.firetasks package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.gaussian.firetasks packageΒΆ

+

SubmodulesΒΆ

+

mispr.gaussian.firetasks.geo_transformation moduleΒΆ

+

Define firetasks for performing various molecule transformations.

+
+
+class mispr.gaussian.firetasks.geo_transformation.AttachFunctionalGroup(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Attach a functional group to a molecule and adds it to fw_spec.

+
+
Parameters:ΒΆ
+
+
func_grp : str

Name of the functional group (e.g. carboxyl).

+
+
index : int

Site index in the molecule at which to attach the functional group.

+
+
db : str or dict, optional

Database credentials.

+
+
molecule : Molecule, optional

Molecule to attach the functional group to; +either provided directly or taken from a previous calculation through +fw_spec; priority is given to the latter.

+
+
bond_order : int, optional

Bond order to calculate the bond length between +the two sites. Defaults to 1.

+
+
save_to_db : bool, optional

Whether to save the derived molecule to db.

+
+
update_duplicates : bool, optional

Whether to update molecule document in +db if it already exists.

+
+
save_mol_file : bool, optional

Whether to save the derived molecule to file +(xyz, pdb, etc.).

+
+
fmt : str, optional

Format of the molecule file to create if save_mol_file is +True; uses xyz if not specified.

+
+
filename : str, optional

Name of the molecule file to create if save_mol_file +is True; will use molecular formula if not specified.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.geo_transformation.BreakMolecule(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Break a molecule into unique fragments (uniqueness is in terms of structure and +assigned charge) and creates optimization and frequency Fireworks for each fragment +(optional).

+

credits: Samuel Blau

+
+
Parameters:ΒΆ
+
+
mol : Molecule, optional

Molecule to break into fragments; can be provided +directly or taken from a previous calculation; priority is given to the latter.

+
+
bonds : list, optional

List of tuples of the bonds to break; e.g. +[(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between +atoms 1 and 2; if none is specified, will attempt to break all bonds; +defaults to None.

+
+
ref_charge : int, optional

Charge on the principle molecule; if not provided, +charge on Molecule will be used.

+
+
fragment_charges : list, optional

List of charges to assign to the fragments +in addition to the ones already assigned.

+
+

Note

+
+
The following charges will be used:
    +
  1. Neutral molecule: each fragment will have charges of 0, 1, and -1

  2. +
  3. +
    Molecule with charge -N: each fragment will have charges of

    0, -N, -N+1, -N+2

    +
    +
    +
  4. +
  5. +
    Molecule with charge +N: each fragment will have charges of

    0, N, N-1, N-2

    +
    +
    +
  6. +
+
+
+

If charges different from the above are provided via fragment_charges, +additional fragments with these charges will be created.

+
+

+
+
open_rings : bool, optional

Whether to open rings; if set to True, will +perform local optimization to get a good initial guess for the structure; +defaults to False.

+
+
opt_steps : int, optional

Number of optimization steps to perform when opening +the rings; uses 10000 if not specified.

+
+
working_dir : str, optional

Working directory to use for saving any files or +running the calculations.

+
+
db : str or dict, optional

Database credentials

+
+
opt_gaussian_inputs : dict, optional

Dictionary of parameters to use for +optimizing the fragments if calc_frags is True.

+
+
freq_gaussian_inputs : dict, optional

Dictionary of parameters to use for +performing a frequency analysis if calc_frags is True.

+
+
cart_coords : bool, optional

Whether to use cartesian coordinates in writing +Gaussian input files if calc_frags is True.

+
+
oxidation_states : dict, optional

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the molecule; +e.g.: {β€œLi”:1, β€œO”:-2}.

+
+
calc_frags : bool, optional

Whether to create optimization and frequency +Fireworks for the generated fragments and add them as children via FWAction.

+
+
save_to_db : bool, optional

Whether to save the generated fragments to db.

+
+
save_to_file : bool, optional

Whether to save the generated fragments to file.

+
+
fmt : str, optional

Format of the molecule file to create if save_to_file is +True (e.g. xyz, pdb, etc.).

+
+
update_duplicates : bool, optional

Whether to update fragment document in +the db if it already exists; works only if save_to_db is True.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.geo_transformation.ConvertToMoleculeObject(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Read a molecule from a file, converts it to a Molecule object, and saves it as +dict to mongodb.

+
+
Parameters:ΒΆ
+
+
mol_file : str

Molecule file; supported file formats include +xyz|pdb|mol|mdl|sdf|sd|ml2|sy2|mol2|cml|mrv, +gaussian input (gjf|g03|g09|com|inp), +Gaussian output (.out), and pymatgen’s JSON serialized molecules.

+
+
db : str or dict, optional

Database credentials.

+
+
save_to_db : bool, optional

Whether to save the processed molecule to db.

+
+
update_duplicates : bool, optional

Whether to update molecule document in db +if it already exists.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.geo_transformation.LinkMolecules(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Link two molecules using one site from the first and another site from the second +molecule and adds the resulting molecule to fw_spec.

+
+
Parameters:ΒΆ
+
+
index1 : int

site index in the first molecule at which to link the two molecules.

+
+
index2 : int

site index in the second molecule at which to link the two molecules.

+
+
db : str or dict, optional

Database credentials.

+
+
mol1 : Molecule, optional

First molecule; can be provided directly or taken +from a previous calculation; priority is given to the latter.

+
+
mol2 : Molecule, optional

Second molecule; can be provided directly or taken +from a previous calculation; priority is given to the latter.

+
+
bond_order : int, optional

Bond order to calculate the bond length between the +two sites. Defaults to 1.

+
+
save_to_db : bool, optional

Whether to save the derived molecule to db.

+
+
update_duplicates : bool, optional

Whether to update molecule document in db +if it already exists.

+
+
save_mol_file : bool, optional

Whether to save the derived molecule to file +(xyz, pdb, etc.).

+
+
fmt : str, optional

Format of the molecule file to create if save_mol_file +is True; uses xyz if not specified.

+
+
filename : str, optional

Name of the molecule file to create if save_mol_file +is True; will use molecular formula if not specified.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Process a molecule and generates a Molecule object. Used for handling different +molecule formats provided to Gaussian workflows.

+
+
Parameters:ΒΆ
+
+
mol : Molecule, str, GaussianOutput, dict

Source of the structure; should +correspond to that of the operation_type; see +mispr.gaussian.utilities.mol.process_mol for more details; besides the +formats supported by mispr.gaussian.utilities.mol.process_mol, if the +molecule is to be obtained via fw_spec, mol should be a string +corresponding to the key in fw_spec.

+
+
operation_type : str, optional

Type of operation to perform. See +mispr.gaussian.utilities.mol.process_mol for details of supported types.

+
+
db : str or dict, optional

Database credentials; could be provided as +the path to the db.json file or in the form of a dictionary; if none is +provided, attempts to get it from the configuration files.

+
+
save_to_db : bool, optional

Whether to save the processed molecule to the +molecules collection in the db.

+
+
charge : int, optional

Charge of the molecule.

+
+
update_duplicates : bool, optional

Whether to update molecule document in the +db if it already exists.

+
+
save_to_file : bool, optional

Whether to save the processed molecule to a file.

+
+
fmt : str, optional

Molecule file format if save_to_file is True. Defaults to xyz.

+
+
filename : str, optional

Name of the file to save the molecule to if +save_to_file is True. Defaults to molecular formula.

+
+
from_fw_spec : bool, optional

Whether to get the molecule from the fw_spec; +mol in this case is the key to the dict in fw_spec.

+
+
local_opt : bool, optional

Whether to perform local optimization on the +molecule.

+
+
force_field : str, optional

Force field to use for local optimization; see +mispr.gaussian.utilities.mol.process_mol for supported force field types.

+
+
steps : int, optional

Number of steps to perform local optimization.

+
+
str_type : str, optional

format of string if operation_type is get_from_str; +e.g. smi or any other format supported by OpenBabel).

+
+
working_dir : str, optional

Working directory to save the molecule file to or +read input files from.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.geo_transformation.RetrieveMoleculeObject(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Retrieve a molecule object from the database using InChI as an identifier and add +it to the fw_spec.

+
+
Parameters:ΒΆ
+
+
inchi : str

InChI string.

+
+
db : str or dict, optional

Database credentials.

+
+
save_mol_file : bool, optional

Whether to save the retrieved molecule to file.

+
+
fmt : str, optional

Format of the molecule file to create if save_mol_file is +True. Defaults to xyz.

+
+
filename : str

Name of the molecule file to create if save_mol_file is True; +will use molecular formula if not specified.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.gaussian.firetasks.parse_outputs moduleΒΆ

+

Define firetasks for parsing Gaussian output files.

+
+
+class mispr.gaussian.firetasks.parse_outputs.BDEtoDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Enter a bond dissociation energy calculation into the database. The calculation can +correspond to one or more bonds in the same molecule.

+
+
Parameters:ΒΆ
+
+
principle_mol_key : str, optional

Key of the Gaussian run corresponding to the +principle molecule in the fw_spec.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the β€œdb.json” file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to insert the BDE dict to the BDE +collection in the db.

+
+
save_to_file : bool, optional

Whether to save the BDE dict to a json file; if +True, will save to a file named β€œbde.json”.

+
+
solvent_gaussian_inputs : str, optional

Gaussian inputs for the implicit +solvent model to add to the BDE dict, if any.

+
+
solvent_properties : dict, optional

Implicit solvent properties to add to the +final BDE dict, if any.

+
+
additional_prop_doc_fields : dict, optional

Additional fields to add to the final +BDE dict.

+
+
visualize : bool, optional

Whether to create a bar plot of the BDE results +along with the 2D structure of the principle molecule with highlighted +broken bonds.

+
+
color : tuple, optional

RGB color to use for highlighting the broken bonds in +the molecule; e.g. (0.0, 0.0, 0.0) for black; if not provided, will use +(197 / 255, 237 / 255, 223 / 255, 1).

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.BindingEnergytoDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Enter a binding energy run into the database. The binding energy value is in eV.

+
+
Parameters:ΒΆ
+
+
index : list

List of indices of the two sites in the molecules at which they +are expected to bind.

+
+
keys : list

List of keys of Gaussian runs in fw_spec to use in building the +binding energy document; e.g. these keys could correspond to set of +optimization and frequency jobs leading to the final result.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the β€œdb.json” file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to insert the binding energy dict to the +binding energy collection in the db.

+
+
save_to_file : bool, optional

Whether to save the binding energy dict to a json +file; if True, will save to a file named β€œbinding_energy.json”.

+
+
additional_prop_doc_fields : dict, optional

Additional fields to add to the final +binding energy dict.

+
+
solvent_gaussian_inputs : str, optional

Gaussian inputs for the implicit +solvent model to add to the final binding energy dict, if any.

+
+
solvent_properties : dict, optional

Implicit solvent properties to add to the +final binding energy dict, if any.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.ESPtoDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Enter an ESP run into the database.

+
+
Parameters:ΒΆ
+
+
keys : list

List of keys of Gaussian runs in fw_spec to use in building the +ESP document; e.g. these keys could correspond to optimization, frequency, +and ESP jobs leading to the final result.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the β€œdb.json” file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to insert the ESP dict to the ESP +collection in the db.

+
+
save_to_file : bool, optional

Whether to save the ESP dict to a json file; if +True, will save to a file named β€œesp.json”.

+
+
additional_prop_doc_fields : dict, optional

Additional fields to add to +the final ESP dict.

+
+
solvent_gaussian_inputs : str, optional

Gaussian inputs for the implicit +solvent model to add to the final ESP dict, if any.

+
+
solvent_properties : dict, optional

Implicit solvent properties to add to the +final ESP dict, if any.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.IPEAtoDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Insert a redox potential run into the database. Save both Gibbs free energies and +redox potentials. If a calculation is performed in multiple steps, will save all +intermediate energies.

+
+
Parameters:ΒΆ
+
+
num_electrons : int

Number of electrons transferred.

+
+
states : list

List of states used in the calculation; e.g. [β€œcation”] for +oxidation, [β€œanion”] for reduction, or [β€œcation”, β€œanion”] for oxidation +and reduction calculations.

+
+
phases : list

List of phases to involved in the calculations; e.g. [β€œsolution”] +for liquid phase, [β€œgas”] for gas phase, or [β€œgas”, β€œsolution”] for the +full thermodynamic cycle.

+
+
steps : str

Whether the redox potential calculation is performed in a single +or multi step electron transfer process.

+
+
root_node_key : str

Key of the Gaussian run corresponding to the root node in +fw_spec.

+
+
keys : list

List of keys of Gaussian runs in fw_spec to use in building the +redox potential document; e.g. these keys could correspond to set of +optimization and frequency jobs leading to the final result.

+
+
pcet : bool

Whether a PCET calculation is performed.

+
+
vertical : bool

Whether a vertical IP/EA calculation is performed.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the β€œdb.json” file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to insert the redox potential dict to the +redox potential collection in the db.

+
+
save_to_file : bool, optional

Whether to save the redox potential dict to a json +file; if True, will save to a file named β€œip_ea.json”.

+
+
solvent_gaussian_inputs : str, optional

Gaussian inputs for the implicit +solvent model to add to the redox potential dict, if any.

+
+
solvent_properties : dict, optional

Implicit solvent properties to add to the +final redox potential dict, if any.

+
+
electrode_potentials : dict, optional

Dictionary of additional electrode +potentials to be used in converting the absolute oxidation and reduction +potentials to commonly used potential scales; note that the hydrogen, +lithium, and magnesium scales are already included; the dictionary should +be in the form:

+
{
+ "<metal>": {
+            "potential": <float>,
+            "ref": bibtex_parser("<ref_bib_file>", dir),
+        }
+}
+
+
+
+

Note

+

bibtexparser needs to be imported from mispr.gaussian.utilities.files.

+
+

+
+
additional_prop_doc_fields : dict, optional

Additional fields to add to the final +redox potential dict.

+
+
gibbs_elec : float, optional

The electron gibbs free energy in Hartree.

+
+
gibbs_h : float, optional

The hydrogen gibbs free energy in Hartree.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.NMRtoDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Enter an NMR run into the database.

+
+
Parameters:ΒΆ
+
+
keys : list

List of keys of Gaussian runs in fw_spec to use in building the +NMR document; e.g. these keys could correspond to optimization, frequency, +and NMR jobs leading to the final result.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the db.json file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to insert the NMR dict to the NMR +collection in the db.

+
+
save_to_file : bool, optional

Whether to save the NMR dict to a json file; if +True, will save to a file named β€œnmr.json”.

+
+
additional_prop_doc_fields : dict, optional

Additional fields to add to the final +NMR dict.

+
+
solvent_gaussian_inputs : str, optional

Gaussian inputs for the implicit +solvent model to add to the final NMR dict, if any.

+
+
solvent_properties : dict, optional

Implicit solvent properties to add to the +final NMR dict, if any.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.ProcessRun(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Process Gaussian output files from a single run. Enters the run to db and/or create +a summary json file.

+
+
Parameters:ΒΆ
+
+
run : GaussianOutput, str, dict

The actual Gaussian run; type depends on the +operation_type.

+
+
operation_type : str, optional

Type of operation to be performed; refer to +mispr.gaussian.utilities.gout.process_run for supported ones.

+
+
db : str or dict, optional

Database credentials to store the run; could be +provided as the path to the db.json file or in the form of a dictionary.

+
+
save_to_db : bool, optional

Whether to save the run to db.

+
+
save_to_file : bool, optional

Whether to save the run to a json file.

+
+
filename : str, optional

Name of the json file to save the run to; uses +β€œrun.json” if not provided.

+
+
input_file : str, optional

The input file for the run; used for adding Gaussian +input parameters to the final Gaussian dictionary; if not specified, will get +these parameters from the run itself, but in this case, β€œinput_parameters” +usually specified at the end of the Gaussian input file will not be saved +since they are not easily retrieved from the Gaussian output file.

+
+
gout_key : str, optional

The key to use for the run in the mod_spec dict passed +to FWAction; used when contents of the run are needed in other tasks.

+
+
format_chk : bool, optional

Whether to create a formatted check file from the +Gaussian checkpoint file.

+
+
formchk_cmd : str, optional

The full command to use for formatting the +checkpoint file; if not provided, will attempt to find one in the configuration +files.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.parse_outputs.RetrieveGaussianOutput(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Get a Gaussian output dict from fw_spec or the database, convert it to a +GaussianInput object, and add it to fw_spec.

+
+
Parameters:ΒΆ
+
+
db : str or dict, optional

Database credentials; could be provided as the path +to the db.json file or in the form of a dictionary.

+
+
gaussian_input_params : dict, optional

Parameters to use in creating the +GaussianInput object; if not provided, will use the ones in the passed +or retrieved Gaussian output dict.

+
+
run_id : str, optional

ID of the run to retrieve from the database; e.g. +β€œ5e3737d9da0b1cbbd5d556f7”.

+
+
inchi : str, optional

InChI of the molecule; used as a query criteria to +retrieve the run from the db.

+
+
functional : str, optional

Density functional of the run in the db; used as a +query criteria.

+
+
basis : str, optional

Basis set of the run in the db; used as a query criteria.

+
+
type : str, optional

Type of the Gaussian job run in the db; e.g. β€œopt” or +β€œfreq”; used as a query criteria.

+
+
phase : str, optional

Phase of the run in the db; e.g. β€œgas” or β€œsolution”; +used as a query criteria.

+
+
tag : str, optional

Tag of the run in the db; used as a query criteria.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.gaussian.firetasks.run_calc moduleΒΆ

+

Define firetasks for running Gaussian calculations.

+
+
+class mispr.gaussian.firetasks.run_calc.RunGaussianCustodian(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run Gaussian using custodian.

+
+
Parameters:ΒΆ
+
+
input_file : str, optional

Name of the Gaussian input file.

+
+
output_file : str, optional

Name of the Gaussian output file.

+
+
gaussian_cmd : str, optional

Name of the full executable to run; if not +provided, will attempt to find the command in the config file.

+
+
stderr_file : str, optional

Name of the file to direct standard error to.

+
+
job_type : str, optional

Type of job to run; supported options are (1) normal +and (2) better_guess. Defaults to β€œnormal”.

+
+
backup : bool, optional

Whether to backup the initial input file; if True, +the input will be copied with a β€œ.orig” appended. Defaults to True.

+
+
scf_max_cycles : int, optional

Maximum number of SCF cycles to run; +defaults to 100.

+
+
opt_max_cycles : int, optional

Maximum number of optimization cycles to run; +defaults to 100.

+
+
cart_coords : bool, optional

Whether to use cartesian coordinates; +defaults to True.

+
+
max_errors : int, optional

Maximum number of errors to handle before giving +up. Defaults to the number specified in mispr.gaussian.defaults.py.

+
+
lower_functional : str, optional

Lower level of theory to use if the +optimization fails and job_type is set to β€œbetter_guess; this will attempt +to generate a better initial guess of the geometry before running the +job again at the higher level of theory.

+
+
lower_basis_set : str, optional

Less expensive basis set to use if the +optimization fails and job_type is set to β€œbetter_guess; this will attempt +to generate a better initial guess of the geometry before running the job +again at the higher level of theory.

+
+
prefix : str, optional

Prefix to the files. Defaults to error, which means a +series of error.1.tar.gz, error.2.tar.gz, … will be generated.

+
+
suffix : str, optional

A suffix to be appended to the final output; +e.g., to rename all Gaussian output from mol.out to mol.out.1, provide β€œ.1” +as the suffix.

+
+
check_convergence : bool, optional

Whether to check convergence in an +optimization job; this will also generate a plot with the convergence +criteria as a function of the number of iterations. Defaults to True.

+
+
wall_time : int, optional

Wall time set to the job in seconds; if provided, +will add the WallTimeErrorHandler, which will restart the job if it hits +the wall time limit.

+
+
buffer_time : int, optional

Buffer time set to the job in seconds; if +provided; if the remaining time for the job = buffer_time, the +WallTimeErrorHandler will cancel the job and restart it; this is done +because if the job hits wall time on its own and is cancelled, it will no +longer be possible to restart it. Defaults to 300 seconds.

+
+
max_wall_time_corrections : int, optional

Maximum number of wall time +corrections to make. Defaults to 3.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.run_calc.RunGaussianDirect(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Execute a command directly for running Gaussian (no custodian).

+
+
Parameters:ΒΆ
+
+
input_file : str, optional

Name of the Gaussian input file.

+
+
output_file : str, optional

Name of the Gaussian output file.

+
+
gaussian_cmd : str, optional

Name of the full executable to run; if not +provided, will attempt to find the command in the config file.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.gaussian.firetasks.run_calc.RunGaussianFake(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run a fake Gaussian calculation.

+
+
Parameters:ΒΆ
+
+
ref_dir : str

Path to reference Gaussian run directory with input and output +files in the folder.

+
+
working_dir : str, optional

Directory where the fake calculation will be run.

+
+
input_file : str, optional

Name of the input file (both reference input and new +input). Defaults to mol.com.

+
+
tolerance : float, optional

Tolerance for the comparison of the reference and +user input file. Defaults to 0.0001.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.gaussian.firetasks.write_inputs moduleΒΆ

+

Define firetasks for writing Gaussian input files.

+
+
+class mispr.gaussian.firetasks.write_inputs.WriteInput(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Write Gaussian input file for a molecule/cluster in the current working directory.

+
+
Parameters:ΒΆ
+
+
gaussian_input : GaussianInput, optional

A GaussianInput object to be +written to a file; can either be provided directly or passed through +fw_spec; if both are provided, will take the one provided directly.

+
+
molecule : Molecule, optional

A Molecule object to be used in creating +Gaussian input file; can be provided as an optional parameter or passed +through fw_spec; if both are provided, will check if their graphs are +isomorphic; if they are isomorphic, will use the molecule passed through +fw_spec, otherwise will take the user input; note that molecule is +ignored if a gaussian_input is available.

+
+
gaussian_input_params : dict, optional

A dictionary of parameters to be used +in creating the Gaussian input file; ignored if a gaussian_input is +provided.

+
+
input_file : str, optional

Name of the input file to be written; default is +β€œmol.com”.

+
+
cart_coords : bool, optional

Whether to write cartesian coordinates or not; +default is True.

+
+
oxidation_states : dict, optional

A dictionary of element symbols and their +oxidation states used in setting the charge on the molecule.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.fireworks.html b/html/mispr.gaussian.fireworks.html new file mode 100644 index 00000000..de684bb2 --- /dev/null +++ b/html/mispr.gaussian.fireworks.html @@ -0,0 +1,1157 @@ + + + + + + + + + + + + + + + + mispr.gaussian.fireworks package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.gaussian.fireworks packageΒΆ

+

SubmodulesΒΆ

+

mispr.gaussian.fireworks.break_mol moduleΒΆ

+

Define firework used to break a molecule and run its fragments.

+
+
+class mispr.gaussian.fireworks.break_mol.BreakMolFW(mol, mol_operation_type='get_from_mol', bonds=None, open_rings=False, ref_charge=0, fragment_charges=None, calc_frags=True, db=None, name='break_mol', parents=None, working_dir=None, tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Process a molecule input, break it into unique fragments, and generate a set of +optimization and frequency calculations for each fragment (optional).

+
+
Parameters:ΒΆ
+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
mol_operation_type : str, optionalΒΆ

The type of molecule operation. +See process_mol defined in mispr/gaussian/utilities/mol.py for +supported operations. Defaults to get_from_mol.

+
+
bonds : list, optionalΒΆ

List of tuples of the bonds to break; e.g. +[(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between +atoms 1 and 2; if none is specified, will attempt to break all bonds.

+
+
open_rings : bool, optionalΒΆ

Whether to open rings; if set to True, will +perform local optimization to get a good initial guess for the +structure. Defaults to False.

+
+
ref_charge : int, optionalΒΆ

Charge on the principle molecule. Defaults to 0.

+
+
fragment_charges : list, optionalΒΆ

List of charges to assign to the +fragments in addition to the ones already assigned; refer to +mispr.gaussian.firetasks.geo_transformation.BreakMolecule for more +details.

+
+
calc_frags : bool, optionalΒΆ

Whether to create optimization and frequency +Fireworks for the generated fragments. Defaults to True.

+
+
db : str or dict, optionalΒΆ

Database credentials.

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to break_mol.

+
+
parents : Firework or [Firework]ΒΆ

List of parent FWs this FW +depends on.

+
+
working_dir : str, optionalΒΆ

Working directory for the calculation; will +use the current working directory if not specified.

+
+
tag : str, optionalΒΆ

Tag for the calculation; the provided tag will be +stored in the db documents for easy retrieval. Defaults to β€œunknown”.

+
+
**kwargsΒΆ

Other kwargs that are passed to:

+
    +
  1. Firework.__init__.

  2. +
  3. mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput

  4. +
  5. mispr.gaussian.firetasks.geo_transformation.BreakMolecule

  6. +
+

+
+
+
+
+
+ +

mispr.gaussian.fireworks.core moduleΒΆ

+

Define common fireworks used in Gaussian workflows.

+
+
+class mispr.gaussian.fireworks.core.CalcFromMolFW(mol, mol_operation_type='get_from_mol', db=None, name='calc_from_mol', parents=None, working_dir=None, input_file='mol.com', output_file='mol.out', gaussian_input_params={}, cart_coords=True, oxidation_states=None, tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Run a Gaussian calculation from a molecule.

+
+
Parameters:ΒΆ
+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
mol_operation_type : str, optionalΒΆ

The type of molecule operation. See +process_mol defined in mispr/gaussian/utilities/mol.py for supported +operations. Defaults to get_from_mol.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the +path to the db.json file or in the form of a dictionary; if none is +provided, attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to calc_from_mol.

+
+
parents : Firework or [Firework], optionalΒΆ

List of parent FWs this FW +depends on.

+
+
working_dir : str, optionalΒΆ

Working directory for the calculation; defaults +to the current directory.

+
+
input_file : str, optionalΒΆ

Name of the Gaussian input file to be created; +defaults to β€œmol.com”.

+
+
output_file : str, optionalΒΆ

Name of the Gaussian output file to be output; +defaults to β€œmol.out”.

+
+
gaussian_input_params : dict, optionalΒΆ

Dictionary of parameters to be +used in the Gaussian input file.

+
+
cart_coords : bool, optionalΒΆ

Whether the coordinates are cartesian or +z-matrix. Defaults to True.

+
+
oxidation_states : list, optionalΒΆ

List of oxidation states for each atom; +defaults to None.

+
+
tag : str, optionalΒΆ

Tag for the calculation; the provided tag will be +stored in the db documents for easy retrieval. Defaults to β€œunknown”.

+
+
**kwargsΒΆ

other kwargs that are passed to:

+
    +
  1. Firework.__init__.

  2. +
  3. mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput

  4. +
  5. mispr.gaussian.fireworks.common_tasks

  6. +
+

+
+
+
+
+
+ +
+
+class mispr.gaussian.fireworks.core.CalcFromRunsDBFW(db=None, name='calc_from_runs_db', parents=None, gaussian_input_params=None, working_dir=None, input_file='mol.com', output_file='mol.out', cart_coords=True, tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Run a Gaussian calculation from a previous calculation or the runs database.

+
+
Parameters:ΒΆ
+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the +path to the db.json file or in the form of a dictionary; if none is +provided, attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to calc_from_runs_db.

+
+
parents : Firework or [Firework], optionalΒΆ

List of parent FWs this FW +depends on.

+
+
gaussian_input_params : dict, optionalΒΆ

Dictionary of parameters to be used +in the Gaussian input file.

+
+
working_dir : str, optionalΒΆ

Working directory for the calculation; +defaults to the current directory.

+
+
input_file : str, optionalΒΆ

Name of the Gaussian input file to be created; +defaults to β€œmol.com”.

+
+
output_file : str, optionalΒΆ

Name of the Gaussian output file to be output; +defaults to β€œmol.out”.

+
+
cart_coords : bool, optionalΒΆ

Whether the coordinates are cartesian or +z-matrix. Defaults to True.

+
+
tag : str, optionalΒΆ

Tag for the calculation; the provided tag will be +stored in the db documents for easy retrieval. Defaults to β€œunknown”.

+
+
**kwargsΒΆ

other kwargs that are passed to:

+
    +
  1. Firework.__init__.

  2. +
  3. mispr.gaussian.firetasks.parse_outputs.RetrieveGaussianOutput

  4. +
  5. mispr.gaussian.fireworks.common_tasks

  6. +
+

+
+
+
+
+
+ +
+
+mispr.gaussian.fireworks.core.common_tasks(db, input_file, output_file, gaussian_input_params, cart_coords, oxidation_states, **kwargs)[source]ΒΆ
+

Define a list of common tasks for Gaussian fireworks, i.e. writing an input file, +running the calculation, and parsing the output.

+
+
Parameters:ΒΆ
+
+
db : str or dictΒΆ

Database credentials to store the run; could be provided as +the path to the db.json file or in the form of a dictionary.

+
+
input_file : strΒΆ

Name of the input file to be written.

+
+
output_file : strΒΆ

name of the Gaussian output file

+
+
gaussian_input_params : dictΒΆ

A dictionary of parameters to be used in creating +the Gaussian input file.

+
+
cart_coords : boolΒΆ

Whether to write cartesian coordinates or not; default +is True.

+
+
oxidation_states : dictΒΆ

A dictionary of element symbols and their oxidation +states used in setting the charge on the molecule.

+
+
**kwargsΒΆ

other kwargs that are passed to:

+
    +
  1. mispr.gaussian.firetasks.write_inputs.WriteInput

  2. +
  3. mispr.gaussian.firetasks.run_calc.RunGaussianCustodian

  4. +
  5. mispr.gaussian.firetasks.parse_outputs.ProcessRun

  6. +
+

+
+
+
+
Returns:ΒΆ
+

List of Firetasks.

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.html b/html/mispr.gaussian.html new file mode 100644 index 00000000..f7b706be --- /dev/null +++ b/html/mispr.gaussian.html @@ -0,0 +1,1653 @@ + + + + + + + + + + + + + + + + mispr.gaussian package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.gaussian packageΒΆ

+

SubpackagesΒΆ

+
+ +
+

SubmodulesΒΆ

+

mispr.gaussian.database moduleΒΆ

+

Define the Gaussian database class.

+
+
+class mispr.gaussian.database.GaussianCalcDb(host, port=None, name=None, username=None, password=None, uri_mode=False, **kwargs)[source]ΒΆ
+

Bases: object

+

Class to help manage database insertions of molecules and Gaussian calculations.

+
+
+abstract build_indexes(background=True)[source]ΒΆ
+

Build indexes for the database.

+
+
Parameters:ΒΆ
+
+
background : bool, optionalΒΆ

If True, this index should be created.

+
+
+
+
+
+ +
+
+delete_molecule(inchi)[source]ΒΆ
+

Delete a molecule from the molecules collection.

+
+
Parameters:ΒΆ
+
+
inchi : strΒΆ

The inchi representation of the molecule to delete.

+
+
+
+
+
+ +
+
+classmethod from_db_file(db_file, admin=True)[source]ΒΆ
+

Create a new database object from a database file.

+
+
Parameters:ΒΆ
+
+
db_file : strΒΆ

The path to the database file.

+
+
admin : bool, optionalΒΆ

Whether to use admin credentials; defaults to +True.

+
+
+
+
Returns:ΒΆ
+

GaussianCalcDb.

+
+
+
+ +
+
+insert_derived_mol(derived_mol, update_duplicates)[source]ΒΆ
+

Insert a derived molecule into the derived_molecules collection.

+
+
Parameters:ΒΆ
+
+
derived_mol : MoleculeΒΆ

pymatgen.Molecule object.

+
+
update_duplicates : boolΒΆ

Whether to update duplicates if the molecule +already exists.

+
+
+
+
+
+ +
+
+insert_fg(fg_file)[source]ΒΆ
+

Insert functional groups into their collection using a json file. The file can +contain one or more functional groups.

+
+
Parameters:ΒΆ
+
+
fg_file : strΒΆ

The path to the json file.

+
+
+
+
+
+ +
+
+insert_molecule(mol, update_duplicates=False)[source]ΒΆ
+

Insert a molecule into the molecules collection.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

A pymatgen Molecule object to insert.

+
+
update_duplicates : bool, optionalΒΆ

If True, update the existing +molecule in the db with the new one. Defaults to False.

+
+
+
+
+
+ +
+
+insert_property(collection_name, property_dict, index, **kwargs)[source]ΒΆ
+

Insert a document into a property collection in the database.

+
+
Parameters:ΒΆ
+
+
collection_name : strΒΆ

The name of the collection to insert the property +into; e.g. bde, binding_energy, etc.

+
+
property_dict : dictΒΆ

The property dictionary to insert.

+
+
index : str, list[tuple]ΒΆ

The indexes to use for fast lookup.

+
+
**kwargsΒΆ

Additional kwargs to pass to pymongo.collection.create_index.

+
+
+
+
+
+ +
+
+insert_run(grun)[source]ΒΆ
+

Insert a Gaussian run into the runs collection.

+
+
Parameters:ΒΆ
+
+
grun : dictΒΆ

A dictionary containing the Gaussian run.

+
+
+
+
+
+ +
+
+move_runs(new_collection, inchi=None, smiles=None, functional=None, basis=None, **kwargs)[source]ΒΆ
+

Move documents from the runs collection to another collection.

+
+
Parameters:ΒΆ
+
+
new_collection : strΒΆ

The name of the collection to move the runs to.

+
+
inchi : str, optionalΒΆ

The inchi representation of the molecule.

+
+
smiles : str, optionalΒΆ

The smiles representation of the molecule.

+
+
functional : str, optionalΒΆ

The name of the density functional.

+
+
basis : str, optionalΒΆ

The name of the basis set.

+
+
**kwargsΒΆ

Other kwargs that can be used to query the collection.

+
+
+
+
+
+ +
+
+query_molecules(query)[source]ΒΆ
+

Query the molecules collection.

+
+
Parameters:ΒΆ
+
+
query : dictΒΆ

A query document that selects which documents to include in +the result set; e.g. keys can be inchi, smiles, chemsys, etc.

+
+
+
+
Returns:ΒΆ
+

A dataframe of documents that match the query.

+
+
Return type:ΒΆ
+

pd.DataFrame

+
+
+
+ +
+
+retrieve_doc(collection_name, inchi=None, smiles=None, functional=None, basis=None, **kwargs)[source]ΒΆ
+

Retrieve a document from any collection of the database.

+
+
Parameters:ΒΆ
+
+
collection_name : strΒΆ

The name of the collection, e.g. bde, molecules, +runs, etc.

+
+
inchi : str, optionalΒΆ

The inchi representation of the molecule.

+
+
smiles : str, optionalΒΆ

The smiles representation of the molecule.

+
+
functional : str, optionalΒΆ

The name of the density functional.

+
+
basis : str, optionalΒΆ

The name of the basis set.

+
+
**kwargsΒΆ

Other kwargs that can be used to query the collection.

+
+
+
+
Returns:ΒΆ
+

A list of documents that match the query

+
+
Return type:ΒΆ
+

list

+
+
+
+ +
+
+retrieve_fg(name)[source]ΒΆ
+

Retrieve a functional group from the functional_groups collection.

+
+
Parameters:ΒΆ
+
+
name : strΒΆ

The name of the functional group to retrieve.

+
+
+
+
Returns:ΒΆ
+

dict

+
+
+
+ +
+
+retrieve_molecule(inchi)[source]ΒΆ
+

Retrieve a molecule from the molecules collection.

+
+
Parameters:ΒΆ
+
+
inchi : strΒΆ

The inchi representation of the molecule.

+
+
+
+
Returns:ΒΆ
+

dict

+
+
+
+ +
+
+retrieve_run(inchi=None, smiles=None, functional=None, basis=None, **kwargs)[source]ΒΆ
+

Retrieve a run from the runs collection.

+
+
Parameters:ΒΆ
+
+
inchi : str, optionalΒΆ

The inchi representation of the molecule.

+
+
smiles : str, optionalΒΆ

The smiles representation of the molecule.

+
+
functional : str, optionalΒΆ

The name of the density functional.

+
+
basis : str, optionalΒΆ

The name of the basis set.

+
+
**kwargsΒΆ

Other kwargs that can be used to query the collection.

+
+
+
+
Returns:ΒΆ
+

A list of documents that match the query.

+
+
Return type:ΒΆ
+

list

+
+
+
+ +
+
+update_run(new_values, inchi=None, smiles=None, job_type=None, functional=None, basis=None, phase=None, **kwargs)[source]ΒΆ
+

Update a document in the runs collection. If multiple documents match the query +criteria, will select the first one.

+
+
Parameters:ΒΆ
+
+
new_values : dictΒΆ

The new output values to update the document with, e.g.

+
+
code-block: : ..

python: {β€œpolarizability”: 3.5}

+
+
inchi : str, optionalΒΆ

The inchi representation of the molecule.

+
+
smiles : str, optionalΒΆ

The smiles representation of the molecule.

+
+
job_type : str, optionalΒΆ

The type of job, e.g. β€œopt”, β€œfreq”.

+
+
functional : str, optionalΒΆ

The name of the density functional.

+
+
basis : str, optionalΒΆ

The name of the basis set.

+
+
phase : str, optionalΒΆ

The phase of the job, e.g. β€œgas”, β€œsolution”.

+
+
**kwargsΒΆ

Other kwargs that can be used to query the collection.

+
+
+
+
+
+ +
+ +

mispr.gaussian.defaults moduleΒΆ

+

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.utilities.html b/html/mispr.gaussian.utilities.html new file mode 100644 index 00000000..b8a99d81 --- /dev/null +++ b/html/mispr.gaussian.utilities.html @@ -0,0 +1,1739 @@ + + + + + + + + + + + + + + + + mispr.gaussian.utilities package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.gaussian.utilities packageΒΆ

+

SubmodulesΒΆ

+

mispr.gaussian.utilities.db_utilities moduleΒΆ

+

Define db utility functions.

+
+
+mispr.gaussian.utilities.db_utilities.get_db(input_db=None)[source]ΒΆ
+

Helper function to create a GaussianCalcDb instance from a file or a dict.

+
+
Parameters:ΒΆ
+
+
input_db : str or dict, optionalΒΆ

Path to db file or a dict containing db info.

+
+
+
+
Returns:ΒΆ
+

GaussianCalcDb.

+
+
+
+ +

mispr.gaussian.utilities.dbdoc moduleΒΆ

+

Define functions for cleaning up JSON documents.

+
+
+mispr.gaussian.utilities.dbdoc.add_solvent_to_prop_dict(prop_dict, solvent_gaussian_inputs, solvent_properties)[source]ΒΆ
+

Add solvent properties to a property dictionary (e.g. BDE, BE, etc.).

+
+
Parameters:ΒΆ
+
+
prop_dict : dictΒΆ

Property dictionary.

+
+
solvent_gaussian_inputs : strΒΆ

Gaussian input parameters corresponding to the +implicit solvent model used in the Gaussian calculations, e.g. +β€œ(Solvent=TetraHydroFuran)”.

+
+
solvent_properties : dictΒΆ

Additional solvent input parameters used in the +Gaussian calculations; e.g., {β€œEPS”:12}.

+
+
+
+
Returns:ΒΆ
+

Property dictionary with solvent properties added.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +

mispr.gaussian.utilities.files moduleΒΆ

+

Define utility functions for handling files and paths.

+
+
+mispr.gaussian.utilities.files.bibtex_parser(bib_file, working_dir)[source]ΒΆ
+

Parse a bibtex file and returns a dictionary of the entries.

+
+
Parameters:ΒΆ
+
+
bib_file : strΒΆ

Relative or absolute path to the bibtex file.

+
+
working_dir : strΒΆ

Name of the working directory where the bibtex file is +located if bib_file path is relative; else None.

+
+
+
+
Returns:ΒΆ
+

Dictionary of the entries in the bibtex file.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +
+
+mispr.gaussian.utilities.files.recursive_relative_to_absolute_path(operand, working_dir)[source]ΒΆ
+

Convert recursively relative paths to absolute paths.

+
+
Parameters:ΒΆ
+
+
operand : str, list, dictΒΆ

File, list of files, or a dictionary where the values +are the files; the file(s) path can be relative or absolute.

+
+
working_dir : strΒΆ

Name of the working directory where the file(s) is/are +located if operand path is relative; else None.

+
+
+
+
Returns:ΒΆ
+

+
File, list of files, or dict where the values are the

absolute paths.

+
+
+

+
+
Return type:ΒΆ
+

str or list or dict

+
+
+
+ +

mispr.gaussian.utilities.fw_utilities moduleΒΆ

+

Define utility functions for modifying workflow settings. Based on atomate powerups.

+
+
+mispr.gaussian.utilities.fw_utilities.add_common_mods(workflow, fw_mods=None)[source]ΒΆ
+

Wrapper function to add common modifications to a workflow.

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to modify.

+
+
fw_mods : dict, optionalΒΆ

A dictionary of modifications to be applied to the +workflow; supported ones are CONTROL_WORKER, MODIFY_QUEUE_PARAMETERS, +REPLACE_RUNTASK, and RUN_FAKE_GAUSSIAN (see the docstring of each +function for more details); values of the dictionary are the inputs to the +corresponding function.

+
+
+
+
Returns:ΒΆ
+

The modified workflow.

+
+
Return type:ΒΆ
+

Workflow

+
+
+
+ +
+
+mispr.gaussian.utilities.fw_utilities.control_worker(workflow, firework_substring=None, task_substring=None, fworker=None, category=None)[source]ΒΆ
+

Modify the Firework’s fworker name and category in a workflow. Can be used when +running workflows on multiple workers at the same time to specify which +worker/machine to use.

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to control.

+
+
firework_substring : str, optionalΒΆ

A substring to search for in the Firework +names to exclude certain fireworks.

+
+
task_substring : str, optionalΒΆ

A substring to search for in the Firetask +names to exclude certain Firetasks.

+
+
fworker : str, optionalΒΆ

The name of the fworker to use for the Firework; +should be consistent with the one specified in the FireWorker +(my_fworker.yaml file).

+
+
category : str, optionalΒΆ

The category to be assigned for the Firework; should +be consistent with the one specified in the FireWorker (my_fworker.yaml file).

+
+
+
+
Returns:ΒΆ
+

The modified workflow with the specified fworker and/or category.

+
+
Return type:ΒΆ
+

Workflow

+
+
+
+ +
+
+mispr.gaussian.utilities.fw_utilities.get_list_fireworks_and_tasks(workflow, firework_substring=None, task_substring=None)[source]ΒΆ
+

Return a list of (firework_index, task_index) tuples for all fireworks and tasks in +a workflow.

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to search.

+
+
firework_substring : str, optionalΒΆ

A substring to search for in the Firework +names to exclude certain fireworks.

+
+
task_substring : str, optionalΒΆ

A substring to search for in the Firetask +names to exclude certain Firetasks.

+
+
+
+
Returns:ΒΆ
+

A list of (firework_index, task_index) tuples.

+
+
Return type:ΒΆ
+

list

+
+
+
+ +
+
+mispr.gaussian.utilities.fw_utilities.modify_queue_parameters(workflow, ntasks_per_node=None, walltime=None, queue=None, pre_rocket=None, other_parameters=None, firework_substring=None, task_substring=None)[source]ΒΆ
+

Modify the default Firework’s queue parameters in a workflow. Default ones are +specified in the my_qadapter.yaml file. Helpful when different workflows requires +different computational resources (e.g. number of CPUs, memory, etc.).

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to modify.

+
+
ntasks_per_node : int, optionalΒΆ

The number of tasks to run on each node.

+
+
walltime : str, optionalΒΆ

The walltime for the job.

+
+
queue : str, optionalΒΆ

The queue/partition to run the job on.

+
+
pre_rocket : str, optionalΒΆ

The pre-rocket command to run before the job.

+
+
other_parameters : dict, optionalΒΆ

Other parameters to be added to the +queueadapter.

+
+
firework_substring : str, optionalΒΆ

A substring to search for in the Firework +names to exclude certain fireworks.

+
+
task_substring : str, optionalΒΆ

A substring to search for in the Firetask +names to exclude certain Firetasks.

+
+
+
+
Returns:ΒΆ
+

The modified workflow with the specified queue parameters.

+
+
Return type:ΒΆ
+

Workflow

+
+
+
+ +
+
+mispr.gaussian.utilities.fw_utilities.replace_runtask(workflow, firework_substring=None, operation='remove_custodian', additional_params=None)[source]ΒΆ
+

Replace all tasks with RunGaussian (e.g. RunGaussianDirect) with +RunGaussianCustodian or vice versa.

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to modify.

+
+
firework_substring : str, optionalΒΆ

A substring to search for in the Firework +names to exclude certain fireworks.

+
+
operation : str, optionalΒΆ

The operation to perform on the Firetask; supported +ones are remove_custodian and use_custodian.

+
+
additional_params : dict, optionalΒΆ

Additional parameters to be added to the +new Firetask that are not included in the original Firetask; refer to the +corresponding Firetask documentation for supported parameters.

+
+
+
+
Returns:ΒΆ
+

The workflow with the replaced run Firetasks.

+
+
Return type:ΒΆ
+

Workflow

+
+
+
+ +
+
+mispr.gaussian.utilities.fw_utilities.run_fake_gaussian(workflow, ref_dirs, input_files=None, tolerance=None)[source]ΒΆ
+

Replace all tasks with RunGaussian (i.e. RunGaussianDirect, RunGaussianCustodian) +with RunGaussianFake that runs a fake Gaussian job. We do not actually run Gaussian +but copy existing inputs and outputs. Useful for testing purposes.

+
+
Parameters:ΒΆ
+
+
workflow : WorkflowΒΆ

The workflow to modify.

+
+
ref_dirs : listΒΆ

A list of directories containing the reference calculations +for the fake Gaussian job (e.g. [β€˜home/opt’, β€˜home/freq’]).

+
+
input_files : list, optionalΒΆ

A list of input files for the fake Gaussian job; +order should match that in ref_dirs; e.g. [β€œopt.com”, β€œfreq.com”].

+
+
tolerance : float, optionalΒΆ

The tolerance for the comparison of the provided +input file with the existing one.

+
+
+
+
Returns:ΒΆ
+

The workflow with the replaced run Firetasks.

+
+
Return type:ΒΆ
+

Workflow

+
+
+
+ +

mispr.gaussian.utilities.gout moduleΒΆ

+

Define functions for processing different gaussian output formats.

+
+
+mispr.gaussian.utilities.gout.process_run(operation_type, run, input_file=None, **kwargs)[source]ΒΆ
+

Process a Gaussian run and returns a dictionary of the results. Used for creating +db documents and/or json files.

+
+
Parameters:ΒΆ
+
+
operation_type : strΒΆ

Type of operation to be performed; supported ones are:

+
    +
  1. get_from_gout: Get data from a GaussianOutput object as defined in +pymatgen.io.gaussian.

  2. +
  3. get_from_gout_file: Get data from a Gaussian output file.

  4. +
  5. get_from_run_dict: Get data from a Gaussian output dictionary.

  6. +
  7. get_from_run_id: Retrieve data from dtabase using a run id, +e.g. β€œ5e3737d9da0b1cbbd5d556f7”.

  8. +
  9. get_from_run_query: Retrieve data from dtabase using query criteria, +e.g.

    +
    {"smiles": "COCCOC", "type": "freq", "functional": "B3LYP",
    +"basis": "6-31+G*", "phase": "gas", ...}
    +
    +
    +
  10. +
+

+
+
run : GaussianOutput, str, dictΒΆ

The actual Gaussian run; type depends on the +operation_type.

+
+
input_file : str, optionalΒΆ

The input file for the run; used for adding Gaussian +input parameters to the final Gaussian dictionary; if not specified, will +get these parameters from the run itself, but in this case, +input_parameters usually specified at the end of the Gaussian input file +will not be saved since they are not easily retrieved from the Gaussian +output file.

+
+
kwargs : keyword argumentsΒΆ

Additional keyword arguments for the operation: +namely, working_dir and db.

+
+
+
+
Returns:ΒΆ
+

Cleaned up Gaussian output dictionary.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +

mispr.gaussian.utilities.inputs moduleΒΆ

+

Define functions for handling gaussian inputs.

+
+
+mispr.gaussian.utilities.inputs.handle_gaussian_inputs(gaussian_inputs, solvent_gaussian_inputs=None, solvent_properties=None)[source]ΒΆ
+

Wrapper function to cleanup/modify the Gaussian input parameters for one or more +job in a workflow. Checks for implicit solvent parameters and adds missing keywords +for a given job.

+
+
Parameters:ΒΆ
+
+
gaussian_inputs : dictΒΆ

Dictionary of dictionaries of Gaussian inputs, e.g.

+
{"opt": {opt_gaussian_inputs}, "freq": {freq_gaussian_inputs}}
+
+
+

+
+
solvent_gaussian_inputs : str, optionalΒΆ

String of Gaussian inputs for the +solvent, e.g.

+
"(Solvent=Generic, Read)"
+
+
+

+
+
solvent_properties : dict, optionalΒΆ

Dictionary of solvent properties, e.g.

+
{"Eps": 4.33, "EpsInf": 1.69}
+
+
+

+
+
+
+
Returns:ΒΆ
+

Dictionary of dictionaries of reformatted Gaussian inputs.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +

mispr.gaussian.utilities.metadata moduleΒΆ

+

Define functions for creating db schema.

+
+
+mispr.gaussian.utilities.metadata.get_chem_schema(mol)[source]ΒΆ
+

Return a dictionary of chemical schema for a given molecule to use in building db +documents or json file.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

Molecule object.

+
+
+
+
Returns:ΒΆ
+

Chemical schema.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +
+
+mispr.gaussian.utilities.metadata.get_job_name(mol, name)[source]ΒΆ
+

Append a molecule label to the name of a workflow for easy monitoring and +identification.

+
+
Parameters:ΒΆ
+
+
mol : Molecule or strΒΆ

If a Molecule is provided, the appended label will be +the molecular formula; otherwise the label will be the provided string.

+
+
name : strΒΆ

Original name of the workflow.

+
+
+
+
Returns:ΒΆ
+

Job name with molecule label.

+
+
Return type:ΒΆ
+

str

+
+
+
+ +
+
+mispr.gaussian.utilities.metadata.get_mol_formula(mol)[source]ΒΆ
+

Get the alphabetical molecular formula for a molecule.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

Molecule object

+
+
+
+
Returns:ΒΆ
+

Alphabetical molecular formula.

+
+
Return type:ΒΆ
+

str

+
+
+
+ +

mispr.gaussian.utilities.misc moduleΒΆ

+

Define miscellaneous functions useful in many of the mispr levels.

+
+
+mispr.gaussian.utilities.misc.pass_gout_dict(fw_spec, key)[source]ΒΆ
+

Helper function used in the Gaussian Fireworks to pass Gaussian output dictionaries +from one task to the other, while checking that the criteria for starting the +following task are met (e.g. normal termination of the previous job, lack of +imaginary frequencies, etc.).

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

Firework spec dictionary.

+
+
key : strΒΆ

Unique key for the Gaussian output dictionary in fw_spec.

+
+
+
+
Returns:ΒΆ
+

Gaussian output dictionary.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +
+
+mispr.gaussian.utilities.misc.recursive_compare_dicts(dict1, dict2, dict1_name, dict2_name, path='')[source]ΒΆ
+

Compare recursively two dictionaries and returns the differences.

+
+
Parameters:ΒΆ
+
+
dict1 : dictΒΆ

First dictionary to compare.

+
+
dict2 : dictΒΆ

Second dictionary to compare.

+
+
dict1_name : strΒΆ

Name of the first dictionary (for messages on the differences).

+
+
dict2_name : strΒΆ

Name of the second dictionary (for messages on the differences).

+
+
path : str, optionalΒΆ

Used internally to keep track of the keys in nested dicts, +meant to be β€œβ€ for the top level

+
+
+
+
Returns:ΒΆ
+

Differences between the two dictionaries (if any).

+
+
Return type:ΒΆ
+

str

+
+
+
+ +
+
+mispr.gaussian.utilities.misc.recursive_signature_remove(d)[source]ΒΆ
+

Remove Recursively the signature β€œ@” from a dictionary (e.g. those in the name of +a module). Used when processing Gaussian runs before saving them to the db.

+
+
Parameters:ΒΆ
+
+
d : dictΒΆ

Dictionary to remove the signature from.

+
+
+
+
Returns:ΒΆ
+

Dictionary with the signature removed.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +

mispr.gaussian.utilities.mol moduleΒΆ

+

Define functions for processing molecules.

+
+
+mispr.gaussian.utilities.mol.get_bond_order_str(mol)[source]ΒΆ
+

Find bond order as a string (β€œU”: unspecified, β€œS”, β€œD”: double, β€œT”: triple, +β€œA”: aromatic) by iterating over bonds of a molecule. First convert pymatgen mol +to openbabel mol to use openbabel in finding bond order.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

pymatgen Molecule object.

+
+
+
+
Returns:ΒΆ
+

+
Dictionary of bond orders with keys as tuples of atom indexes forming the

bond and values as bond order.

+
+
+

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +
+
+mispr.gaussian.utilities.mol.label_atoms(mol)[source]ΒΆ
+

Get the SMILES representation of a molecule and label the atoms that appear in the +SMILES string with the atom indexes as they appear in the molecule.

+

Helpful to know the atom indexes in the molecule without having to visualize it.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

The molecule to be labeled.

+
+
+
+
Returns:ΒΆ
+

SMILES string followed by atom indexes.

+
+
Return type:ΒΆ
+

str

+
+
+
+ +
+
+mispr.gaussian.utilities.mol.perform_local_opt(mol, force_field='uff', steps=200)[source]ΒΆ
+

Perform a local optimization on the molecule using OpenBabel.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

The molecule to be optimized.

+
+
force_field : str, optionalΒΆ

The force field to be used for the optimization; +options include gaff, ghemical, mmff94, mmff94s, and uff; +defaults to uff.

+
+
steps : intΒΆ

The number of steps to be performed in the local optimization; +defaults to 200.

+
+
+
+
Returns:ΒΆ
+

The optimized molecule.

+
+
Return type:ΒΆ
+

Molecule

+
+
+
+ +
+
+mispr.gaussian.utilities.mol.process_mol(operation_type, mol, local_opt=False, **kwargs)[source]ΒΆ
+

Process a molecule. Used for handling different molecule formats provided to +Gaussian workflows.

+
+
Parameters:ΒΆ
+
+
operation_type : strΒΆ

Operation to perform for the molecule to process the input +structure format. Supported commands:

+
    +
  1. get_from_mol: If the input is a pymatgen Molecule object.

  2. +
  3. get_from_file: If the input is any file format supported by Openabel +and pymatgen.

  4. +
  5. get_from_gout_file: If the input is a Gaussian output file.

  6. +
  7. get_from_str: If the input is a string.

  8. +
  9. get_from_mol_db: If the input is an InChI representation of the +molecule to be used to query the database.

  10. +
  11. get_from_gout: If the input is a pymatgen GaussianOutput object.

  12. +
  13. get_from_run_dict: If the input is a GaussianOutput dictionary.

  14. +
  15. get_from_run_id: If the input is a MongoDB document ID to be used +to query the database.

  16. +
  17. get_from_run_query: If the input is a dictionary with criteria to +search the database: e.g.

    +
    {'inchi': inchi,
    + 'type': type,
    + 'functional': func, ...}
    +
    +
    +
  18. +
  19. get_from_pubchem: If the input is a common name for the molecule +to be used in searching the PubChem database.

  20. +
  21. derive_molecule: Used for deriving a molecule by attaching a +functional group at a site and the corresponding mol input should be a +dictionary, e.g.

    +
    {'operation_type': <mol_operation_type for the base structure>,
    + 'mol': <base_mol>,
    + 'func_grp': func_group_name, ...}
    +
    +
    +
  22. +
  23. link_molecules: Used for linking two structures by forming a bond +at specific sites and the corresponding mol input should be a dictionary, +e.g.

    +
    {'operation_type': ['get_from_file', 'get_from_mol_db'],
    + 'mol': ['mol1.xyz', 'mol_inchi'],
    + 'index': [3, 5],
    + 'bond_order': 1}
    +
    +
    +
  24. +
+

+
+
mol : Molecule, str, GaussianOutput, dictΒΆ

Sources of structure, e.g. file path +if mol_operation_type is specified as get_from_file, InChI string if +mol_operation_type is specified as get_from_mol_db, etc.

+
+
local_opt : bool, optionalΒΆ

Whether to perform local optimization on the input +structure using OpenBabel; defaults to False.

+
+
**kwargsΒΆ

Keyword arguments:

+
    +
  1. working_dir.

  2. +
  3. db.

  4. +
  5. str_type (format of string if operation_type = get_from_str, +e.g. smi or any other format supported by OpenBabel).

  6. +
  7. force_field (force field to use for local optimization if +local_opt is True): gaff, ghemical, mmff94, mmff94s, +and uff.

  8. +
  9. steps (number of steps for local optimization if local_opt is True).

  10. +
  11. charge.

  12. +
  13. abbreviation (abbreviation to be used for the molecule when +downloading it from the PubChem database; defaults to mol).

  14. +
+

+
+
+
+
Returns:ΒΆ
+

pymatgen Molecule object.

+
+
Return type:ΒΆ
+

Molecule

+
+
+
+ +

mispr.gaussian.utilities.rdkit moduleΒΆ

+

Define functions for processing rdkit molecules.

+
+
+mispr.gaussian.utilities.rdkit.calc_energy(rdkit_mol, maxIters=200)[source]ΒΆ
+

Perform local optimization on rdkit Mol object and calculates its energy using UFF.

+
+
Parameters:ΒΆ
+
+
rdkit_mol : MolΒΆ

RDKit Mol object.

+
+
maxIters : int, optionalΒΆ

Maximum number of iterations to perform.

+
+
+
+
Returns:ΒΆ
+

Energy of the molecule.

+
+
Return type:ΒΆ
+

float

+
+
+
+ +
+
+mispr.gaussian.utilities.rdkit.draw_rdkit_mol(rdkit_mol, filename='mol.png', working_dir=None)[source]ΒΆ
+

Draw the 2D structure of a molecule and saves it to a file.

+
+
Parameters:ΒΆ
+
+
rdkit_mol : MolΒΆ

RDKit Mol object.

+
+
filename : str, optionalΒΆ

Name of the file to save the image to; defaults to +β€œmol.png”.

+
+
working_dir : str, optionalΒΆ

Directory to save the image to; defaults to +current working directory.

+
+
+
+
+
+ +
+
+mispr.gaussian.utilities.rdkit.draw_rdkit_mol_with_highlighted_bonds(rdkit_mol, bonds, filename='mol.png', colors=None, working_dir=None)[source]ΒΆ
+

Draw the 2D structure of a molecule and highlights the bonds specified by the user.

+
+
Parameters:ΒΆ
+
+
rdkit_mol : MolΒΆ

RDKit Mol object.

+
+
bonds : listΒΆ

List of tuples of indexes of atoms forming a bond to highlight; +e.g. [(3, 11), (5, 13)] to highlight the bonds between sites 3 and 11 and +sites 5 and 13.

+
+
filename : str, optionalΒΆ

Name of the file to save the image to; defaults to +β€œmol.png”.

+
+
colors : list, optionalΒΆ

List of colors to use for highlighting the bonds; +colors should be provided in rgb format, e.g. (0.0, 0.0, 0.0) for black; +if not provided or number of colors provided is less than number of bonds to +highlight, will randomly generate colors.

+
+
working_dir : str, optionalΒΆ

Directory to save the image to; defaults to +current working directory.

+
+
+
+
+
+ +
+
+mispr.gaussian.utilities.rdkit.get_rdkit_mol(mol, sanitize=True, remove_h=False)[source]ΒΆ
+

Convert a pymatgen mol object to RDKit rdmol object. Uses RDKit to perform the +conversion <http://rdkit.org>. Accounts for aromaticity.

+
+
Parameters:ΒΆ
+
+
mol : MoleculeΒΆ

pymatgen Molecule object.

+
+
sanitize : bool, optionalΒΆ

Whether to sanitize the molecule.

+
+
remove_h : bool, optionalΒΆ

whether to remove hydrogens.

+
+
+
+
Returns:ΒΆ
+

RDKit Mol object.

+
+
Return type:ΒΆ
+

Mol

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.workflows.base.html b/html/mispr.gaussian.workflows.base.html new file mode 100644 index 00000000..26b5daa5 --- /dev/null +++ b/html/mispr.gaussian.workflows.base.html @@ -0,0 +1,1690 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows.base package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.gaussian.workflows.base packageΒΆ

+

SubmodulesΒΆ

+

mispr.gaussian.workflows.base.bde moduleΒΆ

+

Define the bond dissociation energy workflow.

+
+
+mispr.gaussian.workflows.base.bde.get_bde(mol_operation_type, mol, ref_charge=0, fragment_charges=None, bonds=None, open_rings=False, db=None, name='bde_calculation', working_dir=None, opt_gaussian_inputs=None, freq_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, cart_coords=True, oxidation_states=None, skips=False, visualize=True, **kwargs)[source]ΒΆ
+

Define a dynamic workflow for calculating the bond dissociation energy.

+
    +
  • Firework 1: Optimize the principle molecule.

  • +
  • Firework 2: Run a frequency analysis.

  • +
  • Firework 3: Break the bonds in the molecule, find all unique fragments, and +generate new optimization and frequency fireworks for each fragment.

  • +
  • Firework N: Run a BDE calculation for each fragment and create a summary BDE +document/json file.

  • +
+
+

Note

+

Fireworks 1 and 2 are only present if user does not request to skip them.

+
+
+

Note

+

Charges on the fragments in this workflow are assigned as (following the method +in the BDE analysis module in pymatgen):

+
    +
  1. Neutral molecule: [(0, 0), (1, -1), (-1, 1)]

  2. +
  3. Molecule with charge -N: [(-N, 0), (-N+1, -N+2), (-N+2, -N+1), (0, -N)]

  4. +
  5. Molecule with charge +N: [(N, 0), (N-1, N-2), (N-2, N-1), (0, N)]

  6. +
+
+
+

Note

+

If multiple bonds are being broken but one fragment results in an error, +the workflow will proceed normally and the final document will include all bonds +except for the one involving the failed fragment.

+
+
+
Parameters:ΒΆ
+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
ref_charge : int, optionalΒΆ

Charge on the principle molecule. Defaults to 0.

+
+
fragment_charges : list, optionalΒΆ

List of additional charges to consider on +the fragments besides the default ones. If ref_charge is -2, by default +all fragments will be calculated with a charge of 0, -1, and -2. If the +user provides fragment_charges is [-3], -3 and 1 will be additionally +calculated. If the user provides fragment_charges is [-2], this will not +cause any change since they are already calculated by the workflow; +defaults to None.

+
+
bonds : list, optionalΒΆ

List of tuples of the bonds to break; e.g. +[(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 +and between atoms 1 and 2; if none is specified, will attempt to break all +bonds. Defaults to None.

+
+
open_rings : bool, optionalΒΆ

If True, will open rings encountered during +fragmentation using OpenBabel’s local opt.. Defaults to False.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€œbde_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created. Defaults to the current +working directory.

+
+
opt_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the optimization step; e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the frequency step; default parameters will be used if not specified.

+
+
solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters corresponding +to the implicit solvent model to be used in the ESP calculations, if any; +e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_gaussian_inputs). Defaults to None.

+

+
+
solvent_properties : dict, optionalΒΆ

Additional input parameters to be used in +the ESP calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}. Defaults to None.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True,otherwise uses z-matrix. Defaults to True.

+
+
oxidation_states : dict, optionalΒΆ

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the molecule; e.g.: +{β€œLi”:1, β€œO”:-2}. Defaults to None.

+
+
skips : list, optionalΒΆ

List of jobs to skip; e.g.: [β€œopt”, β€œfreq”]; only +applicable to the principle molecule. Defaults to None.

+
+
visualize : bool, optionalΒΆ

If True, will generate a summary plot of the +2D structure of the principle molecule with broken bonds highlighted in +color, along with a bar plot of the corresponding BDEs; requires RDKit to +be installed for bond highlighting; if RDKit is not found, will throw a +warning and proceed normally.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

mispr.gaussian.workflows.base.binding_energy moduleΒΆ

+

Define the binding energy workflow.

+
+
+mispr.gaussian.workflows.base.binding_energy.get_binding_energies(mol_operation_type, mol, index, bond_order=1, db=None, name='binding_energy_calculation', working_dir=None, opt_gaussian_inputs=None, freq_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, cart_coords=True, oxidation_states=None, skips=None, **kwargs)[source]ΒΆ
+

Define a workflow for calculating the binding energy between two molecules.

+
    +
  • Fireworks 1 & 2: Optimize the two molecules in parallel.

  • +
  • Firework 3 & 4: Run a frequency calculation on each molecule.

  • +
  • Firework 5: Link the two optimized molecules at a binding site and optimize +the geometry of the generated complex.

  • +
  • Firework 6: Run a frequency calculation on the optimized complex.

  • +
  • Firework 7: Calculate the binding energy of the complex and create BE +document/json file.

  • +
+
+
Parameters:ΒΆ
+
+
mol_operation_type : listΒΆ

List of strings of the type of molecule operations. +See process_mol defined in Defines the binding energy +workflow.mispr/gaussian/utilities/mol.py for supported operations; e.g. +[β€œget_from_mol”, β€œget_from_file”] to get the first molecule from a +Molecule object and the second molecule from a file.

+
+
mol : listΒΆ

List of the source of the two molecules to be processed. Should +match the order in mol_operation_type; e.g. if mol_operation_type is +[β€œget_from_mol”, β€œget_from_file”], mol should be +[Molecule, path to molecule file].

+
+
index : listΒΆ

List of indices of the two sites in the molecules at which they +are expected to bind; order should match that in mol_operation_type +and mol.

+
+
bond_order : int, optionalΒΆ

Bond order to calculate the bond length between the +two sites. Defaults to 1.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

name of the workflow; defaults to +β€œbinding_energy_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created. Defaults to the current +working directory.

+
+
opt_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the optimization step; e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the frequency step; default parameters will be used if not specified.

+
+
solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters corresponding +to the implicit solvent model to be used in the ESP calculations, if any; +e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_gaussian_inputs, etc.). Defaults to None.

+

+
+
solvent_properties : dict, optionalΒΆ

Additional input parameters to be used in +the ESP calculations and relevant to the solvent model, if any; for example, +{β€œEPS”:12}. Defaults to None.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True, otherwise uses z-matrix. Defaults to True.

+
+
oxidation_states : dict, optionalΒΆ

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the molecule; for +example: {β€œLi”:1, β€œO”:-2}. Defaults to None.

+
+
skips : list, optionalΒΆ

List of lists of jobs to skip for each molecule; e.g.: +[[β€œopt”, β€œfreq”], [β€œopt”]]; order should be consistent with that in +mol_operation_type and mol. Defaults to None.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

mispr.gaussian.workflows.base.core moduleΒΆ

+

Define a list of common fireworks used in Gaussian workflows.

+
+
+exception mispr.gaussian.workflows.base.core.GoutTypeError(msg=None)[source]ΒΆ
+

Bases: Exception

+

Exception that is thrown when no Gaussian output is provided.

+
+ +
+
+mispr.gaussian.workflows.base.core.common_fw(mol_operation_type, mol, working_dir, opt_gaussian_inputs, freq_gaussian_inputs, cart_coords, oxidation_states, gout_key=None, db=None, process_mol_func=True, mol_name=None, dir_head=None, skips=None, check_result=None, **kwargs)[source]ΒΆ
+

Define a list of Fireworks commonly used in Gaussian workflows.

+
    +
  • Firework 1: Optimize the molecule.

  • +
  • Firework 2: Run a frequency analysis.

  • +
+
+
Parameters:ΒΆ
+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
working_dir : strΒΆ

Path of the working directory where any required input files +can be found and output will be created.

+
+
opt_gaussian_inputs : dictΒΆ

Dictionary of Gaussian input parameters for the +optimization step.

+
+
freq_gaussian_inputs : dictΒΆ

Dictionary of Gaussian input parameters for the +frequency step.

+
+
cart_coords : boolΒΆ

Whether to use cartesian coordinates in writing Gaussian +input files.

+
+
oxidation_states : dictΒΆ

Dictionary of oxidation states that can be used in +setting the charge and spin multiplicity of the molecule; e.g.: +{β€œLi”:1, β€œO”:-2}.

+
+
gout_key : str, optionalΒΆ

Unique key for the Gaussian output dict; used to +differentiate Gaussian output dictionaries generated in the same workflow; +if None is provided, the key will be set β€œmol”.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if None is provided, +attempts to get it from the configuration files.

+
+
process_mol_func : bool, optionalΒΆ

Whether to process the molecule; if True, +will use the molecular formula as the label. Defaults to True.

+
+
mol_name : str, optionalΒΆ

The name of the molecule; ignored if +process_mol_func is set to True.

+
+
dir_head : str, optionalΒΆ

The name of the head of the directory where the +workflow corresponding to the molecule will be run.

+
+
skips : list, optionalΒΆ

List of jobs to skip; e.g.: [β€œopt”, β€œfreq”]; defaults +to None.

+
+
check_result : list, optionalΒΆ

List of properties to check for in the output +file when skipping jobs; ensures that properties required by the workflow are +available via the molecule format provided as an input (e.g. Gaussian +output dictionary).

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the Fireworks and +Firetasks.

+
+
+
+
Returns:ΒΆ
+

+
Type varies based on the input mol and the

operations performed inside the function.

+
+
+

str: Molecule label. +list: List of Fireworks.

+

+
+
Return type:ΒΆ
+

Molecule, GaussianOutput, str, dict

+
+
+
+ +

mispr.gaussian.workflows.base.esp moduleΒΆ

+

Define the electrostatic partial charges workflow.

+
+
+mispr.gaussian.workflows.base.esp.get_esp_charges(mol_operation_type, mol, db=None, name='esp_charges_calculation', working_dir=None, opt_gaussian_inputs=None, freq_gaussian_inputs=None, esp_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, cart_coords=True, oxidation_states=None, skips=None, **kwargs)[source]ΒΆ
+

Define a workflow for calculating the electrostatic partial charges.

+
    +
  • Firework 1: Optimize the molecule.

  • +
  • Firework 2: Run a frequency analysis.

  • +
  • Firework 3: Run an ESP calculation.

  • +
  • Firework 4: Create ESP document/json file.

  • +
+
+
Parameters:ΒΆ
+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€œesp_charges_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created. Defaults to the current +working directory.

+
+
opt_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the optimization step; e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the frequency step; default parameters will be used if not specified.

+
+
esp_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the ESP step; default parameters will be used if not specified.

+
+
solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters corresponding +to the implicit solvent model to be used in the ESP calculations, if any; +e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_gaussian_inputs, etc.). Defaults to None.

+

+
+
solvent_properties : dict, optionalΒΆ

Additional input parameters to be used in +the ESP calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}. Defaults to None.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True, otherwise uses z-matrix. Defaults to True.

+
+
oxidation_states : dict, optionalΒΆ

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the molecule; e.g.: +{β€œLi”:1, β€œO”:-2}. Defaults to None.

+
+
skips : list, optionalΒΆ

List of jobs to skip; e.g.: [β€œopt”, β€œfreq”]; defaults +to None.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow.

+
+
+
+
Returns:ΒΆ
+

Workflow +str: Label of the molecule (e.g. β€œH2O”, β€œwater”, etc.).

+
+
+
+ +

mispr.gaussian.workflows.base.ip_ea moduleΒΆ

+

Define the redox potentials workflow.

+
+
+class mispr.gaussian.workflows.base.ip_ea.Node(state: str, phase: str, num_electrons: int, mol_operation_type=None, mol=None, skips=None, check_result=None, parent: Node | None = None, ref_charge=None, branch_cation_from_anion: bool = False, h_index: list | None = None)[source]ΒΆ
+

Bases: object

+

Generate the fireworks corresponding to different molecule states in the IP/EA +workflow. Each molecule state corresponds to a node in the tree. The node is a leaf +if it is the last node in the tree, otherwise it is a branch. Not meant to be +instantiated directly.

+
+
Parameters:ΒΆ
+
+
state : strΒΆ

Current state of the molecule: cation or anion.

+
+
phase : strΒΆ

Current phase of the molecule: gas or solution.

+
+
num_electrons : intΒΆ

Number of electrons to transfer.

+
+
mol_operation_type : str, optionalΒΆ

Type of molecule operation; required +for the parent node, i.e. initial molecule state, but not for the child +nodes.

+
+
mol : Molecule, GaussianOutput, str, dict, optionalΒΆ

Molecule to be +processed; required for the parent node, i.e. initial molecule state, +but not for the child nodes since these are generated from the parent +node.

+
+
skips : list, optionalΒΆ

List of jobs to skip; only relevant to the parent +node, i.e. initial molecule state. Defaults to None.

+
+
check_result : list, optionalΒΆ

List of properties to check for in the +output file; only relevant when skipping jobs at the parent node;

+
+

currently checks for β€œfinal_energy” and β€œGibbs Free Energy”, since +these are used in calculating the redox potential.

+
+

+
+
parent : str, optionalΒΆ

Parent node of the current node; None if the node +corresponds to the initial molecule state.

+
+
ref_charge : int, optionalΒΆ

The initial charge on the molecule; only +relevant to the parent node.

+
+
branch_cation_from_anion : bool, optionalΒΆ

Whether to add a hydrogen atom +at the current node; relevant for PCET calculations.

+
+
h_index : int, optionalΒΆ

The site index in the molecule at which to attach +the hydrogen atoms in the PCET calculations.

+
+
+
+
+
+
+branch(branching_states, branching_phases, num_of_electrons, branch_cation_from_anion, h_index, vertical)[source]ΒΆ
+

Generate the children nodes of the current node in the tree representing the +IP/EA workflow.

+
+ +
+
+create_fireworks(opt_gaussian_inputs, freq_gaussian_inputs, solvent_gaussian_inputs, solvent_properties, working_dir, db, cart_coords, branch_cation_from_anion, **kwargs)[source]ΒΆ
+

Generate the optimization and/or frequency fireworks corresponding to the +current node.

+
+ +
+ +
+
+mispr.gaussian.workflows.base.ip_ea.get_ip_ea(mol_operation_type, mol, ref_charge, single_step=False, vertical=False, pcet=False, h_index=None, num_electrons=1, opt_gaussian_inputs=None, freq_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, states=None, phases=None, electrode_potentials=None, gibbs_elec=-0.001378786, gibbs_h=-0.41816, db=None, name='ip_ea_calculation', working_dir=None, cart_coords=True, ref_skips=None, **kwargs)[source]ΒΆ
+

Define a workflow for calculating the ionization potential (IP) and electron affinity +(EA) in eV. Supports multiple methods for calculating redox potentials in gas +and/or solution:

+
    +
  • Direct electron transfer

  • +
  • Vertical calculation of IP and EA

  • +
  • Adiabatic IP/EA

  • +
  • Sequential PCET

  • +
+

Uses a tree structure to dynamically define the dependencies of the fireworks. The +structure of the tree varies based on the inputs to the workflow.

+
+
Parameters:ΒΆ
+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
ref_charge : intΒΆ

The initial charge on the molecule.

+
+
single_step : bool, optionalΒΆ

Whether to run the electron transfer in a single +or multiple steps; e.g. if num_electrons is set to 2 and single_step +is False, the workflow will run the electron transfer in two steps; +defaults to False.

+
+
vertical : bool, optionalΒΆ

Whether to run the vertical IP/EA calculations, +in which optimization is performed only at the reference state at each +phase specified, thereby skipping the optimization step at the charge states; +defaults to False.

+
+
pcet : bool, optionalΒΆ

Whether to run sequential proton-coupled electron +transfer calculations; number of hydrogen transfer steps is assumed to be +equal to the number of electron transfers. Defaults to False.

+
+
h_index : int, optionalΒΆ

The site index in the molecule at which to attach the +hydrogen atoms in the PCET calculations. Defaults to None.

+
+
num_electrons : int, optionalΒΆ

The number of electrons to be transferred; +defaults to 1.

+
+
opt_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the optimization step; e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the frequency step; default parameters will be used if not specified.

+
+
solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters corresponding +to the implicit solvent model to be used in the redox potential calculations, +if any; e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_gaussian_inputs). Defaults to None.

+

+
+
solvent_properties : dict, optionalΒΆ

Additional input parameters to be used in +the ESP calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}. Defaults to None.

+
+
states : list, optionalΒΆ

List of states to be calculated; e.g. [β€œcation”] for +oxidation, [β€œanion”] for reduction, or [β€œcation”, β€œanion”] for oxidation +and reduction calculations; runs both if None is specified.

+
+
phases : list, optionalΒΆ

List of phases to be calculated; e.g. [β€œsolution”] for +liquid phase, [β€œgas”] for gas phase, or [β€œgas”, β€œsolution”] for the full +thermodynamic cycle; runs both if None is specified.

+
+
electrode_potentials : dict, optionalΒΆ

Dictionary of electrode potentials to be +used in converting the absolute oxidation and reduction potentials to +commonly used potential scales; e.g.:

+
{
+ lithium": {
+            "potential": 1.40,
+            "ref": bibtex_parser("li_pot.bib", data_dir),
+        }
+}
+
+
+

Uses hydrogen, magnesium, and lithium if None is specified; overwrites the +existing values if any of these are specified; if different potential scales +are specified, computes the potential relative to the three default scales +as well as the new ones specified.

+

+
+
gibbs_elec : float, optionalΒΆ

The electron gibbs free energy in Hartree; +defaults to -0.001378786.

+
+
gibbs_h : float, optionalΒΆ

The hydrogen gibbs free energy in Hartree; +defaults to -0.41816.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€œip_ea_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created. Defaults to the current +working directory.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True, otherwise uses z-matrix. Defaults to True.

+
+
ref_skips : list, optionalΒΆ

List of jobs to skip; e.g.: [β€œopt”, β€œfreq”]; only +applies to the molecule in the reference state. Defaults to None.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

mispr.gaussian.workflows.base.nmr moduleΒΆ

+

Define the nuclear magnetic resonance workflow.

+
+
+mispr.gaussian.workflows.base.nmr.get_nmr_tensors(mol_operation_type, mol, db=None, name='nmr_tensor_calculation', working_dir=None, opt_gaussian_inputs=None, freq_gaussian_inputs=None, nmr_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, cart_coords=True, oxidation_states=None, skips=None, **kwargs)[source]ΒΆ
+

Define a workflow for calculating the nuclear magnetic resonance tensors.

+
    +
  • Firework 1: Optimize the molecule.

  • +
  • Firework 2: Calculate the frequencies.

  • +
  • Firework 3: Calculate the NMR tensors.

  • +
  • Firework 4: Create NMR document/json file.

  • +
+
+
Parameters:ΒΆ
+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€œnmr_tensor_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created. Defaults to the current +working directory.

+
+
opt_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters; +e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the frequency step; default parameters will be used if not specified.

+
+
nmr_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the NMR step; default parameters will be used if not specified.

+
+
solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters corresponding +to the implicit solvent model to be used in the NMR calculations, if any; +e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_gaussian_inputs, etc.). Defaults to None.

+

+
+
solvent_properties : dict, optionalΒΆ

Additional input parameters to be used in +the NMR calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}. Defaults to None.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True, otherwise uses z-matrix. Defaults to True.

+
+
oxidation_states : dict, optionalΒΆ

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the molecule; e.g.: +{β€œLi”:1, β€œO”:-2}. Defaults to None.

+
+
skips : list, optionalΒΆ

List of jobs to skip; e.g.: [β€œopt”, β€œfreq”]; defaults +to None.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.gaussian.workflows.html b/html/mispr.gaussian.workflows.html new file mode 100644 index 00000000..3add27f9 --- /dev/null +++ b/html/mispr.gaussian.workflows.html @@ -0,0 +1,1087 @@ + + + + + + + + + + + + + + + + mispr.gaussian.workflows package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.html b/html/mispr.html new file mode 100644 index 00000000..b09020af --- /dev/null +++ b/html/mispr.html @@ -0,0 +1,1095 @@ + + + + + + + + + + + + + + + + mispr package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr packageΒΆ

+

SubpackagesΒΆ

+
+ +
+

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.hybrid.firetasks.html b/html/mispr.hybrid.firetasks.html new file mode 100644 index 00000000..7f2e728f --- /dev/null +++ b/html/mispr.hybrid.firetasks.html @@ -0,0 +1,952 @@ + + + + + + + + + + + + + + + + mispr.hybrid.firetasks package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.hybrid.firetasks packageΒΆ

+

SubmodulesΒΆ

+

mispr.hybrid.firetasks.nmr_from_md moduleΒΆ

+
+
+class mispr.hybrid.firetasks.nmr_from_md.NMRFromMD(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.hybrid.html b/html/mispr.hybrid.html new file mode 100644 index 00000000..b32a65da --- /dev/null +++ b/html/mispr.hybrid.html @@ -0,0 +1,994 @@ + + + + + + + + + + + + + + + + mispr.hybrid package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.hybrid.workflows.html b/html/mispr.hybrid.workflows.html new file mode 100644 index 00000000..c0868b43 --- /dev/null +++ b/html/mispr.hybrid.workflows.html @@ -0,0 +1,1163 @@ + + + + + + + + + + + + + + + + mispr.hybrid.workflows package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.hybrid.workflows packageΒΆ

+

SubmodulesΒΆ

+

mispr.hybrid.workflows.core moduleΒΆ

+

Define the DFT-MD hybrid workflow.

+
+
+mispr.hybrid.workflows.core.run_hybrid_calcs(mol_operation_type, mol, mol_type, mol_data, box_data, ff_method=None, ff_params=None, mixture_type='number of molecules', db=None, name='hybrid_calculation', working_dir=None, opt_gaussian_inputs=None, freq_gaussian_inputs=None, esp_gaussian_inputs=None, solvent_gaussian_inputs=None, solvent_properties=None, cart_coords=True, oxidation_states=None, skips=None, box_data_type='cubic', data_file_name='data.mixture', analysis_list=None, analysis_settings=None, **kwargs)[source]ΒΆ
+
+ +

mispr.hybrid.workflows.nmr moduleΒΆ

+

Define the DFT-MD workflow that extracts solvation structures and computes their +nuclear magnetic resonances.

+
+
+mispr.hybrid.workflows.nmr.get_solvation_structures_nmr(mol_operation_type, mol, mol_type, mol_data, box_data, ff_method=None, ff_params=None, mixture_type='number of molecules', db=None, name='hybrid_calculation', working_dir=None, opt_esp_gaussian_inputs=None, freq_esp_gaussian_inputs=None, esp_gaussian_inputs=None, opt_nmr_gaussian_inputs=None, freq_nmr_gaussian_inputs=None, nmr_gaussian_inputs=None, esp_solvent_gaussian_inputs=None, esp_solvent_properties=None, nmr_solvent_gaussian_inputs=None, nmr_solvent_properties=None, cart_coords=True, oxidation_states=None, skips=None, box_data_type='cubic', data_file_name='data.mixture', analysis_list=None, analysis_settings=None, **kwargs)[source]ΒΆ
+

Return a workflow to run hybrid DFT/MD calculations, extract categorize atomic +clusters around a particle of interest, and run the NMR calculations for the +clusters that have the highest frequency of occurrence in solution.

+
+
Parameters:ΒΆ
+
+
mol_operation_type : list of strΒΆ

Operation to perform for each molecule +composing the liquid solution in order to process the input structure +format. Length should correspond to the number of molecules/species +composing the liquid solution. Supported commands:

+
    +
  1. get_from_mol: If the input is a pymatgen Molecule object.

  2. +
  3. get_from_file: If the input is any file format supported by Openabel +and pymatgen.

  4. +
  5. get_from_gout_file: If the input is a Gaussian output file.

  6. +
  7. get_from_str: If the input is a string.

  8. +
  9. get_from_mol_db: If the input is an InChI representation of the +molecule to be used to query the database.

  10. +
  11. get_from_gout: If the input is a pymatgen GaussianOutput object.

  12. +
  13. get_from_run_dict: If the input is a GaussianOutput dictionary.

  14. +
  15. get_from_run_id: If the input is a MongoDB document ID to be used to +query the database.

  16. +
  17. get_from_run_query: If the input is a dictionary with criteria to +search the database: e.g.

    +
    {'inchi': inchi,
    + 'type': type,
    + 'functional': func, ...}
    +
    +
    +
  18. +
  19. get_from_pubchem: If the input is a common name for the molecule +to be used in searching the PubChem database.

  20. +
  21. derive_molecule: Used for deriving a molecule by attaching a +functional group at a site and the corresponding mol input should be a +dictionary, e.g.

    +
    {'operation_type': <mol_operation_type for the base structure>,
    + 'mol': <base_mol>,
    + 'func_grp': func_group_name, ...}
    +
    +
    +
  22. +
  23. link_molecules: Used for linking two structures by forming a bond +at specific sites and the corresponding mol input should be a dictionary, +e.g.

    +
    {'operation_type': ['get_from_file', 'get_from_mol_db'],
    + 'mol': ['mol1.xyz', 'mol_inchi'],
    + 'index': [3, 5],
    + 'bond_order': 1}
    +
    +
    +
  24. +
+

+
+
mol : listΒΆ

Sources of structures making up the liquid solution, e.g. file path +if mol_operation_type is specified as β€œget_from_file”, InChI string if +mol_operation_type is specified as β€œget_from_mol_db”, etc.

+
+

Important

+

Order should match that in mol_operation_type.

+
+

+
+
mol_type : list of strΒΆ

Type of each structure composing the liquid solution. +Supported types: β€œSolvents”, β€œSolutes”. Used for calculating the number of +molecules of each type if this information is not provided.

+
+
mol_data : list of int or list of dictΒΆ

Format depends on mixture_type +input. If mixture_type is β€œnumber of molecules”, mol_data should be +a list of the number of molecules of each type. If mixture_type is +β€œconcentration”, mol_data should be a list of dict, where each +dictionary should follow the format:

+
{'Initial Molarity': molarity_i,
+ 'Final Molarity': molarity_f,
+ 'Density': density,
+ 'Molar Weight': molar_weight
+}
+
+
+

+
+
box_data : float, int, list (3,2), array (3,2), or LammpsBoxΒΆ

Definitions for +box size. See box_data_type for info how to define this parameter.

+
+
ff_method : list of str, optionalΒΆ

Operation to perform for each molecule +composing the liquid solution in order to process the force field parameters. +Can be β€œget_from_esp”, β€œget_from_prmtop”, β€œget_from_dict”, β€œget_from_opls”. +Defaults to β€œget_from_esp” for all molecules.

+
+
ff_params : list of str or dict, optionalΒΆ

Sources of the force field parameters +for each molecule type; type depends on what is specified in the +ff_method input; if β€œget_from_esp” is used, the corresponding +ff_param should be an empty dictionary since the path to the ESP file is +automatically detected from the ESP calculations that is performed at the +beginning of the workflow; if β€œget_from_prmtop” is used, the corresponding +ff_param should be the path to the prmtop file; if β€œget_from_dict” is +used, the corresponding ff_param should be a dictionary, e.g.:

+
{
+    "Labels": ["mg"],
+    "Masses": OrderedDict({"mg": 24.305}),
+    "Nonbond": [[0.8947000005260684, 1.412252647723565]],
+    "Bonds": [],
+    "Angles": [],
+    "Dihedrals": [],
+    "Impropers": [],
+    "Improper Topologies": None,
+    "Charges": np.asarray([2.0]),
+}
+
+
+

If β€œget_from_opls” is used, the corresponding ff_param should be the +path to the molecule PDB file.

+

+
+
mixture_type : str, optionalΒΆ

β€œconcentration” or β€œnumber of molecules”; +defaults to β€œnumber of molecules”.

+
+
db : str or dict, optionalΒΆ

Database credentials; could be provided as the path +to the β€œdb.json” file or in the form of a dictionary; if none is provided, +attempts to get it from the configuration files.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€œhybrid_calculation”.

+
+
working_dir : str, optionalΒΆ

Path of the working directory where any required +input files can be found and output will be created.

+
+
opt_esp_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input +parameters for the optimization step of the ESP workflow; e.g.:

+
{
+    "functional": "B3LYP",
+    "basis_set": "6-31G(d)",
+    "route_parameters": {"Opt": None},
+    "link0_parameters": {
+        "%chk": "checkpoint.chk",
+        "%mem": "45GB",
+        "%NProcShared": "24"}
+}
+
+
+

The above default parameters will be used if not specified.

+

+
+
freq_esp_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input +parameters for the frequency step of the ESP workflow; default parameters +will be used if not specified.

+
+
esp_gaussian_inputs : dict, optionalΒΆ

Sictionary of Gaussian input parameters +for the ESP step of the ESP workflow; default parameters will be used if not +specified.

+
+
opt_nmr_gaussian_inputs : dict, optioanlΒΆ

Dictionary of Gaussian input +parameters for the optimization step of the NMR workflow; default parameters +will be used if not specified.

+
+
freq_nmr_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input +parameters for the frequency step of the NMR workflow; default parameters +will be used if not specified.

+
+
nmr_gaussian_inputs : dict, optionalΒΆ

Dictionary of Gaussian input parameters +for the NMR step of the NMR workflow; default parameters will be used if not +specified.

+
+
esp_solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters +corresponding to the implicit solvent model to be used in the ESP +calculations, if any; e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_gaussian_inputs, +freq_esp_gaussian_inputs, etc.).

+

+
+
esp_solvent_properties : dict, optionalΒΆ

Additional input parameters to be used +in the ESP calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}.

+
+
nmr_solvent_gaussian_inputs : str, optionalΒΆ

Gaussian input parameters +corresponding to the implicit solvent model to be used in the NMR +calculations, if any; e.g.:

+
"(Solvent=TetraHydroFuran)"
+
+
+

These parameters should only be specified here and not included in the main +gaussian_inputs dictionary for each job (i.e. opt_nmr_gaussian_inputs, +freq_nmr_gaussian_inputs, etc.).

+

+
+
nmr_solvent_properties : dict, optionalΒΆ

Additional input parameters to be used +in the NMR calculations and relevant to the solvent model, if any; e.g., +{β€œEPS”:12}.

+
+
cart_coords : bool, optionalΒΆ

Uses cartesian coordinates in writing Gaussian +input files if set to True, otherwise uses z-matrix. Defaults to True.

+
+
oxidation_states : dict, optionalΒΆ

Dictionary of oxidation states that can be +used in setting the charge and spin multiplicity of the clusters extracted +from MD simulations to be used in the NMR workflow.

+
+
skips : list of lists, optionalΒΆ

Type of DFT calculation to skip in the ESP +workflow for each molecule; e.g. [β€œopt”, β€œfreq”], [β€œopt”], [β€œfreq”], or [].

+
+
box_data_type : str, optionalΒΆ

Can be one of the following: β€œcubic”, +β€œrectangular”, or β€œLammpsBox”. If β€œcubic”, box_data must be a float or +int; if β€œrectangular”, box_data must be an array-like with size (3,2); +if β€œLammpsBox”, box_data must be a pymatgen.io.lammps.data.LammpsBox +object. Defaults to β€œcubic”.

+
+
data_file_name : str, optionalΒΆ

Name of the LAMMPS data file to create and use; +defaults to β€œdata.mixture”.

+
+
analysis_list : list of str, optionalΒΆ

Type of MD analysis to perform after the +MD simulations are finished; e.g.: [β€œdiffusion”, β€œrdf”, β€œcn”, β€œclusters”] +if user wants to perform diffusion, RDF, coordination number, and cluster +analysis.

+
+
analysis_settings : list of dict, optionalΒΆ

Settings of the MD analysis steps; +please refer to the mdproptools documentation for details of inputs used in +the analysis functions; order of settings should correspond to the order +used in analysis_list.

+
+
kwargs : keyword argumentsΒΆ

Additional kwargs to be passed to the workflow; e.g.: +lammps recipe and recipe_settings; the defaults for these inputs are +specified in the mispr/lammps/defaults.py.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.firetasks.html b/html/mispr.lammps.firetasks.html new file mode 100644 index 00000000..5609732e --- /dev/null +++ b/html/mispr.lammps.firetasks.html @@ -0,0 +1,2043 @@ + + + + + + + + + + + + + + + + mispr.lammps.firetasks package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps.firetasks packageΒΆ

+

SubmodulesΒΆ

+

mispr.lammps.firetasks.parse_outputs moduleΒΆ

+
+
+class mispr.lammps.firetasks.parse_outputs.CalcCN(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Calculate the coordination number (CN) of a system. The CN is calculated for each +atom type in the system and saved to a file. The CN can be calculated for atomic or +molecular systems.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
cn_settings : dict, optional

A dictionary containing the settings for the CN +calculation based on the calc_atomic_cn and calc_molecular_cn +functions. Refer to the mdproptools.structural.rdf_cn module for more +information.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.parse_outputs.CalcDiff(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Calculate the diffusion coefficient of a system using the mean squared displacement +(MSD) method. The MSD is either calculated from the trajectory dump files or read +from the log file. The diffusion coefficient is then calculated from the MSD using +the Einstein relation.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
diff_settings : dict, optional

A dictionary containing the settings for the +diffusion calculation based on the Diffusion object. Refer to the +mdproptools.dynamical.diffusion module for more information. The +dictionary might contain the following keys:

+
    +
  • timestep (float): The timestep used in the simulation.

  • +
  • units (str): The unit type used in the LAMMPS simulations.

  • +
  • msd_method (str): The method used to calculate the MSD. Supported methods +are β€œfrom_dump” and β€œfrom_log”.

  • +
  • num_mols (list, optional): A list containing the number of molecules of +each type in the system. Required if the msd_method is β€œfrom_dump”.

  • +
  • num_atoms_per_mol (list, optional): A list containing the number of atoms +in each molecule. Required if the msd_method is β€œfrom_dump”.

  • +
  • mass (list, optional): A list containing the masses of each LAMMPS atom +type in the system. Required if the msd_method is β€œfrom_dump”.

  • +
  • file_pattern (str, optional): The pattern used to match the dump files. +Defaults to β€œdump.nvt.*.dump” if calculating from dump and β€œlog.lammps*” +if calculating from log.

  • +
  • avg_interval (bool, optional): Whether to calculate the MSD for individual +particles or not. If False, the MSD will be averaged for each particle +type. Defaults to False. Only used if the msd_method is β€œfrom_dump”.

  • +
  • diff_dist (bool, optional): Whether to calculate the diffusion distribution. +Defaults to False. Only used if the msd_method is β€œfrom_dump”.

  • +
  • outputs_dir (str, optional): Path to the directory containing the dump +files. Defaults to β€œworking_dir/../../nvt”.

  • +
+

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.parse_outputs.ExtractClusters(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Extract atomic clusters from a trajectory file. The clusters are extracted based +on the cutoff radius and saved to separate files. The clusters can be extracted +from the full trajectory or a single frame.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
cluster_settings : dict, optional

A dictionary containing the settings for the +cluster extraction based on the get_clusters and +get_unique_configurations functions. Refer to the +mdproptools.structural.cluster_analysis module for more information.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.parse_outputs.GetRDF(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Calculate the radial distribution function (RDF) of a system. The RDF is calculated +for each atom type in the system and saved to a file. The RDF can be calculated for +atomic or molecular systems.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
rdf_settings : dict, optional

A dictionary containing the settings for the +RDF calculation based on the calc_atomic_rdf and calc_molecular_rdf +functions. Refer to the mdproptools.structural.rdf_cn module for more +information.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.parse_outputs.ProcessAnalysis(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Process the analysis calculations and saves the results to the database and/or a file.

+
+
Parameters:ΒΆ
+
+
analysis_list : list

A list of the analysis calculations to process. Supported +analysis calculations are β€œdiffusion”, β€œrdf”, β€œcn”, and β€œclusters”.

+
+
db : str, optional

The connection information of the database to save the +analysis results to. If not provided, the connection information will be +read from the db.json file.

+
+
save_analysis_to_db : bool, optional

Whether to save the analysis results to +the database. Defaults to False.

+
+
save_analysis_to_file : bool, optional

Whether to save the analysis results to +a file in the working_dir. Defaults to True.

+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.parse_outputs.ProcessPrmtop(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Parse the prmtop file to extract force field parameters and saves them to a file +and/or database in the format required by the LammpsDataWrapper class in the +pymatgen.io.lammps.data module.

+
+
Parameters:ΒΆ
+
+
molecule : Molecule, optional

A pymatgen Molecule object of the molecule. +The order of the atoms in the Molecule object should match the order +of the atoms used when generating the prmtop file. If not provided, the +molecule will be read from the previous calculation in the fw_spec.

+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
db : str, optional

The connection information of the database to save the +force field parameters to. If not provided, the connection information will +be read from the db.json file.

+
+
prmtop_path : str, optional

Path to the prmtop file. If not provided, will try +to get the path based on the prmtop_filename and prmtop_dir.

+
+
prmtop_filename : str, optional

Name of the prmtop file. Only read if the +prmtop_path is not provided.

+
+
prmtop_dir : str, optional

Path to the directory containing the prmtop file. +Only read if the prmtop_path is not provided. Defaults to working_dir.

+
+
unique_molecule_name : str, optional

A unique name for the molecule. If not +provided, the formula of the molecule will be used.

+
+
system_force_field_dict : dict, optional

A dictionary containing the force +field parameters for the system. Will be used as input for +LammpsDataWrapper. Only read if this dict is not already in the +fw_spec. Will be saved to the fw_spec after processing the prmtop +file. Defaults to an empty dict.

+
+
doi : str, optional

Digital Object Identifier for the force field used. +Defaults to the GAFF DOI.

+
+
save_ff_to_db : bool, optional

Whether to save the force field parameters to +the database. Defaults to False.

+
+
save_ff_to_file : bool, optional

Whether to save the force field parameters to +a file in the working_dir. Defaults to True.

+
+
ff_filename : str, optional

Name of the file to save the force field parameters +to. Defaults to β€œff.json”.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.firetasks.run moduleΒΆ

+
+
+class mispr.lammps.firetasks.run.RunAntechamber(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run the Antechamber program. Intented to be used to generate the partial charges +for the molecule in a mol2 file from a Gaussian ESP file. Refer to the AmberTools +documentation for more information on this program: +https://ambermd.org/AmberTools.php.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

The directory to run Antechamber in. Defaults to +the current working directory.

+
+
input_filename_a : str, optional

The name of the input file. Defaults to +β€œmol.esp”.

+
+
input_file_type : str, optional

The type of the input file. Defaults to β€œgesp”.

+
+
output_filename_a : str, optional

The name of the output file. Defaults to +β€œmol.mol2”.

+
+
output_file_type : str, optional

The type of the output file. Defaults to β€œmol2”.

+
+
charge_method : str, optional

The method to calculate the partial charges. +Defaults to β€œresp”.

+
+
antechamber_cmd : str, optional

The command to run Antechamber. If not provided, +the command will be read from the β€œconfig.ini” file.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.run.RunLammpsDirect(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run a LAMMPS simulation from a single control file.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

The directory to run the simulation in. Defaults +to the current working directory. file.

+
+
control_filename : str, optional

Name of the LAMMPS control file. Defaults to +β€œcomplex.lammpsin”.

+
+
lammps_cmd : str, optional

The command to run LAMMPS. If not provided, the +command will attempt to read from the β€œconfig.ini” file.

+
+
net_ntasks : int, optional

The number of processors to run the simulation on. +If not provided, the number of processors will be read from the fw_spec +based on the number of nodes used and the number of tasks per node.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.run.RunLammpsFake(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run a fake LAMMPS simulation.

+
+
Parameters:ΒΆ
+
+
ref_dir : str

The directory containing the reference LAMMPS files.

+
+
working_dir : str, optional

The directory to run the fake simulation in. +Defaults to the current working directory.

+
+
control_filename : str, optional

The name of the LAMMPS control file. Defaults

+
+
"complex.lammpsin". : to

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.run.RunMaestro(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run the Maestro program using the MaestroRunner class in the +mispr.lammps.utilities.opls module to generate OPLS force field parameters for +a molecule. After generating the parameters, add these parameters to the spec. +Refer to the Maestro documentation for more information on this program: +https://www.schrodinger.com/maestro.

+
+
Parameters:ΒΆ
+
+
input_file : str

The path to the input file.

+
+
label : str, optional

The label for the molecule. Defaults to the molecule’s +formula.

+
+
molecule : Molecule, optional

The molecule to generate force field parameters +for. If not provided, the molecule will be read from the input file.

+
+
mae_cmd : str, optional

The command to run the structconvert utility program. +If not provided, the command will be read from the β€œconfig.ini” file.

+
+
ffld_cmd : str, optional

The command to run the ffld_server utility program. +If not provided, the command will be read from the β€œconfig.ini” file.

+
+
working_dir : str, optional

The directory to run Maestro in. Defaults to the +current working directory.

+
+
maestro_cleanup : bool, optional

Whether to clean up the Maestro files after +running. Defaults to False.

+
+
db : str, optional

The connection information of the database to save the force +field parameters to. If not provided, the connection information will be +read from the β€œdb.json” file.

+
+
save_ff_to_db : bool, optional

Whether to save the force field parameters to a +database. Defaults to False.

+
+
save_ff_to_file : bool, optional

Whether to save the force field parameters to +a file. Defaults to True.

+
+
ff_filename : str, optional

The name of the file to save the force field +parameters to. Defaults to β€œff.json”.

+
+
system_force_field_dict : dict, optional

A dictionary to store the force field +parameters for multiple molecules. This is only needed if this dictionary +is not already in the fw_spec. If this dict is not in the fw_spec or +provided by the user, an empty dict will be created.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.run.RunParmchk(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run the Parmchk program. Intended to be used to generate a frcmod file from a mol2 +file. Refer to the AmberTools documentation for more information on the Parmchk +program: https://ambermd.org/AmberTools.php.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

The directory to run Parmchk in. Defaults to the +current working directory.

+
+
input_filename_p : str, optional

The name of the input file. Defaults to +β€œmol.mol2”.

+
+
output_filename_p : str, optional

The name of the output file. Defaults to +β€œmol.frcmod”.

+
+
parmchk_cmd : str, optional

The command to run Parmchk. If not provided, the +command will be read from the β€œconfig.ini” file.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.run.RunTleap(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Run the Tleap program. Intended to be used to generate the GAFF parameters for a +single molecular species into a prmtop file from a mol2 file and a frcmod file. +Refer to the AmberTools documentation for more information on this program: +https://ambermd.org/AmberTools.php.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

The directory to run Tleap in. Defaults to the +current working directory.

+
+
script_filename : str, optional

The name of the script file. Defaults to +β€œtleap.in”.

+
+
tleap_cmd : str, optional

The command to run Tleap. If not provided, the +command will be read from the β€œconfig.ini” file.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.firetasks.write_inputs moduleΒΆ

+
+
+class mispr.lammps.firetasks.write_inputs.LabelFFDict(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Append molecule label to all atom labels in the force field dictionary. Ensures +that no two molecules can share the same atom labels provided that each molecule +has a unique label for the system.

+
+
Parameters:ΒΆ
+
+
mol : Molecule, optional

pymatgen Molecule object; if not provided, the

+
+
used. : prev_calc_molecule key from the fw_spec will be

+
+
unlabeled_dict : dict, optional

Dictionary containing the force field parameters +for the molecule; ignored if the ff_file is provided.

+
+
ff_file : str, optional

Path to the json file containing the force field +parameters for the molecule.

+
+
working_dir : str, optional

Path to the working directory. Defaults to current +working directory.

+
+
label : str, optional

Label for the molecule. Defaults to the molecular formula.

+
+
system_force_field_dict : dict, optional

Dictionary containing the force field +parameters for the system that is used as the input for LammpsDataWrapper +object; intended to be obtained from the spec; if present in the spec, +this will be ignored.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.write_inputs.LabelFFDictFromDB(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Append molecule label to all atom labels in a force field dictionary obtained from +the database. Ensures that no two molecules can share the same atom labels provided +that each molecule has a unique label for the system.

+
+
Parameters:ΒΆ
+
+
filter : dict

Dictionary containing the filter used to query the database.

+
+
working_dir : str, optional

Path to the working directory. Defaults to +current working directory.

+
+
db : dict or str, optional

Information for connecting to the database as +either a dictionary of credentials or a path to a json file containing the +credentials; if not provided, the database specified in the env will be used.

+
+
label : str, optional

Label for the molecule. Defaults to the molecular formula.

+
+
system_force_field_dict : dict, optional

Dictionary containing the force field +parameters for the system that is used as the input for LammpsDataWrapper +object; intended to be obtained from the spec; if present in the spec, this +will be ignored.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.write_inputs.WriteControlFile(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Write a LAMMPS control file based on a template file or string.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to working directory. Default is current +working directory.

+
+
db : str or dict, optional

Connection information for the calc database; If +save_runs_to_db is True, then a document will be stored in the +database. Default is None.

+
+
control_filename : str, optional

Name of control file to be written. Default is +β€œcomplex.lammpsin”.

+
+
template_filename : str, optional

Name of template control file to be used. +Is not used if template_str is provided. Can refer to a custom template +or a template name from the mispr/lammps/templates directory.

+
+
template_dir : str, optional

Path to directory containing template file. If the +template is from mispr/lammps/templates, then this is not needed.

+
+
template_str : str, optional

String containing template for control file.

+
+
control_settings : dict, optional

Dictionary of settings to be used in the +control file. If a mispr template is used, this dictionary will update the +corresponding control_settings dictionary in the mispr/lammps/defaults.py +file. Default is None.

+
+
save_runs_to_db : bool, optional

Whether to save the run info to the calc +database. Default is False.

+
+
save_runs_to_file : bool, optional

Whether to save the run info to a file in +the working directory. Default is True.

+
+
lammpsin_key : str, optional

Key in the fw_spec that corresponds with the +run_doc information. Default is β€œlammpsin”.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.write_inputs.WriteDataFile(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Write LAMMPS data file for a bulk system in the current working directory. User can +provide a LammpsData object, a LammpsDataWrapper object, or the inputs for +instantiating a LammpsDataWrapper object. See the LammpsData and +LammpsDataWrapper classes in the pymatgen.io.lammps.data module for more +information.

+
+
Parameters:ΒΆ
+
+
working_dir : str, optional

Path to the working directory. Defaults to the +current working directory.

+
+
data_filename : str, optional

Name of data file to be written. Defaults to +β€œcomplex.data”.

+
+
lammps_data : LammpsData, optional

The LammpsData object to be written as +the data file. Can be passed through the fw_spec or input by the user. +If both are provided, the one provided directly will be used.

+
+
lammps_data_wrapper : LammpsDataWrapper, optional

The wrapper for the +LammpsData object to be written as data file. Can be passed through +fw_spec or input by the user. If both are provided, the one provided +directly will be used. Will be ignored if lammps_data is provided.

+
+
system_force_field_dict : dict, optional

The force field parameters for the +system. Used as input for LammpsDataWrapper. Intended to be created by +the GetForceField task. Can be passed through fw_spec or input by +the user. If both are provided, will take the one provided in the fw_spec.

+
+
system_mixture_data : dict, optional

The information that will be used to +calculate the number of molecules of each type in the system. Used as input +for a LammpsDataWrapper object. Can be read from fw_spec or input +by the user; If both are provided, will use the one provided in the fw_spec.

+
+
system_box_data : float, int, list, ndarray, optional

Information about the +system box; the value of this arg is determined by the +system_box_data_type. Used as input for a LammpsDataWrapper object. +Can be passed through fw_spec or input by the user. If both are provided, +will take the one provided in the fw_spec.

+
+
system_box_data_type : str, optional

Determines the type for system_box_data. +Used as input for a LammpsDataWrapper object. Defaults to β€œcubic”.

+
+
position_seed : int, optional

Seed for randomizing the positions of atoms. +Indirectly used as input for packmol through LammpsDataWrapper. Defaults +to 150.

+
+
system_mixture_data_type : str, optional

Determines the content of +system_mixture_data. Used as input for a LammpsDataWrapper object. +Defaults to β€œconcentration”.

+
+
scale_charges : bool, optional

Whether to scale the partial charges of all +molecules that have a non-zero net charge in the system. Only used if +building a system from LammpsDataWrapper inputs.

+
+
charge_scaling_factor : float

Factor by which to scale charges in the system. +Only used if building a system from LammpsDataWrapper inputs and if +scale_charges is True.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +
+
+class mispr.lammps.firetasks.write_inputs.WriteTleapScript(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Write a tleap script for generating a prmtop and inpcrd file for a molecule. +Intended to be used to obtain the parameters from the GAFF force field.

+
+
Parameters:ΒΆ
+
+
working_dir : str

Path to the working directory. Defaults to current working +directory.

+
+
script_string : str

String containing the tleap script. If not provided, the +template_filename and template_dir must be provided.

+
+
template_filename : str

Name of the template file. Defaults to β€œgaff_tleap”.

+
+
template_dir : str

Path to the directory containing the template file. Defaults +to the mispr/lammps/templates/ directory.

+
+
tleap_settings : dict

Dictionary containing the settings for the tleap script. +Used to update the TLEAP_SETTINGS dict in +mispr/lammps/defaults.py file. Defaults to empty dict.

+
+
script_filename : str

Name of the tleap script file. Defaults to β€œtleap.in”.

+
+
+
+
+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.fireworks.html b/html/mispr.lammps.fireworks.html new file mode 100644 index 00000000..19949145 --- /dev/null +++ b/html/mispr.lammps.fireworks.html @@ -0,0 +1,1178 @@ + + + + + + + + + + + + + + + + mispr.lammps.fireworks package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps.fireworks packageΒΆ

+

SubmodulesΒΆ

+

mispr.lammps.fireworks.core moduleΒΆ

+
+
+class mispr.lammps.fireworks.core.GetFFDictFW(mol, mol_operation_type, data, operation_type='get_from_esp', label='', name='get_ff_dict', parents=None, working_dir=None, db=None, save_ff_to_db=False, save_ff_to_file=True, ff_filename='ff.json', tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Generate the ff parameters for a molecule.

+
+
Parameters:ΒΆ
+
+
mol : Molecule, GaussianOutput, str, dictΒΆ

Source of the molecule to be +processed. Should match the mol_operation_type.

+
+
mol_operation_type : strΒΆ

The type of molecule operation. See process_mol +defined in mispr/gaussian/utilities/mol.py for supported operations.

+
+
data : str, dictΒΆ

Data to be processed, e.g., path to the esp file if +operation_type is get_from_esp, path to the prmtop file if +operation_type is get_from_prmtop, etc.

+
+
operation_type : str, optionalΒΆ

The operation to perform on the data to read +or generate the force field parameters. Defaults to get_from_esp. +Supported commands:

+
    +
  1. get_from_esp: If the input is an ESP file.

  2. +
  3. get_from_prmtop: If the input is a prmtop file.

  4. +
  5. get_from_opls: If the input is a molecule file to be used to +generate opls ff parameters.

  6. +
  7. get_from_dict: If the input is a dictionary of force field +parameters. e.g.,

    +
    {
    +    "Molecule": pymatgen_molecule,
    +    "Labels": atom_labels,
    +    "Masses": atomtype_masses,
    +    "Nonbond": nonbond_params,
    +    "Bonds": bond_params,
    +    "Angles": angle_params,
    +    "Dihedrals": dihedral_params,
    +    "Impropers": improper_params,
    +    "Improper Topologies": improper_topologies,
    +    "Charges": charges
    + }
    +
    +
    +
  8. +
  9. ’get_from_file’: If the input is a json file of the force field +parameters.

  10. +
  11. ’get_from_db’: If the input is a filter for the database to search +for the force field parameters.

  12. +
+

+
+
label : str, optionalΒΆ

Label for the molecule. This should be unique for +each different molecular species in the system. Defaults to an empty +string. In this case, the label will be obtained based on the molecular +formula.

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to get_ff_dict.

+
+
parents : Firework or [Firework], optionalΒΆ

List of parent Fireworks that +this Firework depends on. Defaults to None.

+
+
working_dir : str, optionalΒΆ

Directory to run the Firework in. Defaults to +the current working directory.

+
+
db : str or dict, optionalΒΆ

Database credentials. Could be provided as the +path to the β€œdb.json” file or in the form of a dict. If none is provided, +attempts to read it from the configuration files to save the Firework to.

+
+
save_ff_to_db : bool, optionalΒΆ

Whether to save the force field to the +database. Defaults to False.

+
+
save_ff_to_file : bool, optionalΒΆ

Whether to save the force field to a file. +Defaults to True.

+
+
ff_filename : str, optionalΒΆ

Filename to save the force field to. Defaults +to β€œff.json”.

+
+
tag : strΒΆ

Tag for the Firework. The provided tag will be stored in the db +documents for easy retrieval. Defaults to β€œunknown”.

+
+
**kwargsΒΆ

Other kwargs that are passed to:

+
    +
  1. Firework.__init__

  2. +
  3. mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput

  4. +
  5. mispr.lammps.firetasks.run.RunAntechamber

  6. +
  7. mispr.lammps.firetasks.run.RunParmchk

  8. +
  9. mispr.lammps.firetasks.write_inputs.WriteTleapScript

  10. +
  11. mispr.lammps.firetasks.run.RunTleap

  12. +
  13. mispr.lammps.firetasks.parse_outputs.ProcessPrmtop

  14. +
  15. mispr.lammps.firetasks.run.RunMaestro

  16. +
  17. mispr.lammps.firetasks.write_inputs.LabelFFDict

  18. +
  19. mispr.lammps.firetasks.write_inputs.LabelFFDictFromDB

  20. +
+

+
+
+
+
+
+ +
+
+class mispr.lammps.fireworks.core.RunAnalysisFW(md_property, name='run_analysis', parents=None, working_dir=None, tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Run an analysis on a LAMMPS trajectory.

+
+
Parameters:ΒΆ
+
+
md_property : strΒΆ

The property to calculate. Supported properties:

+
    +
  1. ’diffusion’: Calculate the diffusion coefficient.

  2. +
  3. ’rdf’: Calculate the radial distribution function.

  4. +
+

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to β€œrun_analysis”.

+
+
parents : Firework or [Firework], optionalΒΆ

List of parent Fireworks that +this Firework depends on. Defaults to None.

+
+
working_dir : str, optionalΒΆ

Directory to run the Firework in. Defaults to +the current working directory.

+
+
tag : strΒΆ

Tag for the Firework. The provided tag will be stored in the db +documents for easy retrieval. Defaults to β€œunknown”.

+
+
**kwargsΒΆ

Other kwargs that are passed to:

+
    +
  1. Firework.__init__

  2. +
  3. mispr.lammps.firetasks.parse_outputs.CalcDiff

  4. +
  5. mispr.lammps.firetasks.parse_outputs.GetRDF

  6. +
  7. mispr.lammps.firetasks.parse_outputs.CalcDiff

  8. +
+

+
+
+
+
+
+ +
+
+class mispr.lammps.fireworks.core.RunLammpsFW(control_file=None, db=None, name='run_lammps', parents=None, working_dir=None, save_run_to_db=True, save_run_to_file=False, tag='unknown', **kwargs)[source]ΒΆ
+

Bases: Firework

+

Run a lammps simulation.

+
+
Parameters:ΒΆ
+
+
control_file : str, optionalΒΆ

Path to the control file. If +not provided, the control file will be generated. +Defaults to None.

+
+
db : str or dict, optionalΒΆ

Database credentials. Could be +provided as the path to the db.json file or in the form +of a dict. If none is provided, attempts to read it +from the configuration files to save the Firework to.

+
+
name : str, optionalΒΆ

Name of the Firework. Defaults to +β€œrun_lammps”.

+
+
parents : Firework or [Firework], optionalΒΆ

List of parent +Fireworks that this Firework depends on. Defaults to +None.

+
+
working_dir : str, optionalΒΆ

Directory to run the Firework +in. Defaults to the current working directory.

+
+
save_run_to_db : bool, optionalΒΆ

Whether to save the run to +the database. Defaults to True.

+
+
save_run_to_file : bool, optionalΒΆ

Whether to save the run +to a file. Defaults to False.

+
+
tag : strΒΆ

Tag for the Firework. The provided tag will be +stored in the db documents for easy retrieval. Defaults +to β€œunknown”.

+
+
**kwargsΒΆ

Other kwargs that are passed to:

+
    +
  1. Firework.__init__

  2. +
  3. mispr.lammps.firetasks.write_inputs.WriteControlFile

  4. +
  5. mispr.lammps.firetasks.run.RunLammpsDirect

  6. +
+

+
+
+
+
+
+ +
+
+mispr.lammps.fireworks.core.ambertools_tasks(**kwargs)[source]ΒΆ
+

Define a list of common tasks for generating GAFF parameters for a molecule. This is +a helper function for the GetFFDictFW Firework.

+
+
Parameters:ΒΆ
+
+
**kwargsΒΆ

other kwargs that are passed to:

+
    +
  1. mispr.lammps.firetasks.run.RunAntechamber

  2. +
  3. mispr.lammps.firetasks.run.RunParmchk

  4. +
  5. mispr.lammps.firetasks.write_inputs.WriteTleapScript

  6. +
  7. mispr.lammps.firetasks.run.RunTleap

  8. +
  9. mispr.lammps.firetasks.parse_outputs.ProcessPrmtop

  10. +
+

+
+
+
+
Returns:ΒΆ
+

List of Firetasks.

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.html b/html/mispr.lammps.html new file mode 100644 index 00000000..fc8b672d --- /dev/null +++ b/html/mispr.lammps.html @@ -0,0 +1,1323 @@ + + + + + + + + + + + + + + + + mispr.lammps package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps packageΒΆ

+

SubpackagesΒΆ

+
+ +
+

SubmodulesΒΆ

+

mispr.lammps.database moduleΒΆ

+
+
+class mispr.lammps.database.LammpsSysDb(host, port=None, name=None, username=None, password=None, uri_mode=False, **kwargs)[source]ΒΆ
+

Bases: object

+
+
+abstract build_indexes(indexes=None, background=True)[source]ΒΆ
+
+ +
+
+delete_force_field(smiles, method, doi=None)[source]ΒΆ
+
+ +
+
+classmethod from_db_file(db_file, admin=True)[source]ΒΆ
+
+ +
+
+insert_force_field(parameter_dict, method, doi=None, update_duplicates=False, **kwargs)[source]ΒΆ
+
+ +
+
+insert_run(lmp_run)[source]ΒΆ
+
+ +
+
+insert_system(sys_doc)[source]ΒΆ
+
+ +
+
+query_force_fields(query)[source]ΒΆ
+
+ +
+
+retrieve_force_field(smiles, method, doi=None)[source]ΒΆ
+
+ +
+
+retrieve_run(_id)[source]ΒΆ
+
+ +
+ +

mispr.lammps.defaults moduleΒΆ

+

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.tests.html b/html/mispr.lammps.tests.html new file mode 100644 index 00000000..23fc6bcd --- /dev/null +++ b/html/mispr.lammps.tests.html @@ -0,0 +1,1150 @@ + + + + + + + + + + + + + + + + mispr.lammps.tests package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps.tests packageΒΆ

+

SubmodulesΒΆ

+

mispr.lammps.tests.antechamber moduleΒΆ

+

mispr.lammps.tests.base_test moduleΒΆ

+
+
+class mispr.lammps.tests.base_test.PrintFW(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Firetask for confirming that modspec works as intended in ProcessPrmtop firetask

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.tests.control moduleΒΆ

+

mispr.lammps.tests.custom_data_workflow moduleΒΆ

+

mispr.lammps.tests.data moduleΒΆ

+
+
+class mispr.lammps.tests.data.PrintFW(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Firetask for confirming that modspec works as intended in ProcessPrmtop firetask

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.tests.electrolyte_wf moduleΒΆ

+

mispr.lammps.tests.esp_to_ff_dict_custom moduleΒΆ

+
+
+class mispr.lammps.tests.esp_to_ff_dict_custom.PrintFW(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Firetask for confirming that modspec works as intended in ProcessPrmtop firetask

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.tests.esp_to_ff_dict_function moduleΒΆ

+
+
+class mispr.lammps.tests.esp_to_ff_dict_function.PrintFW(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Firetask for confirming that modspec works as intended in ProcessPrmtop firetask

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.tests.liquid_wf_local moduleΒΆ

+

mispr.lammps.tests.parmchk moduleΒΆ

+

mispr.lammps.tests.prmtop moduleΒΆ

+
+
+class mispr.lammps.tests.prmtop.PrintFW(*args, **kwargs)[source]ΒΆ
+

Bases: FiretaskBase

+

Firetask for confirming that modspec works as intended in ProcessPrmtop firetask

+
+
+run_task(fw_spec)[source]ΒΆ
+

This method gets called when the Firetask is run. It can take in a +Firework spec, perform some task using that data, and then return an +output in the form of a FWAction.

+
+
Parameters:ΒΆ
+
+
fw_spec : dictΒΆ

A Firework spec. This comes from the master spec. +In addition, this spec contains a special β€œ_fw_env” key that +contains the env settings of the FWorker calling this method. +This provides for abstracting out certain commands or +settings. For example, β€œfoo” may be named β€œfoo1” in resource +1 and β€œfoo2” in resource 2. The FWorker env can specify { +β€œfoo”: β€œfoo1”}, which maps an abstract variable β€œfoo” to the +relevant β€œfoo1” or β€œfoo2”. You can then write a task that +uses fw_spec[β€œ_fw_env”][β€œfoo”] that will work across all +these multiple resources.

+
+
+
+
Returns:ΒΆ
+

(FWAction)

+
+
+
+ +
+ +

mispr.lammps.tests.run_lammps moduleΒΆ

+

mispr.lammps.tests.tleap moduleΒΆ

+

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.utilities.html b/html/mispr.lammps.utilities.html new file mode 100644 index 00000000..62f50dd2 --- /dev/null +++ b/html/mispr.lammps.utilities.html @@ -0,0 +1,1156 @@ + + + + + + + + + + + + + + + + mispr.lammps.utilities package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps.utilities packageΒΆ

+

SubmodulesΒΆ

+

mispr.lammps.utilities.opls moduleΒΆ

+
+
+class mispr.lammps.utilities.opls.MaestroRunner(name, input_file, mae_cmd=None, ffld_cmd=None, working_dir=None)[source]ΒΆ
+

Bases: object

+

Wrapper for assigning OPLS_2005 force field parameters for a molecule using Maestro +software of Schrondinger. The OPLS_2005 parameters are described in:

+

Banks, J.L.; Beard, H.S.; Cao, Y.; Cho, A.E.; Damm, W.; Farid, R.; +Felts, A.K.; Halgren, T.A.; Mainz, D.T.; Maple, J.R.; Murphy, R.; +Philipp, D.M.; Repasky, M.P.; Zhang, L.Y.; Berne, B.J.; Friesner, +R.A.; Gallicchio, E.; Levy. R.M. Integrated Modeling Program, +Applied Chemical Theory (IMPACT). J. Comp. Chem. 2005, 26, 1752.

+

The OPLS_2005 parameters are located in (you need to replace the version in the path +with the correct Schrondinger version installed):

+

$SCHRODINGER/mmshare-vversion/data/f14/

+

To use this class, you need to do the following:

+
    +
  1. Download the free version of Maestro (https://www.schrodinger.com/freemaestro)

  2. +
  3. Install Maestro and set the environment variable $SCHRODINGER, e.g., +β€˜export SCHRODINGER=/opt/schrodinger/suites2022-2’. Check +https://www.schrodinger.com/kb/1842 for more details.

  4. +
+
+
Parameters:ΒΆ
+
+
name : strΒΆ

Name of the molecule to use when saving the mae and log files +generated by Maestro.

+
+
input_file : strΒΆ

Molecule/structure file to use for converting to a mae +file. For a full list of supported formats, check +https://www.schrodinger.com/kb/1278.

+
+
mae_cmd : strΒΆ

Full command to use for converting the structure format to +mae file; if not specified, will try to parse the command from the +MISPR configuration file.

+
+
ffld_cmd : strΒΆ

Full command to use for generating the force field parameters +from the mae file. If not specified, will try to parse the command from +the MISPR configuration file.

+
+
working_dir : strΒΆ

Working directory where the input_file is located and +Maestro files to be generated.

+
+
+
+
+
+
+cleanup()[source]ΒΆ
+

Deletes the log and mae files created by Maestro

+
+ +
+
+convert_ff_log_to_json()[source]ΒΆ
+

Converts the force field parameters in the log file to a +dictionary format that is compatible with MISPR.

+
+ +
+
+convert_mol_to_mae()[source]ΒΆ
+

Converts a structure input file to a mae file.

+
+ +
+
+get_ff_log()[source]ΒΆ
+

Generates a log file with force field parameters using a mae +file.

+
+ +
+
+get_opls_params(cleanup=True)[source]ΒΆ
+

Wrapper function that converts input structure to mae format, uses it to +generate a log file with the force field parameters of the molecule, parses the +log file to generate a dictionary of force parameters in a format compatible +with the lammps workflow in MISPR, and optionally cleans up the working +directory by removing the intermediate files generated in the process.

+
+
Parameters:ΒΆ
+
+
cleanup : boolΒΆ

Whether to clean up the working directory. Defaults to +True.

+
+
+
+
Returns:ΒΆ
+

Dictionary with force field parameters.

+
+
Return type:ΒΆ
+

dict

+
+
+
+ +
+ +

mispr.lammps.utilities.utilities moduleΒΆ

+
+
+mispr.lammps.utilities.utilities.add_ff_labels_to_BADI_lists(ff_list, label)[source]ΒΆ
+

Add extra string to the end of all atom type labels in lists containing information +about Bonds, Angles, Dihedrals, or Impropers (BADI). This function is intended to be +used through the add_ff_labels_to_dict.

+
+
Parameters:ΒΆ
+
+
ff_list : ListΒΆ

The value from ff_dict using one of the following keys: +β€˜Bonds’, β€˜Angles’, β€˜Dihedrals’, or β€˜Impropers’. The form of this list +should be as follows:

+
[{'coeffs': [Float, ...], 'types': [(Str, ...), ...]}, ...]
+
+
+

+
+
label : strΒΆ

A label for the molecular species that is unique for the system +being created.

+
+
+
+
+
+ +
+
+mispr.lammps.utilities.utilities.add_ff_labels_to_dict(ff_dict, label)[source]ΒΆ
+
+
Parameters:ΒΆ
+
+
ff_dictΒΆ

A dictionary containing the force field information for a molecule. +The dictionary should have the following form:

+
{
+    "Molecule": pmg.Molecule,
+    "Labels": List,
+    "Masses": OrderedDict,
+    "Nonbond": List,
+    "Bonds": [{'coeffs': [a, b], 'types': [('x1', 'x2'), ...]}, ...],
+    "Angles": [{'coeffs': [a, b], 'types': [('x1', 'x2', 'x3'), ...]}, ...],
+    "Dihedrals": [{'coeffs': [a, b, c], 'types': [('x1', 'x2', 'x3', 'x4), ...]}, ...],
+    "Impropers": [{'coeffs': [a, b, c], 'types': [('x1', 'x2', 'x3', 'x4), ...]}, ...],
+    "Improper Topologies": List,
+    "Charges": np.Array,
+    ...
+}
+
+
+

+
+
label : strΒΆ

+
+
+
+
+
+ +
+
+mispr.lammps.utilities.utilities.get_db(input_db=None)[source]ΒΆ
+
+ +
+
+mispr.lammps.utilities.utilities.lammps_mass_to_element(lammps_masses)[source]ΒΆ
+

Create a dict for mapping atom mass to element.

+
+
Parameters:ΒΆ
+
+
lammps_masses : listΒΆ

List of masses in lammps units.

+
+
+
+
Returns:ΒΆ
+

dict

+
+
+
+ +
+
+mispr.lammps.utilities.utilities.process_ff_doc(parameter_dict, method=None, doi=None, **kwargs)[source]ΒΆ
+
+ +
+
+mispr.lammps.utilities.utilities.process_run(smiles, nmols, box, template_filename, control_settings=None)[source]ΒΆ
+
+ +
+
+mispr.lammps.utilities.utilities.run_fake_lammps(workflow, ref_dirs, control_filenames=None)[source]ΒΆ
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/mispr.lammps.workflows.html b/html/mispr.lammps.workflows.html new file mode 100644 index 00000000..6d7cc6e0 --- /dev/null +++ b/html/mispr.lammps.workflows.html @@ -0,0 +1,1173 @@ + + + + + + + + + + + + + + + + mispr.lammps.workflows package - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

mispr.lammps.workflows packageΒΆ

+

SubmodulesΒΆ

+

mispr.lammps.workflows.base moduleΒΆ

+
+
+mispr.lammps.workflows.base.lammps_analysis_fws(analysis_list, analysis_settings, working_dir, **kwargs)[source]ΒΆ
+

Generate FireWorks for running LAMMPS analysis.

+
+
Parameters:ΒΆ
+
+
analysis_list : listΒΆ

List of analysis types to perform. Supported types are: +β€˜diffusion’, β€˜rdf’, β€˜cn’, and β€˜clusters’.

+
+
analysis_settings : listΒΆ

List of dictionaries containing the settings for each +analysis type.

+
+
working_dir : strΒΆ

Directory where the data files will be written.

+
+
kwargs : keyword argumentsΒΆ

Additional keyword arguments.

+
+
+
+
Returns:ΒΆ
+

List of FireWorks for running LAMMPS analysis. +links_dict (dict): Dictionary containing the links between the FireWorks.

+
+
Return type:ΒΆ
+

fireworks (list)

+
+
+
+ +
+
+mispr.lammps.workflows.base.lammps_data_fws(system_species_data, system_mixture_type, box_data, box_data_type='cubic', data_file_name='complex.data', working_dir=None, db=None, tag='unknown', **kwargs)[source]ΒΆ
+

Generate FireWorks for writing LAMMPS data files.

+
+
Parameters:ΒΆ
+
+
system_species_data : dictΒΆ

Dictionary containing species data. The keys are the +species labels and the values are dictionaries containing the following keys:

+
    +
  • molecule (Molecule, GaussianOutput, str, dict): Source of the molecule to +be processed. See process_mol in mispr/gaussian/utilities/mol.py +for supported operations.

  • +
  • molecule_operation_type (str): Type of molecule operation. Must match with +molecule value.

  • +
  • ff_param_method (str): Method for obtaining force field parameters. Must +match with ff_param_data value. See available methods for GetFFDictFw +in mispr/lammps/fireworks/core.py.

  • +
  • ff_param_data (str or dict): Data regarding necessary information to obtain +ff parameters. Must match with ff_param_method value.

  • +
  • mol_mixture_type (str): Type of mixture data. Must be β€œSolutes” or β€œSolvents”.

  • +
  • mixture_data (int or dict): Information regarding the number of molecules +of this type in the system. Depends on the system_mixture_type parameter.

  • +
+

+
+
system_mixture_type : strΒΆ

Type of mixture data. Must be β€œconcentration” or +β€œnumber of molecules”. See LammpsDataWrapper in +pymatgen/io/lammps/data.py for more information.

+
+
box_data : float, int, list (3,2), array (3,2), or LammpsBoxΒΆ

Definitions for +box size. See box_data_type for info how to define this parameter.

+
+
box_data_type : str, optionalΒΆ

Determines the value of the box_data parameter. +Can be one of the following: β€˜cubic’, β€˜rectangular’, or β€˜LammpsBox’. If +β€˜cubic’, box_data must be a float or int; if β€˜rectangular’, box_data +must be an array-like with size (3,2); if β€˜LammpsBox’, box_data must be +a LammpsBox object. Defaults to β€˜cubic’.

+
+
data_file_name : str, optionalΒΆ

Name of the data file to be written. Defaults to +β€œcomplex.data”.

+
+
working_dir : str, optionalΒΆ

Directory where the data files will be written. +Defaults to the current working directory.

+
+
db : str or dict, optionalΒΆ

Database credentials. Could be a string with the path +to the database file or a dictionary with the database credentials. If none +is provided, attempts to read the configuration files. Only used when +save_ff_to_db is True.

+
+
tag : str, optionalΒΆ

Tag for the Fireworks. Defaults to β€œunknown”.

+
+
kwargs : keyword argumentsΒΆ

Additional keyword arguments.

+
+
+
+
Returns:ΒΆ
+

List of FireWorks for writing LAMMPS data files.

+
+
Return type:ΒΆ
+

fireworks (list)

+
+
+
+ +
+
+mispr.lammps.workflows.base.lammps_run_fws(recipe=[['emin', ['template_filename', 'emin_gaff']], ['npt', ['template_filename', 'npt']], ['melt', ['template_filename', 'nvt']], ['quench', ['template_filename', 'nvt']], ['nvt', ['template_filename', 'nvt']]], recipe_settings=[{'data_filename': '../data.mixture', 'restart_finalname': 'restart.emin'}, {'restart_filename': '../emin/restart.emin', 'restart_final_filename': 'restart.npt'}, {'restart_filename': '../npt/restart.npt', 'temperature_initial': 500.0, 'temperature_final': 500.0, 'run': 2000000, 'restart_final_filename': 'restart.melt_500K', 'data_final_filename': 'data.melt'}, {'restart_filename': '../melt/restart.melt_500K', 'temperature_initial': 500.0, 'temperature_final': 298.15, 'run': 3000000, 'restart_final_filename': 'restart.quench_298K', 'data_final_filename': 'data.quench_298K'}, {'restart_filename': '../quench/restart.quench_298K', 'temperature_initial': 298.15, 'temperature_final': 298.15, 'run': 5000000, 'restart_final_filename': 'restart.nvt_5ns', 'data_final_filename': 'data.nvt_5ns'}], recipe_qadapter=[{'walltime': '00:10:00', 'job_name': 'emin'}, {'walltime': '08:00:00', 'job_name': 'npt'}, {'walltime': '08:00:00', 'job_name': 'melt'}, {'walltime': '12:00:00', 'job_name': 'quench'}, {'walltime': '48:00:00', 'job_name': 'nvt'}], init_spec=None, db=None, working_dir=None, save_runs_to_db=True, save_runs_to_file=False, **kwargs)[source]ΒΆ
+

Generate FireWorks for running LAMMPS simulations.

+
+
Parameters:ΒΆ
+
+
recipe : list, optionalΒΆ

List of lists containing the name of the step and the +template filename or string for the LAMMPS input file. Defaults to +LAMMPS_RECIPE.

+
+
recipe_settings : list, optionalΒΆ

List of dictionaries containing the settings +for each step in the recipe. Defaults to RECIPE_SETTINGS.

+
+
recipe_qadapter : list, optionalΒΆ

List of dictionaries containing the settings +for the queue adapter for each step in the recipe. Defaults to +QADAPTER_RUN_LAMMPS_SPEC.

+
+
init_spec : dict, optionalΒΆ

Initial spec for the FireWorks. Defaults to None.

+
+
db : str or dict, optionalΒΆ

Database credentials. Could be a string with the path +to the database file or a dictionary with the database credentials. If none +is provided, attempts to read the configuration files. Only used when +save_runs_to_db is True.

+
+
working_dir : str, optionalΒΆ

Directory where the data files will be written. +Defaults to the current working directory.

+
+
save_runs_to_db : bool, optionalΒΆ

Whether to save the runs to the database. +Defaults to True.

+
+
save_runs_to_file : bool, optionalΒΆ

Whether to save the runs to a file. Defaults +to False.

+
+
kwargs : keyword argumentsΒΆ

Additional keyword arguments.

+
+
+
+
Returns:ΒΆ
+

List of FireWorks for running LAMMPS simulations.

+
+
Return type:ΒΆ
+

fireworks( list)

+
+
+
+ +
+
+mispr.lammps.workflows.base.lammps_workflow(system_species_data=None, system_mixture_type=None, box_data=None, box_data_type='cubic', data_file_name='data.mixture', recipe=[['emin', ['template_filename', 'emin_gaff']], ['npt', ['template_filename', 'npt']], ['melt', ['template_filename', 'nvt']], ['quench', ['template_filename', 'nvt']], ['nvt', ['template_filename', 'nvt']]], recipe_settings=[{'data_filename': '../data.mixture', 'restart_finalname': 'restart.emin'}, {'restart_filename': '../emin/restart.emin', 'restart_final_filename': 'restart.npt'}, {'restart_filename': '../npt/restart.npt', 'temperature_initial': 500.0, 'temperature_final': 500.0, 'run': 2000000, 'restart_final_filename': 'restart.melt_500K', 'data_final_filename': 'data.melt'}, {'restart_filename': '../melt/restart.melt_500K', 'temperature_initial': 500.0, 'temperature_final': 298.15, 'run': 3000000, 'restart_final_filename': 'restart.quench_298K', 'data_final_filename': 'data.quench_298K'}, {'restart_filename': '../quench/restart.quench_298K', 'temperature_initial': 298.15, 'temperature_final': 298.15, 'run': 5000000, 'restart_final_filename': 'restart.nvt_5ns', 'data_final_filename': 'data.nvt_5ns'}], recipe_qadapter=[{'walltime': '00:10:00', 'job_name': 'emin'}, {'walltime': '08:00:00', 'job_name': 'npt'}, {'walltime': '08:00:00', 'job_name': 'melt'}, {'walltime': '12:00:00', 'job_name': 'quench'}, {'walltime': '48:00:00', 'job_name': 'nvt'}], db=None, working_dir=None, analysis_list=None, analysis_settings=None, name='lammps_workflow', **kwargs)[source]ΒΆ
+

Create a LAMMPS workflow.

+
+
Parameters:ΒΆ
+
+
system_species_data : dict, optionalΒΆ

Dictionary containing species data. Refer +to the lammps_data_fws function for more information. Defaults to +None. If not provided, the workflow will not create any FireWorks for +writing LAMMPS data files.

+
+
system_mixture_type : strΒΆ

Type of mixture data. Must be β€œconcentration” or +β€œnumber of molecules”. See LammpsDataWrapper in +pymatgen/io/lammps/data.py for more information. Defaults to None. +If not provided, the workflow will not create any FireWorks for writing +LAMMPS data files.

+
+
box_data : float, int, list (3,2), array (3,2), or LammpsBoxΒΆ

Definitions for +box size. See lammps_data_fws for info on how to define this parameter. +Defaults to None. If not provided, the workflow will not create any +FireWorks for writing LAMMPS data files.

+
+
box_data_type : str, optionalΒΆ

Determines the value of the box_data +parameter. Defaults to β€˜cubic’.

+
+
data_file_name : str, optionalΒΆ

Name of the data file to be written. Defaults +to β€˜data.mixture’.

+
+
recipe : list, optionalΒΆ

List of lists containing the name of the step and the +template filename or string for the LAMMPS input file. Defaults to +LAMMPS_RECIPE.

+
+
recipe_settings : list, optionalΒΆ

List of dictionaries containing the settings +for each step in the recipe. Defaults to RECIPE_SETTINGS.

+
+
recipe_qadapter : list, optionalΒΆ

List of dictionaries containing the settings +for the queue adapter for each step in the recipe. Defaults to +QADAPTER_RUN_LAMMPS_SPEC.

+
+
db : str or dict, optionalΒΆ

Database credentials. Could be a string with the +path to the database file or a dictionary with the database credentials. +If none is provided, attempts to read the configuration files. Only used when +save_runs_to_db is True. Defaults to None.

+
+
working_dir : str, optionalΒΆ

Directory where the data files will be written. +Defaults to the current working directory.

+
+
analysis_list : list, optionalΒΆ

List of analysis types to perform. Supported +types are: β€˜diffusion’, β€˜rdf’, β€˜cn’, and β€˜clusters’. Defaults to None. +If not provided, the workflow will not create any FireWorks for running +LAMMPS analysis.

+
+
analysis_settings : list, optionalΒΆ

List of dictionaries containing the settings +for each analysis type. Defaults to None. If not provided, the workflow +will not create any FireWorks for running LAMMPS analysis.

+
+
name : str, optionalΒΆ

Name of the workflow. Defaults to β€˜lammps_workflow’.

+
+
kwargs : keyword argumentsΒΆ

Additional keyword arguments.

+
+
+
+
Returns:ΒΆ
+

Workflow

+
+
+
+ +

Module contentsΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/modules.html b/html/modules.html new file mode 100644 index 00000000..44698024 --- /dev/null +++ b/html/modules.html @@ -0,0 +1,769 @@ + + + + + + + + + + + + + + + + mispr - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + + + + +
+ +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/objects.inv b/html/objects.inv new file mode 100644 index 00000000..3480a9a2 Binary files /dev/null and b/html/objects.inv differ diff --git a/html/overview.html b/html/overview.html new file mode 100644 index 00000000..acbd3781 --- /dev/null +++ b/html/overview.html @@ -0,0 +1,832 @@ + + + + + + + + + + + + + + + + Overview - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

OverviewΒΆ

+

MISPR (Materials Informatics for Structure-Property Relationships) is a +high-throughput computational infrastructure aimed at guiding and +accelerating materials discovery, optimization, and deployment for +liquid solutions by seamlessly integrating density functional theory +(DFT) with classical molecular dynamics (MD) techniques.

+

MISPR is motivated by the Materials Genome Initiative (MGI) principles and is +built on top of open-source Python packages developed for the Materials +Project such as pymatgen, +FireWorks , +and custodian, as +well as MDPropTools, which +is an in-house package for analyzing MD output and trajectory files.

+
+_images/overview.png +
+

Features of MISPR include:

+
    +
  • Automation of DFT and MD simulations and all their underlying tasks +from file management and job submission to supercomputing resources, +to output parsing and data analytics; a task that can be done to a +single molecule/system or to a large number of systems in parallel

  • +
  • Creation of computational databases of force field parameters and DFT +and MD derived properties of molecular systems for establishing +structure-property relations and maintaining data provenance and +reproducibility

  • +
  • Detection of the inevitable errors that occur during the simulations +and their on-the-fly correction based on template responses that have +been designed relying on human intuition coupled with extensive +experience to significantly improve the success rate of high-throughput +simulations while eliminating human intervention

  • +
  • Support for flexible and well-tested DFT workflows that compute various +properties of individual molecular species or complexes such as bond +dissociation energy, binding energy, redox potential, and nuclear +magnetic resonance (NMR) tensors

  • +
  • Derivation of many molecular ensemble properties such as radial +distribution functions, diffusion coefficients, viscosity, and +conductivity of liquid solutions, which are critical to understanding +complex inter- and intra-atomic interactions controlling the performance +of solutions within various chemistry, biology, and materials science +applications

  • +
  • Seamless integration of DFT and MD simulations through hybrid +workflows that enable force field generation and information flow +between the two length scales to allow exploring wide chemical and +parameter spaces (e.g., temperature, pressure, concentration, etc.), +a task that can be infeasible experimentally and challenging using +manual calculations

  • +
  • Automatic extraction of hundreds of thousands of solvation structures +from MD ensembles and their use in DFT workflows to accurately represent +the electronic environment, which is crucial to derive reliable energetics +and other properties such as NMR chemical shifts and redox potentials +and match them to experimental data

  • +
+
+

Note

+

MISPR is primarily built to work with Gaussian +electronic structure software for DFT calculation and +LAMMPS +open-source software for MD simulations.

+
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/py-modindex.html b/html/py-modindex.html new file mode 100644 index 00000000..d25a9966 --- /dev/null +++ b/html/py-modindex.html @@ -0,0 +1,734 @@ + + + + + + + + + + + + + + + + None - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +None + + + + + + +
+
+ + +
+ +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/resources/faq.html b/html/resources/faq.html new file mode 100644 index 00000000..1ca021e4 --- /dev/null +++ b/html/resources/faq.html @@ -0,0 +1,776 @@ + + + + + + + + + + + + + + + + FAQ - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

FAQΒΆ

+

This page is under construction.

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/resources/resources.html b/html/resources/resources.html new file mode 100644 index 00000000..3dd3f244 --- /dev/null +++ b/html/resources/resources.html @@ -0,0 +1,858 @@ + + + + + + + + + + + + + + + + Helpful Links - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Helpful LinksΒΆ

+

Code DocumentationΒΆ

+ +

Code CapsulesΒΆ

+
    +
  • MISPR workshop for high-school students: +a compute capsule that stores the Python environment for the workshop +and includes Jupyter notebooks for predicting various materials +properties using MISPR

  • +
  • NMR tutorial: a compute +capsule that shows how to use the hybrid NMR workflow in MISPR to +sample solvation structures from MD simulations and predict their +NMR chemical shifts in a fully automated manner

  • +
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/searchindex.js b/html/searchindex.js new file mode 100644 index 00000000..79a4210d --- /dev/null +++ b/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"titles": ["Changelog", "Citing MISPR", "MISPR documentation", "Configuration Files", "Prerequisites", "Installation", "Running a Test Workflow", "Keywords", "License", "mispr package", "mispr.common package", "mispr.gaussian package", "mispr.gaussian.firetasks package", "mispr.gaussian.fireworks package", "mispr.gaussian.utilities package", "mispr.gaussian.workflows package", "mispr.gaussian.workflows.base package", "mispr.hybrid package", "mispr.hybrid.firetasks package", "mispr.hybrid.workflows package", "mispr.lammps package", "mispr.lammps.firetasks package", "mispr.lammps.fireworks package", "mispr.lammps.tests package", "mispr.lammps.utilities package", "mispr.lammps.workflows package", "mispr", "Overview", "FAQ", "Helpful Links", "setup module", "Workflow Basics", "Creating Custom Workflows", "Supported Workflows", "Workflow Tutorials"], "terms": {"v0": 0, "0": [0, 6, 12, 13, 14, 16, 19, 25, 34], "1": [0, 1, 3, 6, 12, 13, 14, 16, 18, 19, 21, 23, 34], "initi": [0, 4, 12, 13, 16, 19, 25, 27, 31, 33], "releas": [0, 8], "r": [0, 24, 34], "atwi": [0, 1, 2], "m": [0, 4, 6, 24], "bliss": [0, 1], "4": [0, 6, 14, 16, 34], "support": [0, 12, 13, 14, 16, 19, 21, 22, 24, 25, 27, 34], "retriev": [0, 4, 10, 11, 12, 13, 14, 22, 34], "molecul": [0, 4, 6, 10, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25, 27, 31, 34], "from": [0, 4, 5, 6, 8, 10, 11, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 27, 29, 31, 33, 34], "pubchem": [0, 9, 14, 19, 26, 34], "directli": [0, 5, 6, 12, 16, 21, 34], "us": [0, 1, 2, 3, 4, 6, 8, 10, 11, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25, 27, 29, 31, 33, 34], "them": [0, 3, 4, 12, 14, 16, 21, 27, 31, 33], "workflow": [0, 1, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 17, 20, 24, 27, 29], "opl": [0, 9, 20, 21, 22, 33], "2005": [0, 24], "ff": [0, 21, 22, 25], "run": [0, 2, 3, 4, 5, 7, 9, 11, 12, 13, 14, 16, 18, 19, 20, 22, 23, 25, 31, 33], "maestro": [0, 21, 24], "backend": [0, 4], "option": [0, 3, 4, 5, 10, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25, 31, 34], "charg": [0, 4, 8, 12, 13, 14, 16, 19, 21, 22, 24, 31, 33, 34], "scale": [0, 12, 16, 21, 27], "ionic": 0, "speci": [0, 19, 21, 22, 24, 25, 27], "when": [0, 3, 6, 10, 12, 14, 16, 18, 21, 23, 24, 25], "prepar": [0, 5], "lammp": [0, 3, 4, 9, 19, 26, 27, 29, 31, 33], "data": [0, 4, 6, 9, 12, 14, 18, 19, 20, 21, 22, 24, 25, 27, 31], "file": [0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 19, 21, 22, 24, 25, 27, 31, 33, 34], "automat": [0, 3, 19, 27], "identif": [0, 14], "system": [0, 3, 4, 21, 22, 24, 25, 27, 31, 34], "element": [0, 12, 13, 24], "type": [0, 3, 4, 5, 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 24, 25, 33], "creat": [0, 3, 5, 6, 7, 11, 12, 13, 14, 16, 19, 21, 24, 25, 31, 33, 34], "dump": [0, 21], "simul": [0, 1, 2, 4, 5, 19, 21, 22, 25, 27, 29, 33], "addit": [0, 2, 6, 11, 12, 13, 14, 16, 18, 19, 21, 23, 25], "mdproptool": [0, 19, 21, 27], "packag": [0, 3, 4, 5, 26, 27, 31], "analysi": [0, 12, 16, 19, 21, 22, 25, 31, 33, 34], "md": [0, 1, 2, 4, 5, 19, 27, 29, 31, 33], "trajectori": [0, 21, 22, 27, 33], "depend": [0, 2, 4, 6, 12, 13, 14, 16, 19, 22, 25, 31], "If": [1, 2, 3, 4, 5, 6, 11, 12, 14, 16, 19, 21, 22, 24, 25, 34], "you": [1, 2, 3, 4, 5, 6, 12, 18, 21, 23, 24, 34], "find": [1, 3, 12, 14, 16, 34], "your": [1, 3, 5, 6], "research": 1, "pleas": [1, 2, 3, 19], "consid": [1, 16], "follow": [1, 2, 3, 4, 5, 6, 8, 12, 14, 16, 19, 21, 24, 25, 31, 34], "paper": 1, "articl": 1, "atwi2022mispr": 1, "titl": 1, "an": [1, 3, 4, 6, 8, 10, 12, 13, 14, 16, 18, 19, 21, 22, 23, 25, 27, 31], "autom": [1, 27, 29, 31], "infrastructur": [1, 27, 31], "high": [1, 27, 29], "throughput": [1, 27], "dft": [1, 2, 4, 5, 19, 27, 31, 33], "author": [1, 8], "rasha": [1, 2], "matthew": 1, "makeev": 1, "maxim": 1, "rajput": 1, "nav": 1, "nidhi": 1, "year": 1, "2022": [1, 6, 8, 33], "download": [1, 10, 14, 24, 34], "bibtex": [1, 14], "2": [1, 3, 6, 12, 13, 16, 18, 19, 21, 23, 24, 25, 34], "hybrid": [1, 9, 26, 27, 29, 33], "nmr": [1, 9, 11, 12, 15, 17, 27, 29, 33], "atwi2022autom": 1, "framework": 1, "predict": [1, 4, 29, 31], "chemic": [1, 14, 24, 27, 29, 31, 33], "shift": [1, 27, 29, 33], "within": [1, 3, 27], "liquid": [1, 12, 16, 19, 27], "solut": [1, 11, 12, 16, 19, 25, 27], "chen": 1, "ying": 1, "han": 1, "kee": 1, "sung": 1, "mueller": 1, "karl": 1, "t": [1, 14, 24], "murugesan": 1, "vijayakumar": 1, "journal": 1, "natur": 1, "comput": [1, 2, 3, 5, 7, 14, 16, 19, 27, 29, 31], "scienc": [1, 2, 27, 31], "volum": 1, "number": [1, 3, 4, 12, 14, 16, 19, 21, 25, 27, 33, 34], "page": [1, 3, 28, 32, 34], "112": 1, "122": 1, "publish": [1, 8], "group": [1, 11, 12, 14, 19], "i": [2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25, 27, 28, 31, 32, 34], "python": [2, 5, 6, 7, 11, 27, 29, 31, 34], "librari": [2, 5], "materi": [2, 5, 27, 29], "contain": [2, 3, 6, 11, 12, 14, 18, 21, 23, 24, 25, 31, 34], "preset": [2, 31, 33], "complex": [2, 6, 16, 21, 25, 27], "hierarch": 2, "densiti": [2, 11, 12, 19, 27], "function": [2, 10, 11, 12, 14, 16, 19, 21, 22, 24, 25, 27, 31], "theori": [2, 12, 24, 27], "classic": [2, 27], "molecular": [2, 12, 14, 16, 21, 22, 24, 27, 31], "dynam": [2, 16, 21, 27], "properti": [2, 4, 11, 12, 14, 16, 22, 27, 29, 31], "pip": [2, 4], "befor": [2, 3, 4, 5, 6, 12, 14], "can": [2, 3, 4, 5, 6, 11, 12, 14, 16, 18, 19, 21, 23, 25, 27, 31, 33, 34], "start": [2, 4, 5, 6, 14], "ar": [2, 3, 4, 5, 6, 7, 12, 13, 14, 16, 19, 21, 22, 24, 25, 27, 31, 33, 34], "step": [2, 5, 6, 12, 14, 16, 19, 25, 31, 33, 34], "need": [2, 3, 4, 5, 6, 12, 21, 24], "refer": [2, 3, 6, 12, 13, 14, 16, 19, 21, 25, 34], "guid": [2, 4, 27], "complet": [2, 6, 7, 31], "setup": [2, 4, 31], "instruct": [2, 4, 5], "includ": [2, 3, 4, 6, 8, 11, 12, 14, 16, 19, 27, 29, 31], "ani": [2, 5, 8, 11, 12, 14, 16, 19, 25, 33], "configur": [2, 4, 5, 6, 7, 12, 13, 16, 19, 22, 24, 25, 33], "requir": [2, 3, 4, 14, 16, 19, 21], "about": [2, 21, 24, 31], "overview": 2, "prerequisit": 2, "basic": [2, 3, 5], "extern": 2, "how": [2, 3, 4, 6, 19, 25, 29], "tos": 2, "tutori": [2, 3, 6, 29], "faq": 2, "code": [2, 5, 6, 11], "subpackag": [2, 26], "contirbut": 2, "form": [2, 3, 4, 10, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 31, 34], "request": [2, 16, 34], "ad": [2, 3, 4, 12, 14], "new": [2, 4, 11, 12, 14, 16, 31], "featur": [2, 4, 27], "fix": 2, "bug": 2, "issu": 2, "exampl": [2, 3, 4, 6, 12, 16, 18, 21, 23, 31, 34], "want": [2, 3, 4, 5, 6, 19], "add": [2, 4, 12, 14, 16, 21, 24, 34], "chang": [2, 3, 4, 5, 16], "someth": [2, 6], "do": [2, 3, 4, 8, 14, 24], "thi": [2, 3, 4, 5, 6, 8, 11, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25, 28, 32, 34], "fork": 2, "github": [2, 4, 5], "submit": [2, 34], "pull": [2, 5], "we": [2, 3, 4, 6, 14, 31, 34], "review": 2, "move": [2, 3, 11], "where": [2, 3, 4, 6, 7, 12, 14, 16, 19, 24, 25, 31], "its": [2, 4, 6, 12, 13, 14], "progress": 2, "track": [2, 14], "For": [2, 3, 5, 12, 18, 21, 23, 24, 31, 34], "other": [2, 3, 4, 8, 11, 12, 13, 14, 22, 27, 31, 33, 34], "inquiri": 2, "contact": 2, "u": [2, 4, 14], "stonybrook": 2, "edu": 2, "after": [3, 4, 6, 19, 21, 31], "set": [3, 5, 6, 11, 12, 13, 14, 16, 18, 19, 21, 23, 24, 25], "up": [3, 5, 6, 12, 14, 19, 21, 24], "environ": [3, 5, 6, 7, 24, 27, 29], "instal": [3, 4, 6, 16, 24], "softwar": [3, 5, 6, 8, 24, 27, 31], "work": [3, 4, 6, 10, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25, 27, 34], "done": [3, 12, 27], "intend": [3, 21, 23, 24], "help": [3, 11, 14], "get": [3, 4, 12, 13, 14, 16, 18, 19, 21, 23], "first": [3, 5, 6, 11, 12, 14, 16], "time": [3, 4, 6, 12, 14, 31], "firework": [3, 4, 6, 7, 9, 11, 12, 14, 16, 18, 20, 21, 23, 25, 27, 29, 31, 34], "mispr": [3, 4, 6, 8, 27, 29, 31, 33, 34], "so": [3, 8, 31], "learn": [3, 4], "document": [3, 4, 6, 8, 11, 12, 13, 14, 16, 19, 21, 22, 31], "more": [3, 4, 6, 11, 12, 13, 14, 21, 24, 25, 31], "inform": [3, 6, 19, 21, 24, 25, 27, 31], "here": [3, 6, 16, 19], "onli": [3, 4, 6, 12, 16, 19, 21, 25], "discuss": 3, "which": [3, 4, 6, 11, 12, 14, 16, 18, 21, 23, 27], "suffici": 3, "db": [3, 6, 11, 12, 13, 14, 16, 19, 21, 22, 25], "json": [3, 4, 6, 11, 12, 13, 14, 16, 19, 21, 22, 31, 34], "mongodb": [3, 5, 6, 12, 14, 19, 31], "like": [3, 6, 19, 25, 31], "credenti": [3, 4, 11, 12, 13, 16, 19, 21, 22, 25], "connect": [3, 8, 21], "databas": [3, 4, 5, 7, 9, 10, 12, 13, 14, 16, 19, 21, 22, 25, 26, 27, 31, 34], "calcul": [3, 4, 11, 12, 13, 14, 16, 19, 21, 22, 27, 31, 34], "output": [3, 6, 11, 12, 13, 14, 16, 18, 19, 21, 23, 27, 31, 33, 34], "store": [3, 4, 7, 12, 13, 21, 22, 29, 31], "string": [3, 4, 12, 14, 16, 19, 21, 22, 24, 25], "doubl": [3, 14], "quot": 3, "except": [3, 16], "valu": [3, 11, 12, 14, 16, 21, 24, 25], "port": [3, 4, 11, 20], "integ": 3, "admin_us": 3, "admin_usernam": 3, "admin_password": 3, "alias": 3, "collect": [3, 6, 11, 12, 31], "db_name": 3, "host": [3, 4, 11, 20], "hostnam": 3, "my_fwork": [3, 14], "yaml": [3, 14], "": [3, 4, 6, 12, 14, 16, 21, 24], "In": [3, 4, 12, 18, 21, 22, 23, 31, 34], "simpl": [3, 4, 6], "workstat": 3, "launchpad": [3, 6, 7, 34], "complic": [3, 4], "supercomput": [3, 4, 27], "center": [3, 4], "queue": [3, 6, 14, 25, 34], "name": [3, 4, 6, 10, 11, 12, 13, 14, 16, 18, 19, 20, 21, 22, 23, 24, 25, 31, 34], "worker_nam": 3, "categori": [3, 14], "queri": [3, 10, 11, 12, 14, 19, 20, 21, 34], "env": [3, 12, 18, 21, 23], "db_file": [3, 11, 20], "codes_dir": [3, 4, 5, 7], "config": [3, 12, 21], "scratch_dir": 3, "null": 3, "The": [3, 4, 5, 6, 8, 11, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25, 31, 33, 34], "paramet": [3, 4, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 31, 33], "defin": [3, 11, 12, 13, 14, 16, 19, 22, 25, 31], "worker": [3, 14], "job": [3, 6, 11, 12, 14, 16, 19, 27, 31, 34], "have": [3, 4, 5, 6, 12, 14, 19, 21, 24, 27], "multipl": [3, 6, 11, 12, 14, 16, 18, 19, 21, 23, 31], "see": [3, 4, 6, 12, 13, 14, 16, 19, 21, 22, 25], "control": [3, 7, 9, 14, 20, 21, 22, 27], "than": [3, 4, 14], "one": [3, 6, 11, 12, 14, 16, 19, 21, 24, 25, 31], "default": [3, 4, 9, 10, 12, 13, 14, 16, 19, 21, 22, 24, 25, 26], "allow": [3, 27], "all": [3, 4, 6, 7, 8, 12, 13, 14, 16, 18, 19, 21, 23, 24, 27, 31], "specif": [3, 4, 14, 19], "path": [3, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25], "scratch": 3, "directori": [3, 4, 5, 6, 7, 10, 12, 13, 14, 16, 19, 21, 22, 24, 25, 34], "fast": [3, 11], "disk": 3, "access": [3, 4, 5], "my_launchpad": 3, "manag": [3, 4, 11, 27], "earlier": 3, "result": [3, 5, 11, 12, 14, 16, 21, 31, 34], "while": [3, 4, 14, 27, 31], "two": [3, 5, 12, 14, 16, 19, 21, 27], "same": [3, 4, 6, 12, 14, 16, 21], "differ": [3, 4, 5, 12, 14, 16, 22, 31], "thei": [3, 6, 12, 14, 16], "mostli": 3, "launchpad_nam": 3, "usernam": [3, 11, 20], "password": [3, 11, 20], "logdir": 3, "strm_lvl": 3, "info": [3, 6, 14, 19, 21, 25], "user_indic": 3, "wf_user_indic": 3, "authsourc": 3, "uri_mod": [3, 11, 20], "mongoclient_kwarg": 3, "server": [3, 4], "true": [3, 6, 10, 11, 12, 13, 14, 16, 19, 20, 21, 22, 24, 25, 34], "should": [3, 4, 5, 6, 11, 12, 13, 14, 16, 19, 21, 22, 24], "full": [3, 12, 16, 21, 24, 31], "uri": 3, "case": [3, 4, 12, 14, 22], "pass": [3, 11, 12, 13, 14, 16, 19, 21, 22], "custom": [3, 21, 31, 33], "keyword": [3, 14, 16, 19, 25], "argument": [3, 14, 16, 19, 25, 34], "e": [3, 4, 5, 7, 11, 12, 13, 14, 16, 19, 22, 24, 27, 31, 33], "g": [3, 4, 7, 11, 12, 13, 14, 16, 19, 22, 24, 27, 31, 33], "ssl": 3, "tl": 3, "mongocli": [3, 4], "via": [3, 5, 12, 16, 34], "pymongo": [3, 4, 11], "detail": [3, 4, 12, 13, 14, 19, 24], "my_qadapt": [3, 14], "adapt": [3, 25], "commun": [3, 31], "provid": [3, 4, 8, 12, 13, 14, 16, 18, 19, 21, 22, 23, 25, 31, 33, 34], "slurm": 3, "machin": [3, 4, 6, 14], "doe": [3, 16], "list": [3, 4, 7, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25, 34], "possibl": [3, 12], "check": [3, 4, 6, 12, 14, 16, 24], "rest": 3, "specifi": [3, 6, 10, 12, 13, 14, 16, 18, 19, 21, 23, 24], "pb": 3, "sge": 3, "etc": [3, 7, 11, 12, 14, 16, 19, 22, 27, 31, 33], "_fw_name": 3, "commonadapt": 3, "_fw_q_type": 3, "rocket_launch": 3, "rlaunch": [3, 6], "w": [3, 24], "singleshot": [3, 6], "node": [3, 12, 14, 15, 16, 21], "walltim": [3, 14, 25], "24": [3, 16, 19], "00": [3, 25], "account": [3, 4, 14], "job_nam": [3, 25], "pre_rocket": [3, 14], "post_rocket": 3, "log": [3, 21, 24], "mean": [3, 12, 21], "built": [3, 27], "method": [3, 12, 16, 18, 20, 21, 23, 24, 25], "launch": [3, 6, 34], "rocket": [3, 14], "normal": [3, 12, 14, 16], "script": [3, 4, 21, 31, 34], "alloc": 3, "resourc": [3, 4, 12, 14, 18, 21, 23, 27, 31], "command": [3, 4, 5, 6, 12, 14, 18, 19, 21, 22, 23, 24, 34], "modul": [3, 4, 26], "load": [3, 4, 34], "limit": [3, 4, 8, 12], "each": [3, 5, 12, 13, 14, 16, 19, 21, 22, 25, 31], "reserv": 3, "even": 3, "wait": [3, 7], "rapidfir": [3, 6, 34], "parallel": [3, 16, 27, 31], "go": [3, 4, 5], "over": [3, 14], "between": [3, 12, 13, 14, 16, 25, 27, 31], "mode": [3, 6], "ini": [3, 21], "gaussian": [3, 4, 6, 9, 19, 21, 22, 25, 26, 27, 29, 31, 33, 34], "ambertool": [3, 4, 21], "These": [3, 4, 16, 19], "meant": [3, 14, 16], "show": [3, 6, 29, 31, 34], "match": [3, 11, 13, 14, 16, 19, 21, 22, 25, 27], "runcalc": 3, "gcmd": 3, "g16": 3, "input_path": 3, "output_path": 3, "formchkcmd": 3, "formchk": 3, "lammpsruncalc": 3, "lcmd": 3, "mpirun": 3, "np": [3, 19, 24], "slurm_ntask": 3, "lmp_mpi": 3, "control_path": 3, "lammps_gpu_cmd": 3, "ambertoolsruncalc": 3, "acmd": 3, "antechamb": [3, 9, 20, 21], "input_fil": [3, 12, 13, 14, 21, 24], "fi": 3, "input_typ": 3, "o": [3, 4, 12, 16, 34], "output_fil": [3, 12, 13], "fo": 3, "output_typ": 3, "c": [3, 8, 24, 34], "charge_method": [3, 21], "pcmd": 3, "parmchk2": 3, "f": [3, 34], "mol2": [3, 12, 21], "tcmd": 3, "tleap": [3, 9, 20, 21], "maestrocalc": 3, "mae_cmd": [3, 21, 24], "schroding": [3, 21, 24], "util": [3, 6, 9, 11, 12, 13, 16, 20, 21, 22, 25, 34], "structconvert": [3, 21], "ffld_cmd": [3, 21, 24], "ffld_server": [3, 21], "ima": 3, "version": [3, 4, 24, 31], "14": [3, 34], "print_paramet": 3, "out_fil": 3, "convert": [3, 10, 12, 14, 16, 24], "checkpoint": [3, 12, 16, 19], "format": [3, 4, 10, 12, 14, 16, 19, 21, 24], "gpu": 3, "anyth": 3, "dollar": 3, "sign": 3, "placehold": 3, "variabl": [3, 12, 18, 21, 23, 24], "squar": [3, 21], "bracket": 3, "colon": 3, "gmcd": 3, "sinc": [3, 4, 6, 12, 14, 16, 19], "point": [3, 5, 6, 34], "fw_config": 3, "master": [3, 12, 18, 21, 23], "locat": [3, 14, 24], "config_file_dir": 3, "expect": [3, 12, 16], "modifi": [3, 8, 14], "fw": [3, 13], "abov": [3, 6, 8, 12, 16, 19, 31, 33, 34], "six": 3, "replac": [3, 6, 14, 24], "definit": [3, 4, 7, 19, 25], "call": [3, 6, 12, 18, 21, 23, 31], "look": 3, "now": [3, 5, 6], "append": [3, 12, 14, 21], "line": 3, "bash_profil": 3, "bashrc": 3, "order": [3, 4, 5, 12, 14, 16, 19, 21, 31], "tell": 3, "turn": 3, "export": [3, 24], "fw_config_fil": 3, "third": 4, "parti": 4, "usual": [4, 12, 14], "those": [4, 14], "interfer": 4, "cluster": [4, 12, 19, 21, 25], "strongli": 4, "isol": 4, "describ": [4, 24], "virtualenv": 4, "tool": 4, "feel": 4, "free": [4, 8, 12, 16, 24], "prefer": 4, "conda": [4, 5], "3": [4, 6, 11, 12, 14, 16, 19, 25, 34], "7": [4, 16, 34], "To": [4, 5, 6, 24], "activ": [4, 5, 6], "user": [4, 5, 12, 14, 16, 19, 21, 31], "upgrad": [4, 5], "mispr_env": 4, "sourc": [4, 5, 10, 11, 12, 13, 14, 16, 18, 19, 20, 21, 22, 23, 24, 25, 27], "bin": 4, "prompt": 4, "front": 4, "indic": [4, 12, 16], "insid": [4, 16, 34], "ensur": [4, 5, 16, 21], "program": [4, 21, 24], "deactiv": 4, "enviorn": 4, "simpli": [4, 5], "mai": [4, 12, 18, 21, 23], "setuptool": 4, "old": 4, "At": [4, 31], "perform": [4, 6, 7, 12, 13, 14, 16, 18, 19, 21, 22, 23, 25, 27, 31, 34], "gener": [4, 6, 12, 13, 14, 16, 21, 22, 24, 25, 27, 31, 33], "gaff": [4, 14, 21, 22, 33], "packmol": [4, 21], "execut": [4, 5, 6, 12, 31], "commerci": 4, "licens": 4, "open": [4, 12, 13, 16, 27, 34], "alreadi": [4, 5, 11, 12, 13, 16, 21, 34], "typic": 4, "correspond": [4, 5, 12, 14, 16, 19, 21, 31, 34], "pymatgen": [4, 10, 11, 12, 14, 16, 19, 21, 25, 27, 29], "handl": [4, 12, 14], "represent": [4, 6, 11, 14, 19], "oper": [4, 12, 13, 14, 16, 19, 22, 25, 31, 34], "made": 4, "make": [4, 5, 6, 12, 19], "compat": [4, 24], "our": 4, "been": [4, 27], "merg": [4, 8], "yet": 4, "main": [4, 7, 16, 19], "therefor": [4, 6], "molmd": [4, 5], "git": [4, 5], "clone": [4, 5], "http": [4, 5, 14, 21, 24], "com": [4, 5, 12, 13, 14, 21, 24], "cd": [4, 5], "py": [4, 6, 12, 13, 16, 19, 21, 22, 25, 34], "design": [4, 27], "further": [4, 5], "found": [4, 16, 19], "due": 4, "mani": [4, 6, 14, 27], "advantag": 4, "take": [4, 5, 12, 18, 21, 23], "some": [4, 5, 12, 18, 21, 23, 31, 33], "custodian": [4, 12, 27, 29], "error": [4, 5, 12, 16, 27], "occur": [4, 27], "dure": [4, 16, 27, 34], "correct": [4, 5, 12, 24, 27, 31], "accord": [4, 34], "predefin": 4, "rule": 4, "plug": 4, "similar": 4, "decis": 4, "nosql": 4, "highli": 4, "effici": 4, "scalabl": 4, "manner": [4, 29], "It": [4, 6, 7, 12, 18, 21, 23, 31], "repres": [4, 16, 27, 31], "javascript": 4, "object": [4, 10, 11, 12, 14, 16, 19, 20, 21, 24, 25, 31], "notat": 4, "dictionari": [4, 6, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25], "remov": [4, 10, 14, 24], "search": [4, 10, 14, 19, 22, 34], "statu": [4, 6, 7], "yourself": 4, "local": [4, 6, 12, 13, 14, 16], "pretti": 4, "well": [4, 6, 16, 27, 34], "out": [4, 8, 12, 13, 18, 21, 23], "howev": [4, 31], "storag": 4, "space": [4, 27], "share": [4, 21], "also": [4, 6, 12, 31, 34], "necessari": [4, 25], "privileg": 4, "mongo": 4, "servic": 4, "simplest": 4, "easiest": 4, "larg": [4, 27, 34], "size": [4, 19, 25], "atla": 4, "offer": 4, "500": [4, 25], "mb": 4, "enough": 4, "small": 4, "self": 4, "ask": 4, "continu": 4, "mainten": 4, "keep": [4, 14], "record": 4, "later": [4, 5, 6], "must": [4, 6, 19, 21, 25], "establish": [4, 27], "import": [4, 5, 6, 12, 34], "instanc": [4, 14], "client": 4, "localhost": 4, "27017": 4, "re": 4, "print": [4, 34], "list_database_nam": 4, "success": [4, 27], "return": [4, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], "present": [4, 16, 21], "rememb": 4, "appropri": 4, "below": [5, 31], "virtual": [5, 7], "sure": [5, 6], "chemistri": [5, 27], "project": [5, 27], "base": [5, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 27, 33, 34], "test": [5, 9, 14, 20, 27], "throughout": 5, "assum": [5, 6, 16], "familiar": 5, "linux": 5, "shell": [5, 31], "journei": 5, "beginn": 5, "recommend": 5, "either": [5, 12, 21], "index": [5, 11, 12, 14, 16, 19, 20], "good": [5, 12, 13], "most": [5, 6], "repositori": 5, "contribut": 5, "had": 5, "uninstal": 5, "conflict": 5, "newli": 5, "folder": [5, 12], "equival": 5, "onc": [5, 6, 31, 34], "effect": 5, "immedi": 5, "without": [5, 8, 14], "reinstal": 5, "confirm": [5, 23], "ipython": 5, "termin": [5, 6, 14], "updat": [5, 11, 12, 21], "everyth": 6, "correctli": 6, "veri": 6, "optim": [6, 12, 13, 14, 16, 19, 27, 33, 34], "structur": [6, 12, 13, 14, 16, 19, 21, 24, 27, 29, 31, 33, 34], "lpad": [6, 34], "qlaunch": [6, 34], "part": 6, "reset": 6, "eras": 6, "exist": [6, 11, 12, 14, 16], "entri": [6, 14], "y": [6, 24], "n": [6, 12, 16], "08": [6, 25], "15": [6, 25, 34], "17": 6, "04": 6, "42": 6, "224": 6, "tune": 6, "683": 6, "wa": 6, "next": 6, "geometri": [6, 12, 16, 34], "monoglym": [6, 34], "xyz": [6, 12, 14, 19], "optimize_geometri": 6, "core": [6, 9, 10, 11, 15, 17, 20, 25, 33], "calcfrommolfw": [6, 11, 13], "auto_load": [6, 34], "wf": [6, 34], "get_from_fil": [6, 14, 16, 19, 22], "gaussian_input_param": [6, 12, 13], "route_paramet": [6, 16, 19], "opt": [6, 11, 12, 14, 16, 19, 24], "none": [6, 10, 11, 12, 13, 14, 16, 19, 20, 21, 22, 24, 25], "save_to_fil": [6, 10, 12, 34], "save_to_db": [6, 12, 34], "add_wf": [6, 34], "get_fw": 6, "readi": 6, "fw_id": 6, "created_on": 6, "16t20": 6, "32": 6, "54": 6, "554404": 6, "updated_on": 6, "554716": 6, "state": [6, 12, 13, 16, 19], "calc_from_mol": [6, 13], "altern": 6, "web": 6, "gui": 6, "webgui": 6, "through": [6, 12, 21, 24, 27, 34], "ha": [6, 21], "multi": [6, 12], "ll": 6, "flag": 6, "prevent": 6, "too": 6, "went": 6, "determin": [6, 21, 25], "fail": [6, 12, 16], "rerun": 6, "id": [6, 12, 14, 19], "rerun_fw": 6, "input": [6, 9, 11, 12, 13, 16, 19, 21, 22, 24, 25, 31, 33, 34], "summari": [6, 12, 16, 31], "addition": [6, 16], "inchi": [6, 11, 12, 14, 19, 31], "criteria": [6, 10, 11, 12, 14, 19, 34], "db_util": [6, 9, 11], "get_db": [6, 11, 14, 20, 24], "retrieve_run": [6, 9, 11, 20], "c4h10o2": [6, 34], "c1": 6, "5": [6, 11, 14, 16, 19, 34], "6": [6, 14, 16, 19, 34], "h3": 6, "4h2": 6, "2h3": 6, "save": [6, 10, 12, 14, 21, 22, 24, 25, 31], "view": 6, "compass": 6, "appear": [6, 14], "task": [7, 12, 13, 14, 18, 21, 22, 23, 27], "firetask": [7, 9, 11, 13, 14, 16, 17, 20, 22, 23, 31], "A": [7, 8, 11, 12, 13, 14, 18, 21, 23, 24, 31], "sequenc": [7, 31], "under": [8, 28, 32, 34], "mit": 8, "copyright": 8, "stoni": 8, "brook": 8, "univers": 8, "permiss": 8, "herebi": 8, "grant": 8, "person": 8, "obtain": [8, 12, 21, 22, 25], "copi": [8, 12, 14], "associ": 8, "deal": 8, "restrict": 8, "right": 8, "distribut": [8, 21, 22, 27], "sublicens": 8, "sell": 8, "permit": 8, "whom": 8, "furnish": 8, "subject": 8, "condit": 8, "notic": 8, "shall": 8, "substanti": 8, "portion": 8, "THE": 8, "AS": 8, "warranti": 8, "OF": 8, "kind": 8, "express": 8, "OR": 8, "impli": 8, "BUT": 8, "NOT": 8, "TO": 8, "merchant": 8, "fit": [8, 34], "FOR": 8, "particular": 8, "purpos": [8, 14], "AND": 8, "noninfring": 8, "IN": 8, "NO": 8, "event": 8, "holder": 8, "BE": [8, 14, 16], "liabl": 8, "claim": 8, "damag": 8, "liabil": 8, "whether": [8, 10, 11, 12, 13, 14, 16, 21, 22, 24, 25], "action": 8, "contract": 8, "tort": 8, "otherwis": [8, 12, 14, 16, 19], "aris": 8, "WITH": 8, "common": [9, 13, 14, 16, 19, 22, 26, 34], "submodul": [9, 15, 26], "pubchemrunn": [9, 10], "cleanup": [9, 10, 14, 20, 24], "convert_sdf_to_mol": [9, 10], "download_sdf": [9, 10], "get_mol": [9, 10], "geo_transform": [9, 11, 13, 22], "parse_output": [9, 11, 13, 20, 22], "run_calc": [9, 11, 13], "write_input": [9, 11, 13, 20, 22], "break_mol": [9, 11], "dbdoc": [9, 11], "fw_util": [9, 11], "gout": [9, 11, 12], "metadata": [9, 11, 31], "misc": [9, 11], "mol": [9, 11, 12, 13, 16, 19, 21, 22, 25, 34], "rdkit": [9, 11, 16], "gaussiancalcdb": [9, 11, 14], "build_index": [9, 11, 20], "delete_molecul": [9, 11], "from_db_fil": [9, 11, 20], "insert_derived_mol": [9, 11], "insert_fg": [9, 11], "insert_molecul": [9, 11], "insert_properti": [9, 11], "insert_run": [9, 11, 20], "move_run": [9, 11], "query_molecul": [9, 11], "retrieve_doc": [9, 11], "retrieve_fg": [9, 11], "retrieve_molecul": [9, 11], "update_run": [9, 11], "nmr_from_md": [9, 17], "base_test": [9, 20], "custom_data_workflow": [9, 20], "electrolyte_wf": [9, 20], "esp_to_ff_dict_custom": [9, 20], "esp_to_ff_dict_funct": [9, 20], "liquid_wf_loc": [9, 20], "parmchk": [9, 20, 21], "prmtop": [9, 19, 20, 21, 22], "run_lammp": [9, 20, 22], "lammpssysdb": [9, 20], "delete_force_field": [9, 20], "insert_force_field": [9, 20], "insert_system": [9, 20], "query_force_field": [9, 20], "retrieve_force_field": [9, 20], "implement": [10, 31], "class": [10, 11, 12, 13, 16, 18, 20, 21, 22, 23, 24], "abbrevi": [10, 14], "working_dir": [10, 12, 13, 14, 16, 19, 21, 22, 24, 25], "wrapper": [10, 14, 21, 24], "str": [10, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25], "current": [10, 12, 13, 14, 16, 21, 22, 25, 34], "delet": [10, 11, 24, 31], "sdf": [10, 12], "fmt": [10, 12], "bool": [10, 11, 12, 13, 14, 16, 19, 21, 22, 24, 25], "identifi": [10, 12, 21], "pdb": [10, 12, 19], "intermedi": [10, 12, 24, 31], "attachfunctionalgroup": [11, 12], "run_task": [11, 12, 17, 18, 20, 21, 23], "breakmolecul": [11, 12, 13], "converttomoleculeobject": [11, 12], "linkmolecul": [11, 12], "processmoleculeinput": [11, 12, 13, 22], "retrievemoleculeobject": [11, 12], "bdetodb": [11, 12], "bindingenergytodb": [11, 12], "esptodb": [11, 12], "ipeatodb": [11, 12], "nmrtodb": [11, 12], "processrun": [11, 12, 13], "retrievegaussianoutput": [11, 12, 13], "rungaussiancustodian": [11, 12, 13, 14], "rungaussiandirect": [11, 12, 14], "rungaussianfak": [11, 12, 14], "writeinput": [11, 12, 13], "breakmolfw": [11, 13], "calcfromrunsdbfw": [11, 13], "common_task": [11, 13], "add_solvent_to_prop_dict": [11, 14], "bibtex_pars": [11, 12, 14, 16], "recursive_relative_to_absolute_path": [11, 14], "add_common_mod": [11, 14], "control_work": [11, 14], "get_list_fireworks_and_task": [11, 14], "modify_queue_paramet": [11, 14], "replace_runtask": [11, 14], "run_fake_gaussian": [11, 14], "process_run": [11, 12, 14, 20, 24], "handle_gaussian_input": [11, 14], "get_chem_schema": [11, 14], "get_job_nam": [11, 14], "get_mol_formula": [11, 14], "pass_gout_dict": [11, 14], "recursive_compare_dict": [11, 14], "recursive_signature_remov": [11, 14], "get_bond_order_str": [11, 14], "label_atom": [11, 14], "perform_local_opt": [11, 14], "process_mol": [11, 12, 13, 14, 16, 22, 25, 34], "calc_energi": [11, 14], "draw_rdkit_mol": [11, 14], "draw_rdkit_mol_with_highlighted_bond": [11, 14], "get_rdkit_mol": [11, 14], "bde": [11, 12, 14, 15, 31], "binding_energi": [11, 12, 15], "esp": [11, 12, 15, 19, 21, 22, 31, 33], "ip_ea": [11, 12, 15], "fals": [11, 12, 13, 14, 16, 20, 21, 22, 25], "kwarg": [11, 12, 13, 14, 16, 18, 19, 20, 21, 22, 23, 24, 25], "insert": [11, 12], "abstract": [11, 12, 18, 20, 21, 23], "background": [11, 20], "build": [11, 12, 14, 21, 31, 33], "classmethod": [11, 20], "admin": [11, 20], "derived_mol": 11, "update_dupl": [11, 12, 20], "deriv": [11, 12, 14, 19, 27, 31, 33], "derived_molecul": 11, "duplic": 11, "fg_file": 11, "collection_nam": 11, "property_dict": 11, "dict": [11, 12, 13, 14, 16, 18, 19, 21, 22, 23, 24, 25], "tupl": [11, 12, 13, 14, 16], "lookup": 11, "create_index": 11, "grun": 11, "new_collect": 11, "smile": [11, 14, 20, 24, 31], "basi": [11, 12, 14], "anoth": [11, 12], "select": [11, 34], "kei": [11, 12, 14, 16, 18, 21, 23, 24, 25], "chemsi": 11, "datafram": 11, "pd": 11, "functional_group": 11, "new_valu": 11, "job_typ": [11, 12], "phase": [11, 12, 14, 16], "block": [11, 31, 33], "polariz": 11, "freq": [11, 12, 14, 16, 19], "ga": [11, 12, 14, 16], "variou": [12, 27, 29, 31], "transform": 12, "arg": [12, 18, 21, 23], "firetaskbas": [12, 18, 21, 23], "attach": [12, 14, 16, 19], "fw_spec": [12, 14, 18, 21, 23], "func_grp": [12, 14, 19], "carboxyl": 12, "int": [12, 13, 14, 16, 19, 21, 25], "site": [12, 14, 16, 19], "taken": 12, "previou": [12, 13, 14, 21], "prioriti": 12, "given": [12, 14, 31], "latter": 12, "bond_ord": [12, 14, 16, 19], "bond": [12, 13, 14, 16, 19, 22, 24, 27, 31, 33], "length": [12, 16, 19, 27], "save_mol_fil": 12, "filenam": [12, 14, 22, 25], "formula": [12, 14, 16, 21, 22, 31], "spec": [12, 14, 18, 21, 23, 25], "fwaction": [12, 18, 21, 23], "come": [12, 18, 21, 23], "special": [12, 18, 21, 23], "_fw_env": [12, 18, 21, 23], "fworker": [12, 14, 18, 21, 23], "certain": [12, 14, 18, 21, 23, 34], "foo": [12, 18, 21, 23], "foo1": [12, 18, 21, 23], "foo2": [12, 18, 21, 23], "map": [12, 18, 21, 23, 24], "relev": [12, 16, 18, 19, 21, 23, 31], "write": [12, 13, 16, 18, 19, 21, 23, 25, 31], "across": [12, 18, 21, 23], "break": [12, 13, 16], "uniqu": [12, 13, 14, 16, 21, 22, 24], "fragment": [12, 13, 16], "term": 12, "assign": [12, 13, 14, 16, 24], "frequenc": [12, 13, 14, 16, 19, 34], "credit": 12, "samuel": 12, "blau": 12, "atom": [12, 13, 14, 16, 19, 21, 24, 27, 31, 34], "attempt": [12, 13, 16, 19, 21, 22, 25], "ref_charg": [12, 13, 16], "principl": [12, 13, 16, 27], "fragment_charg": [12, 13, 16], "ones": [12, 13, 14, 16], "neutral": [12, 16], "open_r": [12, 13, 16], "ring": [12, 13, 16], "guess": [12, 13], "opt_step": 12, "10000": 12, "opt_gaussian_input": [12, 14, 16, 19], "calc_frag": [12, 13], "freq_gaussian_input": [12, 14, 16, 19], "cart_coord": [12, 13, 16, 19], "cartesian": [12, 13, 16, 19], "coordin": [12, 13, 16, 19, 21, 33], "oxidation_st": [12, 13, 16, 19], "oxid": [12, 13, 16, 19], "spin": [12, 16, 19], "li": [12, 16], "children": [12, 16], "read": [12, 14, 21, 22, 25, 34], "mol_fil": 12, "mdl": 12, "sd": 12, "ml2": 12, "sy2": 12, "cml": 12, "mrv": 12, "gjf": 12, "g03": 12, "g09": 12, "inp": 12, "serial": 12, "process": [12, 13, 14, 16, 19, 21, 22, 24, 25, 31, 34], "link": [12, 14, 16, 19, 25, 31], "second": [12, 14, 16], "index1": 12, "index2": 12, "mol1": [12, 14, 19], "gaussianoutput": [12, 13, 14, 16, 19, 22, 25], "operation_typ": [12, 14, 19, 22], "besid": [12, 16, 31], "could": [12, 13, 16, 19, 22, 25], "from_fw_spec": 12, "local_opt": [12, 14], "force_field": [12, 14], "forc": [12, 14, 19, 21, 22, 24, 25, 27, 33, 34], "field": [12, 14, 19, 21, 22, 24, 25, 27, 33], "str_type": [12, 14], "get_from_str": [12, 14, 19], "smi": [12, 14], "openbabel": [12, 14, 16], "pars": [12, 13, 14, 21, 24, 27, 31], "enter": 12, "dissoci": [12, 16, 27, 31, 33], "energi": [12, 14, 16, 27, 31, 33], "principle_mol_kei": 12, "solvent_gaussian_input": [12, 14, 16, 19], "implicit": [12, 14, 16, 19], "solvent": [12, 14, 16, 19, 25], "model": [12, 14, 16, 19, 24, 31], "solvent_properti": [12, 14, 16, 19], "final": [12, 14, 16, 19, 31], "additional_prop_doc_field": [12, 34], "visual": [12, 14, 16], "bar": [12, 16], "plot": [12, 16, 31], "along": [12, 16], "2d": [12, 14, 16], "highlight": [12, 14, 16], "broken": [12, 16], "color": [12, 14, 16], "rgb": [12, 14], "black": [12, 14], "197": 12, "255": 12, "237": 12, "223": 12, "bind": [12, 16, 27, 33], "ev": [12, 16], "lead": [12, 31], "redox": [12, 16, 27, 33], "potenti": [12, 16, 27, 33, 34], "both": [12, 16, 21], "gibb": [12, 16], "num_electron": [12, 16], "electron": [12, 16, 27], "transfer": [12, 16, 31], "cation": [12, 16], "anion": [12, 16], "reduct": [12, 16], "involv": [12, 16], "thermodynam": [12, 16], "cycl": [12, 16], "singl": [12, 16, 21, 27, 31], "root_node_kei": 12, "root": 12, "pcet": [12, 16], "vertic": [12, 16], "ip": [12, 16], "ea": [12, 16], "electrode_potenti": [12, 16], "electrod": [12, 16], "absolut": [12, 14, 16], "commonli": [12, 16], "hydrogen": [12, 14, 16], "lithium": [12, 16], "magnesium": [12, 16], "metal": 12, "float": [12, 14, 16, 19, 21, 24, 25], "ref": [12, 16], "ref_bib_fil": 12, "dir": 12, "bibtexpars": 12, "gibbs_elec": [12, 16], "hartre": [12, 16], "gibbs_h": [12, 16], "actual": [12, 14], "itself": [12, 14], "input_paramet": [12, 14], "end": [12, 14, 24, 31], "easili": [12, 14], "gout_kei": [12, 16], "mod_spec": 12, "format_chk": [12, 34], "formchk_cmd": 12, "gaussianinput": 12, "run_id": 12, "5e3737d9da0b1cbbd5d556f7": [12, 14], "tag": [12, 13, 22, 25, 34], "gaussian_cmd": 12, "stderr_fil": 12, "direct": [12, 16, 31], "standard": 12, "better_guess": 12, "backup": 12, "orig": 12, "scf_max_cycl": 12, "maximum": [12, 14], "scf": 12, "100": 12, "opt_max_cycl": 12, "max_error": 12, "give": 12, "lower_funct": 12, "lower": 12, "level": [12, 14], "better": 12, "again": 12, "higher": 12, "lower_basis_set": 12, "less": [12, 14], "expens": 12, "prefix": 12, "seri": 12, "tar": 12, "gz": 12, "suffix": 12, "renam": 12, "check_converg": 12, "converg": [12, 34], "iter": [12, 14], "wall_tim": 12, "wall": [12, 31], "walltimeerrorhandl": 12, "restart": [12, 25], "hit": 12, "buffer_tim": 12, "buffer": 12, "remain": 12, "cancel": 12, "becaus": 12, "own": [12, 33], "longer": 12, "300": 12, "max_wall_time_correct": 12, "fake": [12, 14, 21], "ref_dir": [12, 14, 21, 24], "toler": [12, 14], "comparison": [12, 14], "0001": 12, "gaussian_input": [12, 14, 16, 19], "written": [12, 13, 21, 25], "graph": [12, 31], "isomorph": 12, "ignor": [12, 16, 21], "avail": [12, 16, 25, 33], "symbol": [12, 13], "mol_operation_typ": [13, 14, 16, 19, 22, 34], "get_from_mol": [13, 14, 16, 19], "parent": [13, 16, 22], "unknown": [13, 22, 25], "easi": [13, 14, 22], "__init__": [13, 22], "z": [13, 16, 19], "matrix": [13, 16, 19], "calc_from_runs_db": 13, "input_db": [14, 24], "helper": [14, 22], "clean": [14, 21, 24], "prop_dict": 14, "tetrahydrofuran": [14, 16, 19], "ep": [14, 16, 19], "12": [14, 16, 19, 25, 34], "bib_fil": 14, "rel": [14, 16], "els": 14, "operand": 14, "recurs": 14, "powerup": 14, "fw_mod": 14, "modif": 14, "appli": [14, 16, 24], "docstr": 14, "firework_substr": 14, "task_substr": 14, "substr": 14, "exclud": 14, "consist": [14, 16, 31], "firework_index": 14, "task_index": 14, "ntasks_per_nod": 14, "other_paramet": 14, "cpu": 14, "memori": 14, "partit": 14, "pre": 14, "queueadapt": 14, "remove_custodian": 14, "additional_param": 14, "rungaussian": 14, "vice": 14, "versa": 14, "use_custodian": 14, "origin": 14, "home": 14, "get_from_gout": [14, 19], "io": [14, 19, 21, 25], "get_from_gout_fil": [14, 19], "get_from_run_dict": [14, 19], "get_from_run_id": [14, 19], "dtabas": 14, "get_from_run_queri": [14, 19], "coccoc": 14, "b3lyp": [14, 16, 19], "31": 14, "miss": 14, "33": 14, "epsinf": 14, "69": 14, "reformat": 14, "schema": 14, "label": [14, 16, 19, 21, 22, 24, 25], "monitor": 14, "alphabet": 14, "miscellan": 14, "met": 14, "lack": 14, "imaginari": 14, "dict1": 14, "dict2": 14, "dict1_nam": 14, "dict2_nam": 14, "compar": 14, "messag": 14, "intern": 14, "nest": 14, "top": [14, 27], "d": [14, 16, 19, 24], "signatur": 14, "unspecifi": 14, "tripl": 14, "aromat": 14, "know": 14, "uff": 14, "200": 14, "ghemic": 14, "mmff94": 14, "openabel": [14, 19], "get_from_mol_db": [14, 19], "func": [14, 19], "get_from_pubchem": [14, 19, 34], "derive_molecul": [14, 19], "base_mol": [14, 19], "func_group_nam": [14, 19], "link_molecul": [14, 19], "mol_inchi": [14, 19], "rdkit_mol": 14, "maxit": 14, "png": [14, 34], "draw": 14, "imag": 14, "11": [14, 34], "13": [14, 34], "randomli": 14, "sanit": 14, "remove_h": 14, "rdmol": 14, "convers": 14, "org": [14, 21], "get_bd": [15, 16], "get_binding_energi": [15, 16], "gouttypeerror": [15, 16], "common_fw": [15, 16], "get_esp_charg": [15, 16, 34], "branch": [15, 16], "create_firework": [15, 16], "get_ip_ea": [15, 16], "get_nmr_tensor": [15, 16], "bde_calcul": 16, "skip": [16, 19, 33, 34], "being": [16, 24], "proce": 16, "caus": 16, "encount": 16, "basis_set": [16, 19], "31g": [16, 19], "link0_paramet": [16, 19], "chk": [16, 19], "mem": [16, 19], "45gb": [16, 19], "nprocshar": [16, 19], "applic": [16, 27], "throw": 16, "warn": 16, "binding_energy_calcul": 16, "msg": 16, "thrown": 16, "process_mol_func": 16, "mol_nam": 16, "dir_head": 16, "check_result": 16, "differenti": 16, "head": 16, "vari": 16, "electrostat": [16, 31, 33, 34], "partial": [16, 21, 31, 33, 34], "esp_charges_calcul": 16, "esp_gaussian_input": [16, 19], "h2o": 16, "water": 16, "branch_cation_from_anion": 16, "h_index": 16, "tree": 16, "leaf": 16, "last": [16, 31], "Not": 16, "instanti": [16, 21], "child": 16, "final_energi": 16, "branching_st": 16, "branching_phas": 16, "num_of_electron": 16, "single_step": 16, "001378786": 16, "41816": 16, "ip_ea_calcul": 16, "ref_skip": 16, "ioniz": 16, "affin": 16, "adiabat": 16, "sequenti": [16, 31], "therebi": [16, 33], "proton": 16, "coupl": [16, 27], "equal": 16, "40": 16, "li_pot": 16, "bib": 16, "data_dir": 16, "overwrit": 16, "three": 16, "nuclear": [16, 19, 27], "magnet": [16, 19, 27], "reson": [16, 19, 27], "nmr_tensor_calcul": 16, "nmr_gaussian_input": [16, 19], "tensor": [16, 27], "nmrfrommd": [17, 18], "run_hybrid_calc": [17, 19], "get_solvation_structures_nmr": [17, 19], "mol_typ": 19, "mol_data": 19, "box_data": [19, 25], "ff_method": 19, "ff_param": 19, "mixture_typ": 19, "hybrid_calcul": 19, "box_data_typ": [19, 25], "cubic": [19, 21, 25], "data_file_nam": [19, 25], "mixtur": [19, 25, 33], "analysis_list": [19, 21, 25], "analysis_set": [19, 25], "extract": [19, 21, 27, 33], "solvat": [19, 27, 29, 33], "opt_esp_gaussian_input": 19, "freq_esp_gaussian_input": 19, "opt_nmr_gaussian_input": 19, "freq_nmr_gaussian_input": 19, "esp_solvent_gaussian_input": 19, "esp_solvent_properti": 19, "nmr_solvent_gaussian_input": 19, "nmr_solvent_properti": 19, "categor": 19, "around": 19, "particl": [19, 21], "interest": [19, 31], "highest": 19, "occurr": 19, "compos": 19, "concentr": [19, 21, 25, 27], "molar": 19, "molarity_i": 19, "molarity_f": 19, "weight": 19, "molar_weight": 19, "arrai": [19, 24, 25], "lammpsbox": [19, 25], "box": [19, 21, 24, 25], "get_from_esp": [19, 22], "get_from_prmtop": [19, 22], "get_from_dict": [19, 22], "get_from_opl": [19, 22], "what": 19, "empti": [19, 21, 22], "detect": [19, 27], "begin": 19, "mg": 19, "mass": [19, 21, 22, 24], "ordereddict": [19, 24], "305": 19, "nonbond": [19, 22, 24], "8947000005260684": 19, "412252647723565": 19, "angl": [19, 22, 24], "dihedr": [19, 22, 24], "improp": [19, 22, 24], "topologi": [19, 22, 24], "asarrai": 19, "sictionari": 19, "optioanl": 19, "rectangular": [19, 25], "finish": 19, "diffus": [19, 21, 22, 25, 27, 33], "rdf": [19, 21, 22, 25, 33], "cn": [19, 21, 25], "recip": [19, 25, 31], "recipe_set": [19, 25], "calccn": [20, 21], "calcdiff": [20, 21, 22], "extractclust": [20, 21], "getrdf": [20, 21, 22], "processanalysi": [20, 21], "processprmtop": [20, 21, 22, 23], "runantechamb": [20, 21, 22], "runlammpsdirect": [20, 21, 22], "runlammpsfak": [20, 21], "runmaestro": [20, 21, 22], "runparmchk": [20, 21, 22], "runtleap": [20, 21, 22], "labelffdict": [20, 21, 22], "labelffdictfromdb": [20, 21, 22], "writecontrolfil": [20, 21, 22], "writedatafil": [20, 21], "writetleapscript": [20, 21, 22], "getffdictfw": [20, 22, 25], "runanalysisfw": [20, 22], "runlammpsfw": [20, 22], "ambertools_task": [20, 22], "printfw": [20, 23], "maestrorunn": [20, 21, 24], "convert_ff_log_to_json": [20, 24], "convert_mol_to_ma": [20, 24], "get_ff_log": [20, 24], "get_opls_param": [20, 24], "add_ff_labels_to_badi_list": [20, 24], "add_ff_labels_to_dict": [20, 24], "lammps_mass_to_el": [20, 24], "process_ff_doc": [20, 24], "run_fake_lammp": [20, 24], "lammps_analysis_fw": [20, 25], "lammps_data_fw": [20, 25], "lammps_run_fw": [20, 25], "lammps_workflow": [20, 25], "doi": [20, 21, 24], "parameter_dict": [20, 24], "lmp_run": 20, "sys_doc": 20, "_id": 20, "cn_set": 21, "calc_atomic_cn": 21, "calc_molecular_cn": 21, "rdf_cn": 21, "coeffici": [21, 22, 27, 33], "displac": [21, 34], "msd": 21, "einstein": 21, "relat": [21, 27], "diff_set": 21, "might": 21, "timestep": 21, "unit": [21, 24], "msd_method": 21, "from_dump": 21, "from_log": 21, "num_mol": 21, "num_atoms_per_mol": 21, "file_pattern": 21, "pattern": 21, "nvt": [21, 25], "avg_interv": 21, "individu": [21, 27, 33], "averag": 21, "diff_dist": 21, "outputs_dir": 21, "cutoff": 21, "radiu": 21, "separ": 21, "frame": 21, "cluster_set": 21, "get_clust": 21, "get_unique_configur": 21, "cluster_analysi": 21, "radial": [21, 22, 27], "rdf_set": 21, "calc_atomic_rdf": 21, "calc_molecular_rdf": 21, "save_analysis_to_db": 21, "save_analysis_to_fil": 21, "lammpsdatawrapp": [21, 25], "prmtop_path": 21, "try": [21, 24], "prmtop_filenam": 21, "prmtop_dir": 21, "unique_molecule_nam": 21, "system_force_field_dict": 21, "Will": 21, "digit": 21, "save_ff_to_db": [21, 22, 25], "save_ff_to_fil": [21, 22], "ff_filenam": [21, 22], "intent": 21, "ambermd": 21, "php": 21, "input_filename_a": 21, "input_file_typ": 21, "gesp": 21, "output_filename_a": 21, "output_file_typ": 21, "resp": 21, "antechamber_cmd": 21, "control_filenam": [21, 24], "lammpsin": 21, "lammps_cmd": 21, "net_ntask": 21, "processor": 21, "per": 21, "www": [21, 24], "maestro_cleanup": 21, "frcmod": 21, "input_filename_p": 21, "output_filename_p": 21, "parmchk_cmd": 21, "script_filenam": 21, "tleap_cmd": 21, "prev_calc_molecul": 21, "unlabeled_dict": 21, "ff_file": 21, "filter": [21, 22], "templat": [21, 25, 27], "calc": 21, "save_runs_to_db": [21, 25], "template_filenam": [21, 24, 25], "template_str": 21, "template_dir": 21, "control_set": [21, 24], "save_runs_to_fil": [21, 25], "lammpsin_kei": 21, "run_doc": 21, "bulk": 21, "lammpsdata": 21, "data_filenam": [21, 25], "lammps_data": 21, "lammps_data_wrapp": 21, "getforcefield": 21, "system_mixture_data": 21, "system_box_data": 21, "ndarrai": 21, "system_box_data_typ": 21, "position_se": 21, "seed": 21, "random": 21, "posit": 21, "indirectli": 21, "150": 21, "system_mixture_data_typ": 21, "scale_charg": 21, "non": 21, "zero": 21, "net": 21, "charge_scaling_factor": 21, "factor": 21, "inpcrd": 21, "script_str": 21, "gaff_tleap": 21, "tleap_set": 21, "get_ff_dict": 22, "pymatgen_molecul": 22, "atom_label": 22, "atomtype_mass": 22, "nonbond_param": 22, "bond_param": 22, "angle_param": 22, "dihedral_param": 22, "improper_param": 22, "improper_topologi": 22, "get_from_db": 22, "md_properti": 22, "run_analysi": 22, "control_fil": 22, "save_run_to_db": 22, "save_run_to_fil": 22, "modspec": 23, "opls_2005": 24, "schronding": 24, "bank": 24, "j": 24, "l": 24, "beard": 24, "h": [24, 34], "cao": 24, "cho": 24, "damm": 24, "farid": 24, "felt": 24, "k": 24, "halgren": 24, "mainz": 24, "mapl": 24, "murphi": 24, "philipp": 24, "repaski": 24, "p": 24, "zhang": 24, "bern": 24, "b": 24, "friesner": 24, "gallicchio": 24, "levi": 24, "integr": [24, 27], "impact": 24, "comp": 24, "chem": 24, "26": 24, "1752": 24, "mmshare": 24, "vversion": 24, "f14": 24, "freemaestro": 24, "suites2022": 24, "kb": 24, "1842": 24, "mae": 24, "1278": 24, "ff_list": 24, "extra": 24, "badi": 24, "ff_dict": 24, "coeff": 24, "pmg": 24, "x1": 24, "x2": 24, "x3": 24, "x4": 24, "lammps_mass": 24, "nmol": 24, "links_dict": 25, "system_species_data": 25, "system_mixture_typ": 25, "molecule_operation_typ": 25, "ff_param_method": 25, "ff_param_data": 25, "regard": 25, "mol_mixture_typ": 25, "mixture_data": 25, "emin": 25, "emin_gaff": 25, "npt": 25, "melt": 25, "quench": 25, "restart_finalnam": 25, "restart_filenam": 25, "restart_final_filenam": 25, "temperature_initi": 25, "temperature_fin": 25, "2000000": 25, "melt_500k": 25, "data_final_filenam": 25, "298": 25, "3000000": 25, "quench_298k": 25, "5000000": 25, "nvt_5n": 25, "recipe_qadapt": 25, "10": [25, 34], "48": 25, "init_spec": 25, "lammps_recip": 25, "qadapter_run_lammps_spec": 25, "content": [26, 34], "informat": 27, "relationship": [27, 31], "aim": 27, "acceler": 27, "discoveri": 27, "deploy": 27, "seamlessli": 27, "techniqu": 27, "motiv": 27, "genom": 27, "mgi": 27, "develop": 27, "hous": 27, "analyz": [27, 31], "underli": 27, "submiss": 27, "analyt": 27, "creation": 27, "maintain": [27, 34], "proven": 27, "reproduc": 27, "inevit": 27, "fly": 27, "respons": 27, "reli": 27, "human": 27, "intuit": 27, "extens": 27, "experi": 27, "significantli": 27, "improv": 27, "rate": 27, "elimin": 27, "intervent": 27, "flexibl": 27, "ensembl": 27, "viscos": 27, "conduct": 27, "critic": 27, "understand": 27, "inter": 27, "intra": 27, "interact": 27, "biologi": 27, "seamless": 27, "enabl": 27, "flow": 27, "explor": 27, "wide": 27, "temperatur": 27, "pressur": 27, "infeas": 27, "experiment": 27, "challeng": 27, "manual": 27, "hundr": 27, "thousand": 27, "accur": 27, "crucial": 27, "reliabl": 27, "energet": 27, "primarili": 27, "construct": [28, 32, 34], "workshop": 29, "school": 29, "student": 29, "jupyt": 29, "notebook": 29, "sampl": 29, "fulli": 29, "scientif": 31, "descript": 31, "procedur": 31, "desir": 31, "rang": 31, "post": 31, "encod": 31, "acycl": 31, "chain": 31, "shown": 31, "goal": 31, "simplifi": 31, "report": 31, "took": 31, "summar": 31, "raw": 31, "diagram": [31, 34], "alwai": 31, "juli": 33, "compon": 33, "stabl": 33, "One": 33, "reus": 33, "merz": 34, "singh": 34, "kollman": 34, "scheme": 34, "mark": 34, "dash": 34, "border": 34, "_": 34, "mispr_tutori": 34, "esp_tutori": 34, "And": 34, "subdirectori": 34, "figur": 34, "cours": 34, "374646": 34, "373831": 34, "132166": 34, "132716": 34, "034284": 34, "031733": 34, "033853": 34, "8": 34, "034024": 34, "9": 34, "034218": 34, "034388": 34, "070724": 34, "03474": 34, "03438": 34, "034621": 34, "071656": 34, "16": 34, "034974": 34}, "objects": {"": [[9, 0, 0, 1, "mispr", ""]], "mispr": [[10, 0, 0, 1, "common", ""], [11, 0, 0, 1, "gaussian", ""], [17, 0, 0, 1, "hybrid", ""], [20, 0, 0, 1, "lammps", ""]], "mispr.common": [[10, 0, 0, 1, "pubchem", ""]], "mispr.common.pubchem": [[10, 1, 1, 0, "PubChemRunner", "Bases: object"]], "mispr.common.pubchem.PubChemRunner.__init__": [[10, 2, 2, 0, "abbreviation", "Abbreviation to be used when saving molecule file."], [10, 2, 2, 0, "working_dir", "Working directory for saving the molecule file in; will use the current working directory if not specified."]], "mispr.common.pubchem.PubChemRunner": [[10, 3, 1, 0, "cleanup", "Delete the sdf file downloaded from PubChem."], [10, 3, 1, 0, "convert_sdf_to_mol", "Convert an SDF file to a pymatgen Molecule object."], [10, 3, 1, 0, "download_sdf", "Download an SDF file from PubChem using a common name for the molecule as an identifier."], [10, 3, 1, 0, "get_mol", "Wrapper function that searches for a molecule in the PubChem database, downloads it in the form of an SDF file, and converts the file to a pymatgen Molecule object."]], "mispr.common.pubchem.PubChemRunner.convert_sdf_to_mol": [[10, 2, 2, 0, "fmt", "Molecule file format if save_to_file is True."], [10, 2, 2, 0, "save_to_file", "Whether to save the Molecule object to a file."]], "mispr.common.pubchem.PubChemRunner.download_sdf": [[10, 2, 2, 0, "name", "Name of the molecule to use for searching PubChem."]], "mispr.common.pubchem.PubChemRunner.get_mol": [[10, 2, 2, 0, "cleanup", "Whether to remove the intermediate sdf file."], [10, 2, 2, 0, "fmt", "Molecule file format if save_to_file is True; defaults to \"pdb\"."], [10, 2, 2, 0, "name", "Name of the molecule to use for searching PubChem."], [10, 2, 2, 0, "save_to_file", "Whether to save the Molecule object to a file. Defaults to True."]], "mispr.gaussian": [[11, 0, 0, 1, "database", ""], [11, 0, 0, 1, "defaults", ""], [12, 0, 0, 1, "firetasks", ""], [13, 0, 0, 1, "fireworks", ""], [14, 0, 0, 1, "utilities", ""], [15, 0, 0, 1, "workflows", ""]], "mispr.gaussian.database": [[11, 1, 1, 0, "GaussianCalcDb", "Bases: object"]], "mispr.gaussian.database.GaussianCalcDb": [[11, 3, 1, 0, "build_indexes", "Build indexes for the database."], [11, 3, 1, 0, "delete_molecule", "Delete a molecule from the molecules collection."], [11, 3, 1, 0, "from_db_file", "Create a new database object from a database file."], [11, 3, 1, 0, "insert_derived_mol", "Insert a derived molecule into the derived_molecules collection."], [11, 3, 1, 0, "insert_fg", "Insert functional groups into their collection using a json file. The file can contain one or more functional groups."], [11, 3, 1, 0, "insert_molecule", "Insert a molecule into the molecules collection."], [11, 3, 1, 0, "insert_property", "Insert a document into a property collection in the database."], [11, 3, 1, 0, "insert_run", "Insert a Gaussian run into the runs collection."], [11, 3, 1, 0, "move_runs", "Move documents from the runs collection to another collection."], [11, 3, 1, 0, "query_molecules", "Query the molecules collection."], [11, 3, 1, 0, "retrieve_doc", "Retrieve a document from any collection of the database."], [11, 3, 1, 0, "retrieve_fg", "Retrieve a functional group from the functional_groups collection."], [11, 3, 1, 0, "retrieve_molecule", "Retrieve a molecule from the molecules collection."], [11, 3, 1, 0, "retrieve_run", "Retrieve a run from the runs collection."], [11, 3, 1, 0, "update_run", "Update a document in the runs collection. If multiple documents match the query criteria, will select the first one."]], "mispr.gaussian.database.GaussianCalcDb.build_indexes": [[11, 2, 2, 0, "background", "If True, this index should be created."]], "mispr.gaussian.database.GaussianCalcDb.delete_molecule": [[11, 2, 2, 0, "inchi", "The inchi representation of the molecule to delete."]], "mispr.gaussian.database.GaussianCalcDb.from_db_file": [[11, 2, 2, 0, "admin", "Whether to use admin credentials; defaults to True."], [11, 2, 2, 0, "db_file", "The path to the database file."]], "mispr.gaussian.database.GaussianCalcDb.insert_derived_mol": [[11, 2, 2, 0, "derived_mol", "pymatgen.Molecule object."], [11, 2, 2, 0, "update_duplicates", "Whether to update duplicates if the molecule already exists."]], "mispr.gaussian.database.GaussianCalcDb.insert_fg": [[11, 2, 2, 0, "fg_file", "The path to the json file."]], "mispr.gaussian.database.GaussianCalcDb.insert_molecule": [[11, 2, 2, 0, "mol", "A pymatgen Molecule object to insert."], [11, 2, 2, 0, "update_duplicates", "If True, update the existing molecule in the db with the new one. Defaults to False."]], "mispr.gaussian.database.GaussianCalcDb.insert_property": [[11, 2, 2, 0, "collection_name", "The name of the collection to insert the property into; e.g. bde, binding_energy, etc."], [11, 2, 2, 0, "index", "The indexes to use for fast lookup."], [11, 2, 2, 0, "kwargs", "Additional kwargs to pass to pymongo.collection.create_index."], [11, 2, 2, 0, "property_dict", "The property dictionary to insert."]], "mispr.gaussian.database.GaussianCalcDb.insert_run": [[11, 2, 2, 0, "grun", "A dictionary containing the Gaussian run."]], "mispr.gaussian.database.GaussianCalcDb.move_runs": [[11, 2, 2, 0, "basis", "The name of the basis set."], [11, 2, 2, 0, "functional", "The name of the density functional."], [11, 2, 2, 0, "inchi", "The inchi representation of the molecule."], [11, 2, 2, 0, "kwargs", "Other kwargs that can be used to query the collection."], [11, 2, 2, 0, "new_collection", "The name of the collection to move the runs to."], [11, 2, 2, 0, "smiles", "The smiles representation of the molecule."]], "mispr.gaussian.database.GaussianCalcDb.query_molecules": [[11, 2, 2, 0, "query", "A query document that selects which documents to include in the result set; e.g. keys can be inchi, smiles, chemsys, etc."]], "mispr.gaussian.database.GaussianCalcDb.retrieve_doc": [[11, 2, 2, 0, "basis", "The name of the basis set."], [11, 2, 2, 0, "collection_name", "The name of the collection, e.g. bde, molecules, runs, etc."], [11, 2, 2, 0, "functional", "The name of the density functional."], [11, 2, 2, 0, "inchi", "The inchi representation of the molecule."], [11, 2, 2, 0, "kwargs", "Other kwargs that can be used to query the collection."], [11, 2, 2, 0, "smiles", "The smiles representation of the molecule."]], "mispr.gaussian.database.GaussianCalcDb.retrieve_fg": [[11, 2, 2, 0, "name", "The name of the functional group to retrieve."]], "mispr.gaussian.database.GaussianCalcDb.retrieve_molecule": [[11, 2, 2, 0, "inchi", "The inchi representation of the molecule."]], "mispr.gaussian.database.GaussianCalcDb.retrieve_run": [[11, 2, 2, 0, "basis", "The name of the basis set."], [11, 2, 2, 0, "functional", "The name of the density functional."], [11, 2, 2, 0, "inchi", "The inchi representation of the molecule."], [11, 2, 2, 0, "kwargs", "Other kwargs that can be used to query the collection."], [11, 2, 2, 0, "smiles", "The smiles representation of the molecule."]], "mispr.gaussian.database.GaussianCalcDb.update_run": [[11, 2, 2, 0, "basis", "The name of the basis set."], [11, 2, 2, 0, "functional", "The name of the density functional."], [11, 2, 2, 0, "inchi", "The inchi representation of the molecule."], [11, 2, 2, 0, "job_type", "The type of job, e.g. \"opt\", \"freq\"."], [11, 2, 2, 0, "kwargs", "Other kwargs that can be used to query the collection."], [11, 2, 2, 0, "new_values", "The new output values to update the document with, e.g."], [11, 2, 2, 0, "phase", "The phase of the job, e.g. \"gas\", \"solution\"."], [11, 2, 2, 0, "smiles", "The smiles representation of the molecule."]], "mispr.gaussian.firetasks": [[12, 0, 0, 1, "geo_transformation", ""], [12, 0, 0, 1, "parse_outputs", ""], [12, 0, 0, 1, "run_calc", ""], [12, 0, 0, 1, "write_inputs", ""]], "mispr.gaussian.firetasks.geo_transformation": [[12, 1, 1, 0, "AttachFunctionalGroup", "Bases: FiretaskBase"], [12, 1, 1, 0, "BreakMolecule", "Bases: FiretaskBase"], [12, 1, 1, 0, "ConvertToMoleculeObject", "Bases: FiretaskBase"], [12, 1, 1, 0, "LinkMolecules", "Bases: FiretaskBase"], [12, 1, 1, 0, "ProcessMoleculeInput", "Bases: FiretaskBase"], [12, 1, 1, 0, "RetrieveMoleculeObject", "Bases: FiretaskBase"]], "mispr.gaussian.firetasks.geo_transformation.AttachFunctionalGroup": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.AttachFunctionalGroup.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.geo_transformation.BreakMolecule": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.BreakMolecule.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.geo_transformation.ConvertToMoleculeObject": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.ConvertToMoleculeObject.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.geo_transformation.LinkMolecules": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.LinkMolecules.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.ProcessMoleculeInput.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.geo_transformation.RetrieveMoleculeObject": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.geo_transformation.RetrieveMoleculeObject.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs": [[12, 1, 1, 0, "BDEtoDB", "Bases: FiretaskBase"], [12, 1, 1, 0, "BindingEnergytoDB", "Bases: FiretaskBase"], [12, 1, 1, 0, "ESPtoDB", "Bases: FiretaskBase"], [12, 1, 1, 0, "IPEAtoDB", "Bases: FiretaskBase"], [12, 1, 1, 0, "NMRtoDB", "Bases: FiretaskBase"], [12, 1, 1, 0, "ProcessRun", "Bases: FiretaskBase"], [12, 1, 1, 0, "RetrieveGaussianOutput", "Bases: FiretaskBase"]], "mispr.gaussian.firetasks.parse_outputs.BDEtoDB": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.BDEtoDB.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.BindingEnergytoDB": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.BindingEnergytoDB.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.ESPtoDB": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.ESPtoDB.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.IPEAtoDB": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.IPEAtoDB.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.NMRtoDB": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.NMRtoDB.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.ProcessRun": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.ProcessRun.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.parse_outputs.RetrieveGaussianOutput": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.parse_outputs.RetrieveGaussianOutput.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.run_calc": [[12, 1, 1, 0, "RunGaussianCustodian", "Bases: FiretaskBase"], [12, 1, 1, 0, "RunGaussianDirect", "Bases: FiretaskBase"], [12, 1, 1, 0, "RunGaussianFake", "Bases: FiretaskBase"]], "mispr.gaussian.firetasks.run_calc.RunGaussianCustodian": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.run_calc.RunGaussianCustodian.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.run_calc.RunGaussianDirect": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.run_calc.RunGaussianDirect.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.run_calc.RunGaussianFake": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.run_calc.RunGaussianFake.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.firetasks.write_inputs": [[12, 1, 1, 0, "WriteInput", "Bases: FiretaskBase"]], "mispr.gaussian.firetasks.write_inputs.WriteInput": [[12, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.gaussian.firetasks.write_inputs.WriteInput.run_task": [[12, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.gaussian.fireworks": [[13, 0, 0, 1, "break_mol", ""], [13, 0, 0, 1, "core", ""]], "mispr.gaussian.fireworks.break_mol": [[13, 1, 1, 0, "BreakMolFW", "Bases: Firework"]], "mispr.gaussian.fireworks.break_mol.BreakMolFW.__init__": [[13, 2, 2, 0, "bonds", "List of tuples of the bonds to break; e.g. [(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between atoms 1 and 2; if none is specified, will attempt to break all bonds."], [13, 2, 2, 0, "calc_frags", "Whether to create optimization and frequency Fireworks for the generated fragments. Defaults to True."], [13, 2, 2, 0, "db", "Database credentials."], [13, 2, 2, 0, "fragment_charges", "List of charges to assign to the fragments in addition to the ones already assigned; refer to mispr.gaussian.firetasks.geo_transformation.BreakMolecule for more details."], [13, 2, 2, 0, "kwargs", "Other kwargs that are passed to:"], [13, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [13, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations. Defaults to get_from_mol."], [13, 2, 2, 0, "name", "Name of the Firework. Defaults to break_mol."], [13, 2, 2, 0, "open_rings", "Whether to open rings; if set to True, will perform local optimization to get a good initial guess for the structure. Defaults to False."], [13, 2, 2, 0, "parents", "List of parent FWs this FW depends on."], [13, 2, 2, 0, "ref_charge", "Charge on the principle molecule. Defaults to 0."], [13, 2, 2, 0, "tag", "Tag for the calculation; the provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [13, 2, 2, 0, "working_dir", "Working directory for the calculation; will use the current working directory if not specified."]], "mispr.gaussian.fireworks.core": [[13, 1, 1, 0, "CalcFromMolFW", "Bases: Firework"], [13, 1, 1, 0, "CalcFromRunsDBFW", "Bases: Firework"], [13, 4, 1, 0, "common_tasks", "Define a list of common tasks for Gaussian fireworks, i.e. writing an input file, running the calculation, and parsing the output."]], "mispr.gaussian.fireworks.core.CalcFromMolFW.__init__": [[13, 2, 2, 0, "cart_coords", "Whether the coordinates are cartesian or z-matrix. Defaults to True."], [13, 2, 2, 0, "db", "Database credentials; could be provided as the path to the db.json file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [13, 2, 2, 0, "gaussian_input_params", "Dictionary of parameters to be used in the Gaussian input file."], [13, 2, 2, 0, "input_file", "Name of the Gaussian input file to be created; defaults to \"mol.com\"."], [13, 2, 2, 0, "kwargs", "other kwargs that are passed to:"], [13, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [13, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations. Defaults to get_from_mol."], [13, 2, 2, 0, "name", "Name of the Firework. Defaults to calc_from_mol."], [13, 2, 2, 0, "output_file", "Name of the Gaussian output file to be output; defaults to \"mol.out\"."], [13, 2, 2, 0, "oxidation_states", "List of oxidation states for each atom; defaults to None."], [13, 2, 2, 0, "parents", "List of parent FWs this FW depends on."], [13, 2, 2, 0, "tag", "Tag for the calculation; the provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [13, 2, 2, 0, "working_dir", "Working directory for the calculation; defaults to the current directory."]], "mispr.gaussian.fireworks.core.CalcFromRunsDBFW.__init__": [[13, 2, 2, 0, "cart_coords", "Whether the coordinates are cartesian or z-matrix. Defaults to True."], [13, 2, 2, 0, "db", "Database credentials; could be provided as the path to the db.json file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [13, 2, 2, 0, "gaussian_input_params", "Dictionary of parameters to be used in the Gaussian input file."], [13, 2, 2, 0, "input_file", "Name of the Gaussian input file to be created; defaults to \"mol.com\"."], [13, 2, 2, 0, "kwargs", "other kwargs that are passed to:"], [13, 2, 2, 0, "name", "Name of the Firework. Defaults to calc_from_runs_db."], [13, 2, 2, 0, "output_file", "Name of the Gaussian output file to be output; defaults to \"mol.out\"."], [13, 2, 2, 0, "parents", "List of parent FWs this FW depends on."], [13, 2, 2, 0, "tag", "Tag for the calculation; the provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [13, 2, 2, 0, "working_dir", "Working directory for the calculation; defaults to the current directory."]], "mispr.gaussian.fireworks.core.common_tasks": [[13, 2, 2, 0, "cart_coords", "Whether to write cartesian coordinates or not; default is True."], [13, 2, 2, 0, "db", "Database credentials to store the run; could be provided as the path to the db.json file or in the form of a dictionary."], [13, 2, 2, 0, "gaussian_input_params", "A dictionary of parameters to be used in creating the Gaussian input file."], [13, 2, 2, 0, "input_file", "Name of the input file to be written."], [13, 2, 2, 0, "kwargs", "other kwargs that are passed to:"], [13, 2, 2, 0, "output_file", "name of the Gaussian output file"], [13, 2, 2, 0, "oxidation_states", "A dictionary of element symbols and their oxidation states used in setting the charge on the molecule."]], "mispr.gaussian.utilities": [[14, 0, 0, 1, "db_utilities", ""], [14, 0, 0, 1, "dbdoc", ""], [14, 0, 0, 1, "files", ""], [14, 0, 0, 1, "fw_utilities", ""], [14, 0, 0, 1, "gout", ""], [14, 0, 0, 1, "inputs", ""], [14, 0, 0, 1, "metadata", ""], [14, 0, 0, 1, "misc", ""], [14, 0, 0, 1, "mol", ""], [14, 0, 0, 1, "rdkit", ""]], "mispr.gaussian.utilities.db_utilities": [[14, 4, 1, 0, "get_db", "Helper function to create a GaussianCalcDb instance from a file or a dict."]], "mispr.gaussian.utilities.db_utilities.get_db": [[14, 2, 2, 0, "input_db", "Path to db file or a dict containing db info."]], "mispr.gaussian.utilities.dbdoc": [[14, 4, 1, 0, "add_solvent_to_prop_dict", "Add solvent properties to a property dictionary (e.g. BDE, BE, etc.)."]], "mispr.gaussian.utilities.dbdoc.add_solvent_to_prop_dict": [[14, 2, 2, 0, "prop_dict", "Property dictionary."], [14, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model used in the Gaussian calculations, e.g. \"(Solvent=TetraHydroFuran)\"."], [14, 2, 2, 0, "solvent_properties", "Additional solvent input parameters used in the Gaussian calculations; e.g., {\"EPS\":12}."]], "mispr.gaussian.utilities.files": [[14, 4, 1, 0, "bibtex_parser", "Parse a bibtex file and returns a dictionary of the entries."], [14, 4, 1, 0, "recursive_relative_to_absolute_path", "Convert recursively relative paths to absolute paths."]], "mispr.gaussian.utilities.files.bibtex_parser": [[14, 2, 2, 0, "bib_file", "Relative or absolute path to the bibtex file."], [14, 2, 2, 0, "working_dir", "Name of the working directory where the bibtex file is located if bib_file path is relative; else None."]], "mispr.gaussian.utilities.files.recursive_relative_to_absolute_path": [[14, 2, 2, 0, "operand", "File, list of files, or a dictionary where the values are the files; the file(s) path can be relative or absolute."], [14, 2, 2, 0, "working_dir", "Name of the working directory where the file(s) is/are located if operand path is relative; else None."]], "mispr.gaussian.utilities.fw_utilities": [[14, 4, 1, 0, "add_common_mods", "Wrapper function to add common modifications to a workflow."], [14, 4, 1, 0, "control_worker", "Modify the Firework's fworker name and category in a workflow. Can be used when running workflows on multiple workers at the same time to specify which worker/machine to use."], [14, 4, 1, 0, "get_list_fireworks_and_tasks", "Return a list of (firework_index, task_index) tuples for all fireworks and tasks in a workflow."], [14, 4, 1, 0, "modify_queue_parameters", "Modify the default Firework's queue parameters in a workflow. Default ones are specified in the my_qadapter.yaml file. Helpful when different workflows requires different computational resources (e.g. number of CPUs, memory, etc.)."], [14, 4, 1, 0, "replace_runtask", "Replace all tasks with RunGaussian (e.g. RunGaussianDirect) with RunGaussianCustodian or vice versa."], [14, 4, 1, 0, "run_fake_gaussian", "Replace all tasks with RunGaussian (i.e. RunGaussianDirect, RunGaussianCustodian) with RunGaussianFake that runs a fake Gaussian job. We do not actually run Gaussian but copy existing inputs and outputs. Useful for testing purposes."]], "mispr.gaussian.utilities.fw_utilities.add_common_mods": [[14, 2, 2, 0, "fw_mods", "A dictionary of modifications to be applied to the workflow; supported ones are CONTROL_WORKER, MODIFY_QUEUE_PARAMETERS, REPLACE_RUNTASK, and RUN_FAKE_GAUSSIAN (see the docstring of each function for more details); values of the dictionary are the inputs to the corresponding function."], [14, 2, 2, 0, "workflow", "The workflow to modify."]], "mispr.gaussian.utilities.fw_utilities.control_worker": [[14, 2, 2, 0, "category", "The category to be assigned for the Firework; should be consistent with the one specified in the FireWorker (my_fworker.yaml file)."], [14, 2, 2, 0, "firework_substring", "A substring to search for in the Firework names to exclude certain fireworks."], [14, 2, 2, 0, "fworker", "The name of the fworker to use for the Firework; should be consistent with the one specified in the FireWorker (my_fworker.yaml file)."], [14, 2, 2, 0, "task_substring", "A substring to search for in the Firetask names to exclude certain Firetasks."], [14, 2, 2, 0, "workflow", "The workflow to control."]], "mispr.gaussian.utilities.fw_utilities.get_list_fireworks_and_tasks": [[14, 2, 2, 0, "firework_substring", "A substring to search for in the Firework names to exclude certain fireworks."], [14, 2, 2, 0, "task_substring", "A substring to search for in the Firetask names to exclude certain Firetasks."], [14, 2, 2, 0, "workflow", "The workflow to search."]], "mispr.gaussian.utilities.fw_utilities.modify_queue_parameters": [[14, 2, 2, 0, "firework_substring", "A substring to search for in the Firework names to exclude certain fireworks."], [14, 2, 2, 0, "ntasks_per_node", "The number of tasks to run on each node."], [14, 2, 2, 0, "other_parameters", "Other parameters to be added to the queueadapter."], [14, 2, 2, 0, "pre_rocket", "The pre-rocket command to run before the job."], [14, 2, 2, 0, "queue", "The queue/partition to run the job on."], [14, 2, 2, 0, "task_substring", "A substring to search for in the Firetask names to exclude certain Firetasks."], [14, 2, 2, 0, "walltime", "The walltime for the job."], [14, 2, 2, 0, "workflow", "The workflow to modify."]], "mispr.gaussian.utilities.fw_utilities.replace_runtask": [[14, 2, 2, 0, "additional_params", "Additional parameters to be added to the new Firetask that are not included in the original Firetask; refer to the corresponding Firetask documentation for supported parameters."], [14, 2, 2, 0, "firework_substring", "A substring to search for in the Firework names to exclude certain fireworks."], [14, 2, 2, 0, "operation", "The operation to perform on the Firetask; supported ones are remove_custodian and use_custodian."], [14, 2, 2, 0, "workflow", "The workflow to modify."]], "mispr.gaussian.utilities.fw_utilities.run_fake_gaussian": [[14, 2, 2, 0, "input_files", "A list of input files for the fake Gaussian job; order should match that in ref_dirs; e.g. [\"opt.com\", \"freq.com\"]."], [14, 2, 2, 0, "ref_dirs", "A list of directories containing the reference calculations for the fake Gaussian job (e.g. ['home/opt', 'home/freq'])."], [14, 2, 2, 0, "tolerance", "The tolerance for the comparison of the provided input file with the existing one."], [14, 2, 2, 0, "workflow", "The workflow to modify."]], "mispr.gaussian.utilities.gout": [[14, 4, 1, 0, "process_run", "Process a Gaussian run and returns a dictionary of the results. Used for creating db documents and/or json files."]], "mispr.gaussian.utilities.gout.process_run": [[14, 2, 2, 0, "input_file", "The input file for the run; used for adding Gaussian input parameters to the final Gaussian dictionary; if not specified, will get these parameters from the run itself, but in this case, input_parameters usually specified at the end of the Gaussian input file will not be saved since they are not easily retrieved from the Gaussian output file."], [14, 2, 2, 0, "kwargs", "Additional keyword arguments for the operation: namely, working_dir and db."], [14, 2, 2, 0, "operation_type", "Type of operation to be performed; supported ones are:"], [14, 2, 2, 0, "run", "The actual Gaussian run; type depends on the operation_type."]], "mispr.gaussian.utilities.inputs": [[14, 4, 1, 0, "handle_gaussian_inputs", "Wrapper function to cleanup/modify the Gaussian input parameters for one or more job in a workflow. Checks for implicit solvent parameters and adds missing keywords for a given job."]], "mispr.gaussian.utilities.inputs.handle_gaussian_inputs": [[14, 2, 2, 0, "gaussian_inputs", "Dictionary of dictionaries of Gaussian inputs, e.g."], [14, 2, 2, 0, "solvent_gaussian_inputs", "String of Gaussian inputs for the solvent, e.g."], [14, 2, 2, 0, "solvent_properties", "Dictionary of solvent properties, e.g."]], "mispr.gaussian.utilities.metadata": [[14, 4, 1, 0, "get_chem_schema", "Return a dictionary of chemical schema for a given molecule to use in building db documents or json file."], [14, 4, 1, 0, "get_job_name", "Append a molecule label to the name of a workflow for easy monitoring and identification."], [14, 4, 1, 0, "get_mol_formula", "Get the alphabetical molecular formula for a molecule."]], "mispr.gaussian.utilities.metadata.get_chem_schema": [[14, 2, 2, 0, "mol", "Molecule object."]], "mispr.gaussian.utilities.metadata.get_job_name": [[14, 2, 2, 0, "mol", "If a Molecule is provided, the appended label will be the molecular formula; otherwise the label will be the provided string."], [14, 2, 2, 0, "name", "Original name of the workflow."]], "mispr.gaussian.utilities.metadata.get_mol_formula": [[14, 2, 2, 0, "mol", "Molecule object"]], "mispr.gaussian.utilities.misc": [[14, 4, 1, 0, "pass_gout_dict", "Helper function used in the Gaussian Fireworks to pass Gaussian output dictionaries from one task to the other, while checking that the criteria for starting the following task are met (e.g. normal termination of the previous job, lack of imaginary frequencies, etc.)."], [14, 4, 1, 0, "recursive_compare_dicts", "Compare recursively two dictionaries and returns the differences."], [14, 4, 1, 0, "recursive_signature_remove", "Remove Recursively the signature \"@\" from a dictionary (e.g. those in the name of a module). Used when processing Gaussian runs before saving them to the db."]], "mispr.gaussian.utilities.misc.pass_gout_dict": [[14, 2, 2, 0, "fw_spec", "Firework spec dictionary."], [14, 2, 2, 0, "key", "Unique key for the Gaussian output dictionary in fw_spec."]], "mispr.gaussian.utilities.misc.recursive_compare_dicts": [[14, 2, 2, 0, "dict1", "First dictionary to compare."], [14, 2, 2, 0, "dict1_name", "Name of the first dictionary (for messages on the differences)."], [14, 2, 2, 0, "dict2", "Second dictionary to compare."], [14, 2, 2, 0, "dict2_name", "Name of the second dictionary (for messages on the differences)."], [14, 2, 2, 0, "path", "Used internally to keep track of the keys in nested dicts, meant to be \"\" for the top level"]], "mispr.gaussian.utilities.misc.recursive_signature_remove": [[14, 2, 2, 0, "d", "Dictionary to remove the signature from."]], "mispr.gaussian.utilities.mol": [[14, 4, 1, 0, "get_bond_order_str", "Find bond order as a string (\"U\": unspecified, \"S\", \"D\": double, \"T\": triple, \"A\": aromatic) by iterating over bonds of a molecule. First convert pymatgen mol to openbabel mol to use openbabel in finding bond order."], [14, 4, 1, 0, "label_atoms", "Get the SMILES representation of a molecule and label the atoms that appear in the SMILES string with the atom indexes as they appear in the molecule."], [14, 4, 1, 0, "perform_local_opt", "Perform a local optimization on the molecule using OpenBabel."], [14, 4, 1, 0, "process_mol", "Process a molecule. Used for handling different molecule formats provided to Gaussian workflows."]], "mispr.gaussian.utilities.mol.get_bond_order_str": [[14, 2, 2, 0, "mol", "pymatgen Molecule object."]], "mispr.gaussian.utilities.mol.label_atoms": [[14, 2, 2, 0, "mol", "The molecule to be labeled."]], "mispr.gaussian.utilities.mol.perform_local_opt": [[14, 2, 2, 0, "force_field", "The force field to be used for the optimization; options include gaff, ghemical, mmff94, mmff94s, and uff; defaults to uff."], [14, 2, 2, 0, "mol", "The molecule to be optimized."], [14, 2, 2, 0, "steps", "The number of steps to be performed in the local optimization; defaults to 200."]], "mispr.gaussian.utilities.mol.process_mol": [[14, 2, 2, 0, "kwargs", "Keyword arguments:"], [14, 2, 2, 0, "local_opt", "Whether to perform local optimization on the input structure using OpenBabel; defaults to False."], [14, 2, 2, 0, "mol", "Sources of structure, e.g. file path if mol_operation_type is specified as get_from_file, InChI string if mol_operation_type is specified as get_from_mol_db, etc."], [14, 2, 2, 0, "operation_type", "Operation to perform for the molecule to process the input structure format. Supported commands:"]], "mispr.gaussian.utilities.rdkit": [[14, 4, 1, 0, "calc_energy", "Perform local optimization on rdkit Mol object and calculates its energy using UFF."], [14, 4, 1, 0, "draw_rdkit_mol", "Draw the 2D structure of a molecule and saves it to a file."], [14, 4, 1, 0, "draw_rdkit_mol_with_highlighted_bonds", "Draw the 2D structure of a molecule and highlights the bonds specified by the user."], [14, 4, 1, 0, "get_rdkit_mol", "Convert a pymatgen mol object to RDKit rdmol object. Uses RDKit to perform the conversion . Accounts for aromaticity."]], "mispr.gaussian.utilities.rdkit.calc_energy": [[14, 2, 2, 0, "maxIters", "Maximum number of iterations to perform."], [14, 2, 2, 0, "rdkit_mol", "RDKit Mol object."]], "mispr.gaussian.utilities.rdkit.draw_rdkit_mol": [[14, 2, 2, 0, "filename", "Name of the file to save the image to; defaults to \"mol.png\"."], [14, 2, 2, 0, "rdkit_mol", "RDKit Mol object."], [14, 2, 2, 0, "working_dir", "Directory to save the image to; defaults to current working directory."]], "mispr.gaussian.utilities.rdkit.draw_rdkit_mol_with_highlighted_bonds": [[14, 2, 2, 0, "bonds", "List of tuples of indexes of atoms forming a bond to highlight; e.g. [(3, 11), (5, 13)] to highlight the bonds between sites 3 and 11 and sites 5 and 13."], [14, 2, 2, 0, "colors", "List of colors to use for highlighting the bonds; colors should be provided in rgb format, e.g. (0.0, 0.0, 0.0) for black; if not provided or number of colors provided is less than number of bonds to highlight, will randomly generate colors."], [14, 2, 2, 0, "filename", "Name of the file to save the image to; defaults to \"mol.png\"."], [14, 2, 2, 0, "rdkit_mol", "RDKit Mol object."], [14, 2, 2, 0, "working_dir", "Directory to save the image to; defaults to current working directory."]], "mispr.gaussian.utilities.rdkit.get_rdkit_mol": [[14, 2, 2, 0, "mol", "pymatgen Molecule object."], [14, 2, 2, 0, "remove_h", "whether to remove hydrogens."], [14, 2, 2, 0, "sanitize", "Whether to sanitize the molecule."]], "mispr.gaussian.workflows": [[16, 0, 0, 1, "base", ""]], "mispr.gaussian.workflows.base": [[16, 0, 0, 1, "bde", ""], [16, 0, 0, 1, "binding_energy", ""], [16, 0, 0, 1, "core", ""], [16, 0, 0, 1, "esp", ""], [16, 0, 0, 1, "ip_ea", ""], [16, 0, 0, 1, "nmr", ""]], "mispr.gaussian.workflows.base.bde": [[16, 4, 1, 0, "get_bde", "Define a dynamic workflow for calculating the bond dissociation energy."]], "mispr.gaussian.workflows.base.bde.get_bde": [[16, 2, 2, 0, "bonds", "List of tuples of the bonds to break; e.g. [(0, 1), (1, 2)] will break the bonds between atoms 0 and 1 and between atoms 1 and 2; if none is specified, will attempt to break all bonds. Defaults to None."], [16, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True,otherwise uses z-matrix. Defaults to True."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "fragment_charges", "List of additional charges to consider on the fragments besides the default ones. If ref_charge is -2, by default all fragments will be calculated with a charge of 0, -1, and -2. If the user provides fragment_charges is [-3], -3 and 1 will be additionally calculated. If the user provides fragment_charges is [-2], this will not cause any change since they are already calculated by the workflow; defaults to None."], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step; default parameters will be used if not specified."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow."], [16, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [16, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [16, 2, 2, 0, "name", "Name of the workflow. Defaults to \"bde_calculation\"."], [16, 2, 2, 0, "open_rings", "If True, will open rings encountered during fragmentation using OpenBabel's local opt.. Defaults to False."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step; e.g.:"], [16, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the molecule; e.g.: {\"Li\":1, \"O\":-2}. Defaults to None."], [16, 2, 2, 0, "ref_charge", "Charge on the principle molecule. Defaults to 0."], [16, 2, 2, 0, "skips", "List of jobs to skip; e.g.: [\"opt\", \"freq\"]; only applicable to the principle molecule. Defaults to None."], [16, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the ESP calculations, if any; e.g.:"], [16, 2, 2, 0, "solvent_properties", "Additional input parameters to be used in the ESP calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}. Defaults to None."], [16, 2, 2, 0, "visualize", "If True, will generate a summary plot of the 2D structure of the principle molecule with broken bonds highlighted in color, along with a bar plot of the corresponding BDEs; requires RDKit to be installed for bond highlighting; if RDKit is not found, will throw a warning and proceed normally."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created. Defaults to the current working directory."]], "mispr.gaussian.workflows.base.binding_energy": [[16, 4, 1, 0, "get_binding_energies", "Define a workflow for calculating the binding energy between two molecules."]], "mispr.gaussian.workflows.base.binding_energy.get_binding_energies": [[16, 2, 2, 0, "bond_order", "Bond order to calculate the bond length between the two sites. Defaults to 1."], [16, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True, otherwise uses z-matrix. Defaults to True."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step; default parameters will be used if not specified."], [16, 2, 2, 0, "index", "List of indices of the two sites in the molecules at which they are expected to bind; order should match that in mol_operation_type and mol."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow."], [16, 2, 2, 0, "mol", "List of the source of the two molecules to be processed. Should match the order in mol_operation_type; e.g. if mol_operation_type is [\"get_from_mol\", \"get_from_file\"], mol should be [Molecule, path to molecule file]."], [16, 2, 2, 0, "mol_operation_type", "List of strings of the type of molecule operations. See process_mol defined in Defines the binding energy workflow.mispr/gaussian/utilities/mol.py for supported operations; e.g. [\"get_from_mol\", \"get_from_file\"] to get the first molecule from a Molecule object and the second molecule from a file."], [16, 2, 2, 0, "name", "name of the workflow; defaults to \"binding_energy_calculation\"."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step; e.g.:"], [16, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the molecule; for example: {\"Li\":1, \"O\":-2}. Defaults to None."], [16, 2, 2, 0, "skips", "List of lists of jobs to skip for each molecule; e.g.: [[\"opt\", \"freq\"], [\"opt\"]]; order should be consistent with that in mol_operation_type and mol. Defaults to None."], [16, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the ESP calculations, if any; e.g.:"], [16, 2, 2, 0, "solvent_properties", "Additional input parameters to be used in the ESP calculations and relevant to the solvent model, if any; for example, {\"EPS\":12}. Defaults to None."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created. Defaults to the current working directory."]], "mispr.gaussian.workflows.base.core": [[16, 5, 1, 0, "GoutTypeError", "Bases: Exception"], [16, 4, 1, 0, "common_fw", "Define a list of Fireworks commonly used in Gaussian workflows."]], "mispr.gaussian.workflows.base.core.common_fw": [[16, 2, 2, 0, "cart_coords", "Whether to use cartesian coordinates in writing Gaussian input files."], [16, 2, 2, 0, "check_result", "List of properties to check for in the output file when skipping jobs; ensures that properties required by the workflow are available via the molecule format provided as an input (e.g. Gaussian output dictionary)."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if None is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "dir_head", "The name of the head of the directory where the workflow corresponding to the molecule will be run."], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step."], [16, 2, 2, 0, "gout_key", "Unique key for the Gaussian output dict; used to differentiate Gaussian output dictionaries generated in the same workflow; if None is provided, the key will be set \"mol\"."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the Fireworks and Firetasks."], [16, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [16, 2, 2, 0, "mol_name", "The name of the molecule; ignored if process_mol_func is set to True."], [16, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step."], [16, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the molecule; e.g.: {\"Li\":1, \"O\":-2}."], [16, 2, 2, 0, "process_mol_func", "Whether to process the molecule; if True, will use the molecular formula as the label. Defaults to True."], [16, 2, 2, 0, "skips", "List of jobs to skip; e.g.: [\"opt\", \"freq\"]; defaults to None."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created."]], "mispr.gaussian.workflows.base.esp": [[16, 4, 1, 0, "get_esp_charges", "Define a workflow for calculating the electrostatic partial charges."]], "mispr.gaussian.workflows.base.esp.get_esp_charges": [[16, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True, otherwise uses z-matrix. Defaults to True."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "esp_gaussian_inputs", "Dictionary of Gaussian input parameters for the ESP step; default parameters will be used if not specified."], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step; default parameters will be used if not specified."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow."], [16, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [16, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [16, 2, 2, 0, "name", "Name of the workflow. Defaults to \"esp_charges_calculation\"."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step; e.g.:"], [16, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the molecule; e.g.: {\"Li\":1, \"O\":-2}. Defaults to None."], [16, 2, 2, 0, "skips", "List of jobs to skip; e.g.: [\"opt\", \"freq\"]; defaults to None."], [16, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the ESP calculations, if any; e.g.:"], [16, 2, 2, 0, "solvent_properties", "Additional input parameters to be used in the ESP calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}. Defaults to None."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created. Defaults to the current working directory."]], "mispr.gaussian.workflows.base.ip_ea": [[16, 1, 1, 0, "Node", "Bases: object"], [16, 4, 1, 0, "get_ip_ea", "Define a workflow for calculating the ionization potential (IP) and electron affinity (EA) in eV. Supports multiple methods for calculating redox potentials in gas and/or solution:"]], "mispr.gaussian.workflows.base.ip_ea.Node.__init__": [[16, 2, 2, 0, "branch_cation_from_anion", "Whether to add a hydrogen atom at the current node; relevant for PCET calculations."], [16, 2, 2, 0, "check_result", "List of properties to check for in the output file; only relevant when skipping jobs at the parent node;"], [16, 2, 2, 0, "h_index", "The site index in the molecule at which to attach the hydrogen atoms in the PCET calculations."], [16, 2, 2, 0, "mol", "Molecule to be processed; required for the parent node, i.e. initial molecule state, but not for the child nodes since these are generated from the parent node."], [16, 2, 2, 0, "mol_operation_type", "Type of molecule operation; required for the parent node, i.e. initial molecule state, but not for the child nodes."], [16, 2, 2, 0, "num_electrons", "Number of electrons to transfer."], [16, 2, 2, 0, "parent", "Parent node of the current node; None if the node corresponds to the initial molecule state."], [16, 2, 2, 0, "phase", "Current phase of the molecule: gas or solution."], [16, 2, 2, 0, "ref_charge", "The initial charge on the molecule; only relevant to the parent node."], [16, 2, 2, 0, "skips", "List of jobs to skip; only relevant to the parent node, i.e. initial molecule state. Defaults to None."], [16, 2, 2, 0, "state", "Current state of the molecule: cation or anion."]], "mispr.gaussian.workflows.base.ip_ea.Node": [[16, 3, 1, 0, "branch", "Generate the children nodes of the current node in the tree representing the IP/EA workflow."], [16, 3, 1, 0, "create_fireworks", "Generate the optimization and/or frequency fireworks corresponding to the current node."]], "mispr.gaussian.workflows.base.ip_ea.get_ip_ea": [[16, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True, otherwise uses z-matrix. Defaults to True."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "electrode_potentials", "Dictionary of electrode potentials to be used in converting the absolute oxidation and reduction potentials to commonly used potential scales; e.g.:"], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step; default parameters will be used if not specified."], [16, 2, 2, 0, "gibbs_elec", "The electron gibbs free energy in Hartree; defaults to -0.001378786."], [16, 2, 2, 0, "gibbs_h", "The hydrogen gibbs free energy in Hartree; defaults to -0.41816."], [16, 2, 2, 0, "h_index", "The site index in the molecule at which to attach the hydrogen atoms in the PCET calculations. Defaults to None."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow."], [16, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [16, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [16, 2, 2, 0, "name", "Name of the workflow. Defaults to \"ip_ea_calculation\"."], [16, 2, 2, 0, "num_electrons", "The number of electrons to be transferred; defaults to 1."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step; e.g.:"], [16, 2, 2, 0, "pcet", "Whether to run sequential proton-coupled electron transfer calculations; number of hydrogen transfer steps is assumed to be equal to the number of electron transfers. Defaults to False."], [16, 2, 2, 0, "phases", "List of phases to be calculated; e.g. [\"solution\"] for liquid phase, [\"gas\"] for gas phase, or [\"gas\", \"solution\"] for the full thermodynamic cycle; runs both if None is specified."], [16, 2, 2, 0, "ref_charge", "The initial charge on the molecule."], [16, 2, 2, 0, "ref_skips", "List of jobs to skip; e.g.: [\"opt\", \"freq\"]; only applies to the molecule in the reference state. Defaults to None."], [16, 2, 2, 0, "single_step", "Whether to run the electron transfer in a single or multiple steps; e.g. if num_electrons is set to 2 and single_step is False, the workflow will run the electron transfer in two steps; defaults to False."], [16, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the redox potential calculations, if any; e.g.:"], [16, 2, 2, 0, "solvent_properties", "Additional input parameters to be used in the ESP calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}. Defaults to None."], [16, 2, 2, 0, "states", "List of states to be calculated; e.g. [\"cation\"] for oxidation, [\"anion\"] for reduction, or [\"cation\", \"anion\"] for oxidation and reduction calculations; runs both if None is specified."], [16, 2, 2, 0, "vertical", "Whether to run the vertical IP/EA calculations, in which optimization is performed only at the reference state at each phase specified, thereby skipping the optimization step at the charge states; defaults to False."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created. Defaults to the current working directory."]], "mispr.gaussian.workflows.base.nmr": [[16, 4, 1, 0, "get_nmr_tensors", "Define a workflow for calculating the nuclear magnetic resonance tensors."]], "mispr.gaussian.workflows.base.nmr.get_nmr_tensors": [[16, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True, otherwise uses z-matrix. Defaults to True."], [16, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [16, 2, 2, 0, "freq_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step; default parameters will be used if not specified."], [16, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow."], [16, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [16, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [16, 2, 2, 0, "name", "Name of the workflow. Defaults to \"nmr_tensor_calculation\"."], [16, 2, 2, 0, "nmr_gaussian_inputs", "Dictionary of Gaussian input parameters for the NMR step; default parameters will be used if not specified."], [16, 2, 2, 0, "opt_gaussian_inputs", "Dictionary of Gaussian input parameters; e.g.:"], [16, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the molecule; e.g.: {\"Li\":1, \"O\":-2}. Defaults to None."], [16, 2, 2, 0, "skips", "List of jobs to skip; e.g.: [\"opt\", \"freq\"]; defaults to None."], [16, 2, 2, 0, "solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the NMR calculations, if any; e.g.:"], [16, 2, 2, 0, "solvent_properties", "Additional input parameters to be used in the NMR calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}. Defaults to None."], [16, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created. Defaults to the current working directory."]], "mispr.hybrid": [[17, 0, 0, 1, "defaults", ""], [18, 0, 0, 1, "firetasks", ""], [19, 0, 0, 1, "workflows", ""]], "mispr.hybrid.firetasks": [[18, 0, 0, 1, "nmr_from_md", ""]], "mispr.hybrid.firetasks.nmr_from_md": [[18, 1, 1, 0, "NMRFromMD", "Bases: FiretaskBase"]], "mispr.hybrid.firetasks.nmr_from_md.NMRFromMD": [[18, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.hybrid.firetasks.nmr_from_md.NMRFromMD.run_task": [[18, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.hybrid.workflows": [[19, 0, 0, 1, "core", ""], [19, 0, 0, 1, "nmr", ""]], "mispr.hybrid.workflows.core": [[19, 4, 1, 0, "run_hybrid_calcs", ""]], "mispr.hybrid.workflows.nmr": [[19, 4, 1, 0, "get_solvation_structures_nmr", "Return a workflow to run hybrid DFT/MD calculations, extract categorize atomic clusters around a particle of interest, and run the NMR calculations for the clusters that have the highest frequency of occurrence in solution."]], "mispr.hybrid.workflows.nmr.get_solvation_structures_nmr": [[19, 2, 2, 0, "analysis_list", "Type of MD analysis to perform after the MD simulations are finished; e.g.: [\"diffusion\", \"rdf\", \"cn\", \"clusters\"] if user wants to perform diffusion, RDF, coordination number, and cluster analysis."], [19, 2, 2, 0, "analysis_settings", "Settings of the MD analysis steps; please refer to the mdproptools documentation for details of inputs used in the analysis functions; order of settings should correspond to the order used in analysis_list."], [19, 2, 2, 0, "box_data", "Definitions for box size. See box_data_type for info how to define this parameter."], [19, 2, 2, 0, "box_data_type", "Can be one of the following: \"cubic\", \"rectangular\", or \"LammpsBox\". If \"cubic\", box_data must be a float or int; if \"rectangular\", box_data must be an array-like with size (3,2); if \"LammpsBox\", box_data must be a pymatgen.io.lammps.data.LammpsBox object. Defaults to \"cubic\"."], [19, 2, 2, 0, "cart_coords", "Uses cartesian coordinates in writing Gaussian input files if set to True, otherwise uses z-matrix. Defaults to True."], [19, 2, 2, 0, "data_file_name", "Name of the LAMMPS data file to create and use; defaults to \"data.mixture\"."], [19, 2, 2, 0, "db", "Database credentials; could be provided as the path to the \"db.json\" file or in the form of a dictionary; if none is provided, attempts to get it from the configuration files."], [19, 2, 2, 0, "esp_gaussian_inputs", "Sictionary of Gaussian input parameters for the ESP step of the ESP workflow; default parameters will be used if not specified."], [19, 2, 2, 0, "esp_solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the ESP calculations, if any; e.g.:"], [19, 2, 2, 0, "esp_solvent_properties", "Additional input parameters to be used in the ESP calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}."], [19, 2, 2, 0, "ff_method", "Operation to perform for each molecule composing the liquid solution in order to process the force field parameters. Can be \"get_from_esp\", \"get_from_prmtop\", \"get_from_dict\", \"get_from_opls\". Defaults to \"get_from_esp\" for all molecules."], [19, 2, 2, 0, "ff_params", "Sources of the force field parameters for each molecule type; type depends on what is specified in the ff_method input; if \"get_from_esp\" is used, the corresponding ff_param should be an empty dictionary since the path to the ESP file is automatically detected from the ESP calculations that is performed at the beginning of the workflow; if \"get_from_prmtop\" is used, the corresponding ff_param should be the path to the prmtop file; if \"get_from_dict\" is used, the corresponding ff_param should be a dictionary, e.g.:"], [19, 2, 2, 0, "freq_esp_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step of the ESP workflow; default parameters will be used if not specified."], [19, 2, 2, 0, "freq_nmr_gaussian_inputs", "Dictionary of Gaussian input parameters for the frequency step of the NMR workflow; default parameters will be used if not specified."], [19, 2, 2, 0, "kwargs", "Additional kwargs to be passed to the workflow; e.g.: lammps recipe and recipe_settings; the defaults for these inputs are specified in the mispr/lammps/defaults.py."], [19, 2, 2, 0, "mixture_type", "\"concentration\" or \"number of molecules\"; defaults to \"number of molecules\"."], [19, 2, 2, 0, "mol", "Sources of structures making up the liquid solution, e.g. file path if mol_operation_type is specified as \"get_from_file\", InChI string if mol_operation_type is specified as \"get_from_mol_db\", etc."], [19, 2, 2, 0, "mol_data", "Format depends on mixture_type input. If mixture_type is \"number of molecules\", mol_data should be a list of the number of molecules of each type. If mixture_type is \"concentration\", mol_data should be a list of dict, where each dictionary should follow the format:"], [19, 2, 2, 0, "mol_operation_type", "Operation to perform for each molecule composing the liquid solution in order to process the input structure format. Length should correspond to the number of molecules/species composing the liquid solution. Supported commands:"], [19, 2, 2, 0, "mol_type", "Type of each structure composing the liquid solution. Supported types: \"Solvents\", \"Solutes\". Used for calculating the number of molecules of each type if this information is not provided."], [19, 2, 2, 0, "name", "Name of the workflow. Defaults to \"hybrid_calculation\"."], [19, 2, 2, 0, "nmr_gaussian_inputs", "Dictionary of Gaussian input parameters for the NMR step of the NMR workflow; default parameters will be used if not specified."], [19, 2, 2, 0, "nmr_solvent_gaussian_inputs", "Gaussian input parameters corresponding to the implicit solvent model to be used in the NMR calculations, if any; e.g.:"], [19, 2, 2, 0, "nmr_solvent_properties", "Additional input parameters to be used in the NMR calculations and relevant to the solvent model, if any; e.g., {\"EPS\":12}."], [19, 2, 2, 0, "opt_esp_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step of the ESP workflow; e.g.:"], [19, 2, 2, 0, "opt_nmr_gaussian_inputs", "Dictionary of Gaussian input parameters for the optimization step of the NMR workflow; default parameters will be used if not specified."], [19, 2, 2, 0, "oxidation_states", "Dictionary of oxidation states that can be used in setting the charge and spin multiplicity of the clusters extracted from MD simulations to be used in the NMR workflow."], [19, 2, 2, 0, "skips", "Type of DFT calculation to skip in the ESP workflow for each molecule; e.g. [\"opt\", \"freq\"], [\"opt\"], [\"freq\"], or []."], [19, 2, 2, 0, "working_dir", "Path of the working directory where any required input files can be found and output will be created."]], "mispr.lammps": [[20, 0, 0, 1, "database", ""], [20, 0, 0, 1, "defaults", ""], [21, 0, 0, 1, "firetasks", ""], [22, 0, 0, 1, "fireworks", ""], [23, 0, 0, 1, "tests", ""], [24, 0, 0, 1, "utilities", ""], [25, 0, 0, 1, "workflows", ""]], "mispr.lammps.database": [[20, 1, 1, 0, "LammpsSysDb", "Bases: object"]], "mispr.lammps.database.LammpsSysDb": [[20, 3, 1, 0, "build_indexes", ""], [20, 3, 1, 0, "delete_force_field", ""], [20, 3, 1, 0, "from_db_file", ""], [20, 3, 1, 0, "insert_force_field", ""], [20, 3, 1, 0, "insert_run", ""], [20, 3, 1, 0, "insert_system", ""], [20, 3, 1, 0, "query_force_fields", ""], [20, 3, 1, 0, "retrieve_force_field", ""], [20, 3, 1, 0, "retrieve_run", ""]], "mispr.lammps.firetasks": [[21, 0, 0, 1, "parse_outputs", ""], [21, 0, 0, 1, "run", ""], [21, 0, 0, 1, "write_inputs", ""]], "mispr.lammps.firetasks.parse_outputs": [[21, 1, 1, 0, "CalcCN", "Bases: FiretaskBase"], [21, 1, 1, 0, "CalcDiff", "Bases: FiretaskBase"], [21, 1, 1, 0, "ExtractClusters", "Bases: FiretaskBase"], [21, 1, 1, 0, "GetRDF", "Bases: FiretaskBase"], [21, 1, 1, 0, "ProcessAnalysis", "Bases: FiretaskBase"], [21, 1, 1, 0, "ProcessPrmtop", "Bases: FiretaskBase"]], "mispr.lammps.firetasks.parse_outputs.CalcCN": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.CalcCN.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.parse_outputs.CalcDiff": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.CalcDiff.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.parse_outputs.ExtractClusters": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.ExtractClusters.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.parse_outputs.GetRDF": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.GetRDF.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.parse_outputs.ProcessAnalysis": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.ProcessAnalysis.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.parse_outputs.ProcessPrmtop": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.parse_outputs.ProcessPrmtop.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run": [[21, 1, 1, 0, "RunAntechamber", "Bases: FiretaskBase"], [21, 1, 1, 0, "RunLammpsDirect", "Bases: FiretaskBase"], [21, 1, 1, 0, "RunLammpsFake", "Bases: FiretaskBase"], [21, 1, 1, 0, "RunMaestro", "Bases: FiretaskBase"], [21, 1, 1, 0, "RunParmchk", "Bases: FiretaskBase"], [21, 1, 1, 0, "RunTleap", "Bases: FiretaskBase"]], "mispr.lammps.firetasks.run.RunAntechamber": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunAntechamber.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run.RunLammpsDirect": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunLammpsDirect.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run.RunLammpsFake": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunLammpsFake.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run.RunMaestro": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunMaestro.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run.RunParmchk": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunParmchk.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.run.RunTleap": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.run.RunTleap.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.write_inputs": [[21, 1, 1, 0, "LabelFFDict", "Bases: FiretaskBase"], [21, 1, 1, 0, "LabelFFDictFromDB", "Bases: FiretaskBase"], [21, 1, 1, 0, "WriteControlFile", "Bases: FiretaskBase"], [21, 1, 1, 0, "WriteDataFile", "Bases: FiretaskBase"], [21, 1, 1, 0, "WriteTleapScript", "Bases: FiretaskBase"]], "mispr.lammps.firetasks.write_inputs.LabelFFDict": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.write_inputs.LabelFFDict.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.write_inputs.LabelFFDictFromDB": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.write_inputs.LabelFFDictFromDB.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.write_inputs.WriteControlFile": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.write_inputs.WriteControlFile.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.write_inputs.WriteDataFile": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.write_inputs.WriteDataFile.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.firetasks.write_inputs.WriteTleapScript": [[21, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.firetasks.write_inputs.WriteTleapScript.run_task": [[21, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.fireworks": [[22, 0, 0, 1, "core", ""]], "mispr.lammps.fireworks.core": [[22, 1, 1, 0, "GetFFDictFW", "Bases: Firework"], [22, 1, 1, 0, "RunAnalysisFW", "Bases: Firework"], [22, 1, 1, 0, "RunLammpsFW", "Bases: Firework"], [22, 4, 1, 0, "ambertools_tasks", "Define a list of common tasks for generating GAFF parameters for a molecule. This is a helper function for the GetFFDictFW Firework."]], "mispr.lammps.fireworks.core.GetFFDictFW.__init__": [[22, 2, 2, 0, "data", "Data to be processed, e.g., path to the esp file if operation_type is get_from_esp, path to the prmtop file if operation_type is get_from_prmtop, etc."], [22, 2, 2, 0, "db", "Database credentials. Could be provided as the path to the \"db.json\" file or in the form of a dict. If none is provided, attempts to read it from the configuration files to save the Firework to."], [22, 2, 2, 0, "ff_filename", "Filename to save the force field to. Defaults to \"ff.json\"."], [22, 2, 2, 0, "kwargs", "Other kwargs that are passed to:"], [22, 2, 2, 0, "label", "Label for the molecule. This should be unique for each different molecular species in the system. Defaults to an empty string. In this case, the label will be obtained based on the molecular formula."], [22, 2, 2, 0, "mol", "Source of the molecule to be processed. Should match the mol_operation_type."], [22, 2, 2, 0, "mol_operation_type", "The type of molecule operation. See process_mol defined in mispr/gaussian/utilities/mol.py for supported operations."], [22, 2, 2, 0, "name", "Name of the Firework. Defaults to get_ff_dict."], [22, 2, 2, 0, "operation_type", "The operation to perform on the data to read or generate the force field parameters. Defaults to get_from_esp. Supported commands:"], [22, 2, 2, 0, "parents", "List of parent Fireworks that this Firework depends on. Defaults to None."], [22, 2, 2, 0, "save_ff_to_db", "Whether to save the force field to the database. Defaults to False."], [22, 2, 2, 0, "save_ff_to_file", "Whether to save the force field to a file. Defaults to True."], [22, 2, 2, 0, "tag", "Tag for the Firework. The provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [22, 2, 2, 0, "working_dir", "Directory to run the Firework in. Defaults to the current working directory."]], "mispr.lammps.fireworks.core.RunAnalysisFW.__init__": [[22, 2, 2, 0, "kwargs", "Other kwargs that are passed to:"], [22, 2, 2, 0, "md_property", "The property to calculate. Supported properties:"], [22, 2, 2, 0, "name", "Name of the Firework. Defaults to \"run_analysis\"."], [22, 2, 2, 0, "parents", "List of parent Fireworks that this Firework depends on. Defaults to None."], [22, 2, 2, 0, "tag", "Tag for the Firework. The provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [22, 2, 2, 0, "working_dir", "Directory to run the Firework in. Defaults to the current working directory."]], "mispr.lammps.fireworks.core.RunLammpsFW.__init__": [[22, 2, 2, 0, "control_file", "Path to the control file. If not provided, the control file will be generated. Defaults to None."], [22, 2, 2, 0, "db", "Database credentials. Could be provided as the path to the db.json file or in the form of a dict. If none is provided, attempts to read it from the configuration files to save the Firework to."], [22, 2, 2, 0, "kwargs", "Other kwargs that are passed to:"], [22, 2, 2, 0, "name", "Name of the Firework. Defaults to \"run_lammps\"."], [22, 2, 2, 0, "parents", "List of parent Fireworks that this Firework depends on. Defaults to None."], [22, 2, 2, 0, "save_run_to_db", "Whether to save the run to the database. Defaults to True."], [22, 2, 2, 0, "save_run_to_file", "Whether to save the run to a file. Defaults to False."], [22, 2, 2, 0, "tag", "Tag for the Firework. The provided tag will be stored in the db documents for easy retrieval. Defaults to \"unknown\"."], [22, 2, 2, 0, "working_dir", "Directory to run the Firework in. Defaults to the current working directory."]], "mispr.lammps.fireworks.core.ambertools_tasks": [[22, 2, 2, 0, "kwargs", "other kwargs that are passed to:"]], "mispr.lammps.tests": [[23, 0, 0, 1, "antechamber", ""], [23, 0, 0, 1, "base_test", ""], [23, 0, 0, 1, "control", ""], [23, 0, 0, 1, "custom_data_workflow", ""], [23, 0, 0, 1, "data", ""], [23, 0, 0, 1, "electrolyte_wf", ""], [23, 0, 0, 1, "esp_to_ff_dict_custom", ""], [23, 0, 0, 1, "esp_to_ff_dict_function", ""], [23, 0, 0, 1, "liquid_wf_local", ""], [23, 0, 0, 1, "parmchk", ""], [23, 0, 0, 1, "prmtop", ""], [23, 0, 0, 1, "run_lammps", ""], [23, 0, 0, 1, "tleap", ""]], "mispr.lammps.tests.base_test": [[23, 1, 1, 0, "PrintFW", "Bases: FiretaskBase"]], "mispr.lammps.tests.base_test.PrintFW": [[23, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.tests.base_test.PrintFW.run_task": [[23, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.tests.data": [[23, 1, 1, 0, "PrintFW", "Bases: FiretaskBase"]], "mispr.lammps.tests.data.PrintFW": [[23, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.tests.data.PrintFW.run_task": [[23, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.tests.esp_to_ff_dict_custom": [[23, 1, 1, 0, "PrintFW", "Bases: FiretaskBase"]], "mispr.lammps.tests.esp_to_ff_dict_custom.PrintFW": [[23, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.tests.esp_to_ff_dict_custom.PrintFW.run_task": [[23, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.tests.esp_to_ff_dict_function": [[23, 1, 1, 0, "PrintFW", "Bases: FiretaskBase"]], "mispr.lammps.tests.esp_to_ff_dict_function.PrintFW": [[23, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.tests.esp_to_ff_dict_function.PrintFW.run_task": [[23, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.tests.prmtop": [[23, 1, 1, 0, "PrintFW", "Bases: FiretaskBase"]], "mispr.lammps.tests.prmtop.PrintFW": [[23, 3, 1, 0, "run_task", "This method gets called when the Firetask is run. It can take in a Firework spec, perform some task using that data, and then return an output in the form of a FWAction."]], "mispr.lammps.tests.prmtop.PrintFW.run_task": [[23, 2, 2, 0, "fw_spec", "A Firework spec. This comes from the master spec. In addition, this spec contains a special \"_fw_env\" key that contains the env settings of the FWorker calling this method. This provides for abstracting out certain commands or settings. For example, \"foo\" may be named \"foo1\" in resource 1 and \"foo2\" in resource 2. The FWorker env can specify { \"foo\": \"foo1\"}, which maps an abstract variable \"foo\" to the relevant \"foo1\" or \"foo2\". You can then write a task that uses fw_spec[\"_fw_env\"][\"foo\"] that will work across all these multiple resources."]], "mispr.lammps.utilities": [[24, 0, 0, 1, "opls", ""], [24, 0, 0, 1, "utilities", ""]], "mispr.lammps.utilities.opls": [[24, 1, 1, 0, "MaestroRunner", "Bases: object"]], "mispr.lammps.utilities.opls.MaestroRunner.__init__": [[24, 2, 2, 0, "ffld_cmd", "Full command to use for generating the force field parameters from the mae file. If not specified, will try to parse the command from the MISPR configuration file."], [24, 2, 2, 0, "input_file", "Molecule/structure file to use for converting to a mae file. For a full list of supported formats, check https://www.schrodinger.com/kb/1278."], [24, 2, 2, 0, "mae_cmd", "Full command to use for converting the structure format to mae file; if not specified, will try to parse the command from the MISPR configuration file."], [24, 2, 2, 0, "name", "Name of the molecule to use when saving the mae and log files generated by Maestro."], [24, 2, 2, 0, "working_dir", "Working directory where the input_file is located and Maestro files to be generated."]], "mispr.lammps.utilities.opls.MaestroRunner": [[24, 3, 1, 0, "cleanup", "Deletes the log and mae files created by Maestro"], [24, 3, 1, 0, "convert_ff_log_to_json", "Converts the force field parameters in the log file to a dictionary format that is compatible with MISPR."], [24, 3, 1, 0, "convert_mol_to_mae", "Converts a structure input file to a mae file."], [24, 3, 1, 0, "get_ff_log", "Generates a log file with force field parameters using a mae file."], [24, 3, 1, 0, "get_opls_params", "Wrapper function that converts input structure to mae format, uses it to generate a log file with the force field parameters of the molecule, parses the log file to generate a dictionary of force parameters in a format compatible with the lammps workflow in MISPR, and optionally cleans up the working directory by removing the intermediate files generated in the process."]], "mispr.lammps.utilities.opls.MaestroRunner.get_opls_params": [[24, 2, 2, 0, "cleanup", "Whether to clean up the working directory. Defaults to True."]], "mispr.lammps.utilities.utilities": [[24, 4, 1, 0, "add_ff_labels_to_BADI_lists", "Add extra string to the end of all atom type labels in lists containing information about Bonds, Angles, Dihedrals, or Impropers (BADI). This function is intended to be used through the add_ff_labels_to_dict."], [24, 4, 1, 0, "add_ff_labels_to_dict", "A dictionary containing the force field information for a molecule. The dictionary should have the following form:"], [24, 4, 1, 0, "get_db", ""], [24, 4, 1, 0, "lammps_mass_to_element", "Create a dict for mapping atom mass to element."], [24, 4, 1, 0, "process_ff_doc", ""], [24, 4, 1, 0, "process_run", ""], [24, 4, 1, 0, "run_fake_lammps", ""]], "mispr.lammps.utilities.utilities.add_ff_labels_to_BADI_lists": [[24, 2, 2, 0, "ff_list", "The value from ff_dict using one of the following keys: 'Bonds', 'Angles', 'Dihedrals', or 'Impropers'. The form of this list should be as follows:"], [24, 2, 2, 0, "label", "A label for the molecular species that is unique for the system being created."]], "mispr.lammps.utilities.utilities.add_ff_labels_to_dict": [[24, 2, 2, 0, "ff_dict", "A dictionary containing the force field information for a molecule. The dictionary should have the following form:"], [24, 2, 2, 0, "label", ""]], "mispr.lammps.utilities.utilities.lammps_mass_to_element": [[24, 2, 2, 0, "lammps_masses", "List of masses in lammps units."]], "mispr.lammps.workflows": [[25, 0, 0, 1, "base", ""]], "mispr.lammps.workflows.base": [[25, 4, 1, 0, "lammps_analysis_fws", "Generate FireWorks for running LAMMPS analysis."], [25, 4, 1, 0, "lammps_data_fws", "Generate FireWorks for writing LAMMPS data files."], [25, 4, 1, 0, "lammps_run_fws", "Generate FireWorks for running LAMMPS simulations."], [25, 4, 1, 0, "lammps_workflow", "Create a LAMMPS workflow."]], "mispr.lammps.workflows.base.lammps_analysis_fws": [[25, 2, 2, 0, "analysis_list", "List of analysis types to perform. Supported types are: 'diffusion', 'rdf', 'cn', and 'clusters'."], [25, 2, 2, 0, "analysis_settings", "List of dictionaries containing the settings for each analysis type."], [25, 2, 2, 0, "kwargs", "Additional keyword arguments."], [25, 2, 2, 0, "working_dir", "Directory where the data files will be written."]], "mispr.lammps.workflows.base.lammps_data_fws": [[25, 2, 2, 0, "box_data", "Definitions for box size. See box_data_type for info how to define this parameter."], [25, 2, 2, 0, "box_data_type", "Determines the value of the box_data parameter. Can be one of the following: 'cubic', 'rectangular', or 'LammpsBox'. If 'cubic', box_data must be a float or int; if 'rectangular', box_data must be an array-like with size (3,2); if 'LammpsBox', box_data must be a LammpsBox object. Defaults to 'cubic'."], [25, 2, 2, 0, "data_file_name", "Name of the data file to be written. Defaults to \"complex.data\"."], [25, 2, 2, 0, "db", "Database credentials. Could be a string with the path to the database file or a dictionary with the database credentials. If none is provided, attempts to read the configuration files. Only used when save_ff_to_db is True."], [25, 2, 2, 0, "kwargs", "Additional keyword arguments."], [25, 2, 2, 0, "system_mixture_type", "Type of mixture data. Must be \"concentration\" or \"number of molecules\". See LammpsDataWrapper in pymatgen/io/lammps/data.py for more information."], [25, 2, 2, 0, "system_species_data", "Dictionary containing species data. The keys are the species labels and the values are dictionaries containing the following keys:"], [25, 2, 2, 0, "tag", "Tag for the Fireworks. Defaults to \"unknown\"."], [25, 2, 2, 0, "working_dir", "Directory where the data files will be written. Defaults to the current working directory."]], "mispr.lammps.workflows.base.lammps_run_fws": [[25, 2, 2, 0, "db", "Database credentials. Could be a string with the path to the database file or a dictionary with the database credentials. If none is provided, attempts to read the configuration files. Only used when save_runs_to_db is True."], [25, 2, 2, 0, "init_spec", "Initial spec for the FireWorks. Defaults to None."], [25, 2, 2, 0, "kwargs", "Additional keyword arguments."], [25, 2, 2, 0, "recipe", "List of lists containing the name of the step and the template filename or string for the LAMMPS input file. Defaults to LAMMPS_RECIPE."], [25, 2, 2, 0, "recipe_qadapter", "List of dictionaries containing the settings for the queue adapter for each step in the recipe. Defaults to QADAPTER_RUN_LAMMPS_SPEC."], [25, 2, 2, 0, "recipe_settings", "List of dictionaries containing the settings for each step in the recipe. Defaults to RECIPE_SETTINGS."], [25, 2, 2, 0, "save_runs_to_db", "Whether to save the runs to the database. Defaults to True."], [25, 2, 2, 0, "save_runs_to_file", "Whether to save the runs to a file. Defaults to False."], [25, 2, 2, 0, "working_dir", "Directory where the data files will be written. Defaults to the current working directory."]], "mispr.lammps.workflows.base.lammps_workflow": [[25, 2, 2, 0, "analysis_list", "List of analysis types to perform. Supported types are: 'diffusion', 'rdf', 'cn', and 'clusters'. Defaults to None. If not provided, the workflow will not create any FireWorks for running LAMMPS analysis."], [25, 2, 2, 0, "analysis_settings", "List of dictionaries containing the settings for each analysis type. Defaults to None. If not provided, the workflow will not create any FireWorks for running LAMMPS analysis."], [25, 2, 2, 0, "box_data", "Definitions for box size. See lammps_data_fws for info on how to define this parameter. Defaults to None. If not provided, the workflow will not create any FireWorks for writing LAMMPS data files."], [25, 2, 2, 0, "box_data_type", "Determines the value of the box_data parameter. Defaults to 'cubic'."], [25, 2, 2, 0, "data_file_name", "Name of the data file to be written. Defaults to 'data.mixture'."], [25, 2, 2, 0, "db", "Database credentials. Could be a string with the path to the database file or a dictionary with the database credentials. If none is provided, attempts to read the configuration files. Only used when save_runs_to_db is True. Defaults to None."], [25, 2, 2, 0, "kwargs", "Additional keyword arguments."], [25, 2, 2, 0, "name", "Name of the workflow. Defaults to 'lammps_workflow'."], [25, 2, 2, 0, "recipe", "List of lists containing the name of the step and the template filename or string for the LAMMPS input file. Defaults to LAMMPS_RECIPE."], [25, 2, 2, 0, "recipe_qadapter", "List of dictionaries containing the settings for the queue adapter for each step in the recipe. Defaults to QADAPTER_RUN_LAMMPS_SPEC."], [25, 2, 2, 0, "recipe_settings", "List of dictionaries containing the settings for each step in the recipe. Defaults to RECIPE_SETTINGS."], [25, 2, 2, 0, "system_mixture_type", "Type of mixture data. Must be \"concentration\" or \"number of molecules\". See LammpsDataWrapper in pymatgen/io/lammps/data.py for more information. Defaults to None. If not provided, the workflow will not create any FireWorks for writing LAMMPS data files."], [25, 2, 2, 0, "system_species_data", "Dictionary containing species data. Refer to the lammps_data_fws function for more information. Defaults to None. If not provided, the workflow will not create any FireWorks for writing LAMMPS data files."], [25, 2, 2, 0, "working_dir", "Directory where the data files will be written. Defaults to the current working directory."]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:parameter", "3": "py:method", "4": "py:function", "5": "py:exception"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "parameter", "Python parameter"], "3": ["py", "method", "Python method"], "4": ["py", "function", "Python function"], "5": ["py", "exception", "Python exception"]}, "titleterms": {"changelog": 0, "cite": 1, "mispr": [1, 2, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26], "0": 2, "4": 2, "document": [2, 29], "instal": [2, 5], "import": [2, 19], "learn": 2, "resourc": 2, "contribut": 2, "report": 2, "support": [2, 33], "configur": 3, "file": [3, 14], "note": [3, 4, 5, 6, 12, 16, 27, 31, 33, 34], "write": 3, "bash": 3, "profil": 3, "prerequisit": 4, "virtual": 4, "python": 4, "environ": 4, "recommend": 4, "creat": [4, 32], "comput": 4, "chemistri": 4, "softwar": 4, "materi": 4, "project": 4, "base": [4, 16, 25], "librari": 4, "mongodb": 4, "set": 4, "up": 4, "test": [4, 6, 23], "your": 4, "connect": 4, "mdproptool": 5, "method": 5, "1": 5, "us": 5, "pip": 5, "2": 5, "develop": 5, "mode": 5, "post": 5, "run": [6, 21, 34], "workflow": [6, 15, 16, 19, 25, 31, 32, 33, 34], "initi": 6, "databas": [6, 11, 20], "warn": 6, "add": 6, "verifi": 6, "submit": 6, "monitor": 6, "queri": 6, "result": 6, "keyword": 7, "licens": 8, "packag": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], "subpackag": [9, 11, 15, 17, 20], "modul": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 30], "content": [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], "common": 10, "submodul": [10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], "pubchem": 10, "gaussian": [11, 12, 13, 14, 15, 16], "default": [11, 17, 20], "firetask": [12, 18, 21], "geo_transform": 12, "parse_output": [12, 21], "run_calc": 12, "write_input": [12, 21], "firework": [13, 22], "break_mol": 13, "core": [13, 16, 19, 22], "util": [14, 24], "db_util": 14, "dbdoc": 14, "fw_util": 14, "gout": 14, "input": 14, "metadata": 14, "misc": 14, "mol": 14, "rdkit": 14, "bde": [16, 34], "binding_energi": 16, "esp": [16, 34], "ip_ea": 16, "nmr": [16, 19], "hybrid": [17, 18, 19, 34], "nmr_from_md": 18, "lammp": [20, 21, 22, 23, 24, 25], "antechamb": 23, "base_test": 23, "control": 23, "custom_data_workflow": 23, "data": 23, "electrolyte_wf": 23, "esp_to_ff_dict_custom": 23, "esp_to_ff_dict_funct": 23, "liquid_wf_loc": 23, "parmchk": 23, "prmtop": 23, "run_lammp": 23, "tleap": 23, "opl": 24, "overview": 27, "faq": 28, "help": 29, "link": 29, "code": 29, "capsul": 29, "setup": 30, "basic": 31, "custom": 32, "tutori": 34, "an": 34, "md": 34}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinx": 56}, "docurls": ["changelog.html", "citing.html", "index.html", "installation/configuration.html", "installation/dependencies.html", "installation/index.html", "installation/test.html", "keywords.html", "license.html", "mispr.html", "mispr.common.html", "mispr.gaussian.html", "mispr.gaussian.firetasks.html", "mispr.gaussian.fireworks.html", "mispr.gaussian.utilities.html", "mispr.gaussian.workflows.html", "mispr.gaussian.workflows.base.html", "mispr.hybrid.html", "mispr.hybrid.firetasks.html", "mispr.hybrid.workflows.html", "mispr.lammps.html", "mispr.lammps.firetasks.html", "mispr.lammps.fireworks.html", "mispr.lammps.tests.html", "mispr.lammps.utilities.html", "mispr.lammps.workflows.html", "modules.html", "overview.html", "resources/faq.html", "resources/resources.html", "setup.html", "workflows/basics.html", "workflows/custom.html", "workflows/supported.html", "workflows/tutorials.html"]}) \ No newline at end of file diff --git a/html/setup.html b/html/setup.html new file mode 100644 index 00000000..3d176575 --- /dev/null +++ b/html/setup.html @@ -0,0 +1,729 @@ + + + + + + + + + + + + + + + + setup module - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

setup moduleΒΆ

+ + + + + + + +
+
+ + +
+ +
+ +
+ + + + +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/workflows/basics.html b/html/workflows/basics.html new file mode 100644 index 00000000..b6bcf8bb --- /dev/null +++ b/html/workflows/basics.html @@ -0,0 +1,835 @@ + + + + + + + + + + + + + + + + Workflow Basics - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Workflow BasicsΒΆ

+

A scientific workflow in MISPR provides a complete description of the +procedure leading to the final data used to predict the desired property +of a given molecule or system. It consists of multiple steps ranging +from the initial setup of a molecule or system of molecules to a +sequence of calculations with dependencies and optional automated +post-processing of parsed data to derive properties of interest.

+
+

Note

+

The workflow model we use to encode DFT and MD recipes in MISPR is +defined by the FireWorks workflow software.

+
+

A workflow in FireWorks is modeled as a Directed Acyclic Graph +representing the chain of relationships between +computational operations. A workflow consists of one or more Fireworks +(jobs) with dependencies. The workflow contains information +about the links between Fireworks to execute them in the correct order. +Each Firework consists of one or more Firetasks that run sequentially. +A Firetask is an atomic computing job that can call shell scripts, +transfer files, write/delete files, or execute other Python functions. +An example of the structure of a DFT workflow in MISPR is shown below:

+
+../_images/workflow.png +
+

Once a Workflow object is created, the user can use the FireWorks package +to execute the calculations on various computing resources. The goal of +MISPR infrastructure is to provide preset workflows for +computing properties relevant to the molecular science community and to +simplify the process of creating new workflows by using the implemented +FireWorks and Firetasks in MISPR as building blocks for custom workflows.

+

At the end of each workflow in MISPR, an analysis FireTask is performed +to analyze the results and generate a report. The report is in the form +of a JSON file and/or MongoDB document. It contains all the input parameters +used in the calculations, the output data, general information about the +calculation like the software version used (Gaussian, LAMMPS, MISPR, etc.), +the wall time the full run took, and chemical metadata about the molecule +or system of molecules (e.g. SMILES, InChI, molecular formula, etc.).

+

In general, each property predicted by MISPR workflows is the result of +multiple Gaussian or LAMMPS calculations, and the predicted property is +represented by a single file/document summarizing data and β€œraw” information +collected from different calculation steps. The MongoDB document +corresponding to a predicted property is stored in a MongoDB collection +named after the property. For example, bond dissociation energies are +stored in a bde collection in the database while electrostatic +partial charges are saved in an esp collection and so on. Some of +the analysis FireTasks also include optional plotting of the results. +Besides the final summary file/document, MISPR stores data from the +intermediate calculation steps into a collection called runs in the +database.

+

The following diagram summarizes the process in MISPR workflows to generate +the analysis files/documents:

+
+../_images/analysis.png +
+
+

Note

+

The above diagram shows one example of the structure of a workflow +where the Fireworks are executed sequentially. Some workflows contain +parallel Fireworks. However, the analysis Firework +is always the last Firework in all the workflows in MISPR.

+
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/workflows/custom.html b/html/workflows/custom.html new file mode 100644 index 00000000..d5f8b04d --- /dev/null +++ b/html/workflows/custom.html @@ -0,0 +1,776 @@ + + + + + + + + + + + + + + + + Creating Custom Workflows - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Creating Custom WorkflowsΒΆ

+

This page is under construction.

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/workflows/supported.html b/html/workflows/supported.html new file mode 100644 index 00000000..7bd404b2 --- /dev/null +++ b/html/workflows/supported.html @@ -0,0 +1,821 @@ + + + + + + + + + + + + + + + + Supported Workflows - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Supported WorkflowsΒΆ

+

Some of the workflows available as of July 2022 are:

+
    +
  • +
    DFT:
      +
    • Electrostatic partial charges (ESP)

    • +
    • NMR shifts

    • +
    • Redox potentials

    • +
    • Binding energies

    • +
    • Bond dissociation energies

    • +
    +
    +
    +
  • +
  • +
    MD:
      +
    • Initial configuration building, generation of GAFF +or OPLS parameters, +running of MD simulations

    • +
    • Analysis of output and trajectory files (e.g. RDF, coordination +number, diffusion coefficients, etc.)

    • +
    +
    +
    +
  • +
  • +
    Hybrid:
      +
    • Core workflow for optimizing the individual structure of the +mixture of components, generating their ESP charges, and using +them in MD simulations

    • +
    • NMR: deriving NMR chemicals for stable solvation structures +extracted from MD simulations

    • +
    +
    +
    +
  • +
+

One can customize any of the above workflows or create their own by reusing +the building blocks provided by MISPR. The above preset workflows are in +mispr/gaussian/workflows/base, mispr/lammps/workflows/base, and +mispr/hybrid/workflows.

+
+

Note

+

Other types of force field parameters can be provided as +inputs to the MD workflow, thereby skipping the force field +generation step.

+
+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/workflows/tutorials.html b/html/workflows/tutorials.html new file mode 100644 index 00000000..2d8901fb --- /dev/null +++ b/html/workflows/tutorials.html @@ -0,0 +1,1025 @@ + + + + + + + + + + + + + + + + Workflow Tutorials - Materials informatics for structure-property relationships + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + +

Workflow TutorialsΒΆ

+

This page is under construction.

+

Running an ESP workflowΒΆ

+

The ESP workflow calculates the partial charges on atoms of a molecule. The charges are +fit to the electrostatic potential at points selected according to the Merz-Singh-Kollman +scheme, but other schemes supported by Gaussian can be used as well.

+

The ESP workflow performs the following steps:

+
+ %%{ +init: { + 'theme': 'base', + 'themeVariables': { + 'primaryTextColor': 'black', + 'lineColor': 'lightgrey', + 'secondaryColor': 'pink', + 'tertiaryColor': 'lightgrey' + } +} +}%% + +graph TD + A[(Input Structure)] -->|Preprocessing| DFT + DFT -->| | B[Geometry Optimization] + B -->| | C[Frequency Calculation] + C -->| | D[ESP Calculation] + D -->|Postprocessing| E[(Output)] + + subgraph DFT + B[Geometry Optimization] + C[Frequency Calculation] + D[ESP Calculation] + end + + style A fill:#EBEBEB,stroke:#BB2528 + style DFT fill:#DDEEFF,stroke:#DDEEFF,font-weight:bold + style B fill:#fff,stroke-dasharray: 5, 5, stroke:#BB2528 + style C fill:#fff,stroke-dasharray: 5, 5, stroke:#BB2528 + style D fill:#fff,stroke:#BB2528 + style E fill:#EBEBEB,stroke:#BB2528 +
+

Note

+

The geometry optimization and frequency calculation steps (marked with a dashed +border in the above diagram) are optional. If the input structure is already +optimized, the workflow will skip these steps.

+
+

In the following example, we will run the ESP workflow on a monoglyme molecule.

+
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
from fireworks import LaunchPad
+
+from mispr.gaussian.workflows.base.esp import get_esp_charges
+
+lpad = LaunchPad.auto_load()
+
+wf, _ = get_esp_charges(
+    mol_operation_type="get_from_pubchem", # (1)!
+    mol="monoglyme",
+    format_chk=True,
+    save_to_db=True,
+    save_to_file=True,
+    additional_prop_doc_fields={"name": "monoglyme"},
+    tag="mispr_tutorial",
+)
+lpad.add_wf(wf) # (2)!
+
+
    +
  1. mol_operation_type refers to the operation to be performed on the input to process the molecule.

    +

    In this example, we are requesting to directly retrieve the molecule from PubChem by providing a +common name for the molecule to be used as query criteria for searching the PubChem database via +the mol input argument. For a list of supported mol_operation_type and the corresponding +mol, refer to mispr.gaussian.utilities.mol.process_mol().

    +
  2. +
  3. Adds the workflow to the launchpad.

  4. +
+
+

Download esp_tutorial.py.

+

Run the script using the following command:

+
python esp_tutorial.py
+
+
+

And then launch the job through the queueing system using the following command:

+
qlaunch rapidfire # (1)!
+
+
    +
  1. This command can submit a large number of jobs at once +or maintain a certain number of jobs in the queue.

  2. +
+
+

The workflow will run and create a directory named C4H10O2 in the current working +directory. The directory will contain the following subdirectories:

+
C4H10O2
+β”œβ”€β”€ Optimization
+β”œβ”€β”€ Frequency
+β”œβ”€β”€ ESP
+β”œβ”€β”€ analysis
+
+
+

Inside the Optimization, Frequency, and ESP subdirectories, you +will find the Gaussian input and output files for the corresponding step. Inside the +Optimization subdirectory, you will also find a β€œconvergence.png” figure that +shows the forces and displacement convergence during the course of the optimization.

+
+../_images/convergence.png +
+

The analysis subdirectory contains the results of the workflow in the form of a +esp.json file. You can read the content of the esp.json file using the +following commands:

+
1
+2
+3
+4
+5
+6
import json
+
+with open("C4H10O2/analysis/esp.json", "r") as f:
+    esp = json.load(f)
+
+print(esp["esp"])
+
+
+

This will output the partial charges on the atoms of the molecule:

+
{
+"1": ["O", -0.374646],
+"2": ["O", -0.373831],
+"3": ["C", 0.132166],
+"4": ["C", 0.132716],
+"5": ["C", 0.034284],
+"6": ["C", 0.031733],
+"7": ["H", 0.033853],
+"8": ["H", 0.034024],
+"9": ["H", 0.034218],
+"10": ["H", 0.034388],
+"11": ["H", 0.070724],
+"12": ["H", 0.03474],
+"13": ["H", 0.03438],
+"14": ["H", 0.034621],
+"15": ["H", 0.071656],
+"16": ["H", 0.034974],
+}
+
+
+

Running a BDE workflowΒΆ

+

Running an MD workflowΒΆ

+

Running a hybrid workflowΒΆ

+ + + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..5896b1de --- /dev/null +++ b/index.html @@ -0,0 +1 @@ + \ No newline at end of file