diff --git a/arc/main.py b/arc/main.py index 7d62bf6d03..c6e5618757 100644 --- a/arc/main.py +++ b/arc/main.py @@ -155,6 +155,7 @@ class ARC(object): Only used for restarting. running_jobs (dict, optional): A dictionary of jobs submitted in a precious ARC instance, used for restarting. ts_adapters (list, optional): Entries represent different TS adapters. + only_process (bool, optional): Whether to only run statmech and process runs from a (restart) input file. Attributes: project (str): The project's name. Used for naming the working directory. @@ -221,6 +222,7 @@ class ARC(object): format (``True``) or classical two-parameter Arrhenius equation format (``False``). trsh_ess_jobs (bool): Whether to attempt troubleshooting failed ESS jobs. Default is ``True``. ts_adapters (list): Entries represent different TS adapters. + only_process (bool): Whether to only run statmech and process runs from a (restart) input file. """ def __init__(self, @@ -249,6 +251,7 @@ def __init__(self, level_of_theory: str = '', max_job_time: Optional[float] = None, n_confs: int = 10, + only_process: bool = False, opt_level: Optional[Union[str, dict, Level]] = None, orbitals_level: Optional[Union[str, dict, Level]] = None, output: Optional[dict] = None, @@ -323,6 +326,7 @@ def __init__(self, for ts_adapter in self.ts_adapters or list(): if ts_adapter.lower() not in _registered_job_adapters.keys(): raise InputError(f'Unknown TS adapter: "{ts_adapter}"') + self.only_process = only_process # attributes related to level of theory specifications self.level_of_theory = level_of_theory @@ -475,6 +479,8 @@ def as_dict(self) -> dict: restart_dict['dont_gen_confs'] = self.dont_gen_confs if self.ts_adapters: restart_dict['ts_adapters'] = self.ts_adapters + if self.only_process: + restart_dict['only_process'] = self.only_process restart_dict['e_confs'] = self.e_confs restart_dict['ess_settings'] = self.ess_settings if self.freq_level is not None: @@ -592,6 +598,7 @@ def execute(self) -> dict: trsh_ess_jobs=self.trsh_ess_jobs, fine_only=self.fine_only, ts_adapters=self.ts_adapters, + only_process=self.only_process, ) save_yaml_file(path=os.path.join(self.project_directory, 'output', 'status.yml'), content=self.scheduler.output) diff --git a/arc/plotter.py b/arc/plotter.py index 5b52a9f0bf..ea13a91c2e 100644 --- a/arc/plotter.py +++ b/arc/plotter.py @@ -777,11 +777,11 @@ def save_thermo_lib(species_list: list, try: thermo_library.load_entry(index=i, label=spc.label, - molecule=spc.mol_list[0].copy(deep=True).to_adjacency_list(), + molecule=spc.adjlist or spc.mol_list[0].copy(deep=True).to_adjacency_list(), thermo=spc.thermo, shortDesc=spc.thermo.comment, longDesc=spc.long_thermo_description) - except (InvalidAdjacencyListError, DatabaseError, ValueError) as e: + except (InvalidAdjacencyListError, DatabaseError, ValueError, TypeError) as e: logger.error(f'Could not save species {spc.label} in the thermo library, got:') logger.info(e) else: @@ -806,11 +806,11 @@ def save_transport_lib(species_list, path, name, lib_long_desc=''): try: transport_library.load_entry(index=i, label=spc.label, - molecule=spc.mol_list[0].copy(deep=True).to_adjacency_list(), + molecule=spc.adjlist or spc.mol_list[0].copy(deep=True).to_adjacency_list(), transport=spc.transport_data, shortDesc=spc.thermo.comment, longDesc=description) - except (InvalidAdjacencyListError, ValueError) as e: + except (InvalidAdjacencyListError, DatabaseError, ValueError, TypeError) as e: logger.error(f'Could not save species {spc.label} in the transport library, got:') logger.info(e) logger.info(f'\n\nTransport properties for {spc.label}:') diff --git a/arc/reaction_test.py b/arc/reaction_test.py index 2d2d624220..4457cbf2d0 100644 --- a/arc/reaction_test.py +++ b/arc/reaction_test.py @@ -121,20 +121,22 @@ def setUpClass(cls): r_species=[ARCSpecies(label='NH2', smiles='[NH2]'), ARCSpecies(label='N2H3', smiles='N[NH]')], p_species=[ARCSpecies(label='NH3', smiles='N'), - ARCSpecies(label='H2NN(S)', adjlist="""multiplicity 1 - 1 N u0 p0 c+1 {2,D} {3,S} {4,S} - 2 N u0 p2 c-1 {1,D} - 3 H u0 p0 c0 {1,S} - 4 H u0 p0 c0 {1,S}""")]) + ARCSpecies(label='H2NN(S)', + adjlist="""multiplicity 1 +1 N u0 p0 c+1 {2,D} {3,S} {4,S} +2 N u0 p2 c-1 {1,D} +3 H u0 p0 c0 {1,S} +4 H u0 p0 c0 {1,S}""")]) cls.rxn7 = ARCReaction(reactants=['NH2', 'N2H3'], products=['NH3', 'H2NN(T)'], r_species=[ARCSpecies(label='NH2', smiles='[NH2]'), ARCSpecies(label='N2H3', smiles='N[NH]')], p_species=[ARCSpecies(label='NH3', smiles='N'), - ARCSpecies(label='H2NN(T)', adjlist="""multiplicity 3 - 1 N u0 p1 c0 {2,S} {3,S} {4,S} - 2 N u2 p1 c0 {1,S} - 3 H u0 p0 c0 {1,S} - 4 H u0 p0 c0 {1,S}""")]) + ARCSpecies(label='H2NN(T)', + adjlist="""multiplicity 3 +1 N u0 p1 c0 {2,S} {3,S} {4,S} +2 N u2 p1 c0 {1,S} +3 H u0 p0 c0 {1,S} +4 H u0 p0 c0 {1,S}""")]) cls.rxn8 = ARCReaction(r_species=[ARCSpecies(label='CH4', smiles='C', xyz=cls.ch4_xyz), ARCSpecies(label='OH', smiles='[OH]', xyz=cls.oh_xyz)], p_species=[ARCSpecies(label='CH3', smiles='[CH3]', xyz=cls.ch3_xyz), @@ -278,6 +280,11 @@ def test_as_dict(self): 'multiplicity': 1, 'number_of_rotors': 0}, {'arkane_file': None, + 'adjlist': """multiplicity 1 +1 N u0 p0 c+1 {2,D} {3,S} {4,S} +2 N u0 p2 c-1 {1,D} +3 H u0 p0 c0 {1,S} +4 H u0 p0 c0 {1,S}""", 'bond_corrections': {'H-N': 2, 'N=N': 1}, 'charge': 0, 'cheap_conformer': 'N -0.08201544 0.01567102 0.28740725\n' @@ -341,6 +348,13 @@ def test_as_dict(self): 'ts_xyz_guess': []} self.assertEqual(rxn_dict_6, expected_dict_6) + rxn_7_dict = self.rxn7.as_dict() + self.assertEqual(rxn_7_dict['p_species'][1]['adjlist'], """multiplicity 3 +1 N u0 p1 c0 {2,S} {3,S} {4,S} +2 N u2 p1 c0 {1,S} +3 H u0 p0 c0 {1,S} +4 H u0 p0 c0 {1,S}""") + def test_from_dict(self): """Test ARCReaction.from_dict()""" rxn_dict = self.rxn1.as_dict() diff --git a/arc/scheduler.py b/arc/scheduler.py index aeab89a643..2d206b80cb 100644 --- a/arc/scheduler.py +++ b/arc/scheduler.py @@ -160,6 +160,7 @@ class Scheduler(object): freq_scale_factor (float, optional): The harmonic frequencies scaling factor. trsh_ess_jobs (bool, optional): Whether to attempt troubleshooting failed ESS jobs. Default is ``True``. ts_adapters (list, optional): Entries represent different TS adapters. + only_process (bool, optional): Whether to only run statmech and process runs from a (restart) input file. Attributes: project (str): The project's name. Used for naming the working directory. @@ -248,6 +249,7 @@ def __init__(self, kinetics_adapter: str = 'arkane', freq_scale_factor: float = 1.0, ts_adapters: List[str] = None, + only_process: bool = False, ) -> None: self.project = project @@ -409,7 +411,9 @@ def __init__(self, species.initial_xyz = species.conformers[0] if species.label not in self.running_jobs: self.running_jobs[species.label] = list() # initialize before running the first job - if species.is_monoatomic(): + if only_process: + pass + elif species.is_monoatomic(): if not self.output[species.label]['job_types']['sp'] \ and not self.output[species.label]['job_types']['composite'] \ and 'sp' not in list(self.job_dict[species.label].keys()) \ @@ -485,7 +489,7 @@ def __init__(self, species.ts_conf_spawned = True self.save_restart = True self.timer = True - if not self.testing: + if not self.testing and not only_process: self.schedule_jobs() def schedule_jobs(self): diff --git a/arc/species/species.py b/arc/species/species.py index 893b89b4a9..2c9acff680 100644 --- a/arc/species/species.py +++ b/arc/species/species.py @@ -342,6 +342,7 @@ def __init__(self, self._radius = None self.mol = mol self.mol_list = None + self.adjlist = adjlist self.multiplicity = multiplicity self.number_of_radicals = number_of_radicals self.external_symmetry = external_symmetry @@ -642,6 +643,8 @@ def as_dict(self, species_dict['number_of_rotors'] = self.number_of_rotors if self.external_symmetry is not None: species_dict['external_symmetry'] = self.external_symmetry + if self.adjlist: + species_dict['adjlist'] = self.adjlist if self.irc_label is not None: species_dict['irc_label'] = self.irc_label if self.optical_isomers is not None: @@ -783,6 +786,7 @@ def from_dict(self, species_dict): self.is_ts = species_dict['is_ts'] if 'is_ts' in species_dict else False self.ts_conf_spawned = species_dict['ts_conf_spawned'] if 'ts_conf_spawned' in species_dict \ else False if self.is_ts else None + self.adjlist = species_dict['adjlist'] if 'adjlist' in species_dict else None if self.is_ts: self.ts_number = species_dict['ts_number'] if 'ts_number' in species_dict else None self.ts_guesses_exhausted = species_dict['ts_guesses_exhausted'] if 'ts_guesses_exhausted' in species_dict else False