def load_input_file(path): """ Load the Arkane input file located at `path` on disk, and return a list of the jobs defined in that file. """ global species_dict, transition_state_dict, reaction_dict, network_dict, job_list # Clear module-level variables species_dict, transition_state_dict, reaction_dict, network_dict = dict( ), dict(), dict(), dict() job_list = [] global_context = {'__builtins__': None} local_context = { '__builtins__': None, 'True': True, 'False': False, 'range': range, # Collision 'TransportData': TransportData, 'SingleExponentialDown': SingleExponentialDown, # Kinetics 'Arrhenius': Arrhenius, 'RateUncertainty': RateUncertainty, # Statistical mechanics 'IdealGasTranslation': IdealGasTranslation, 'LinearRotor': LinearRotor, 'NonlinearRotor': NonlinearRotor, 'KRotor': KRotor, 'SphericalTopRotor': SphericalTopRotor, 'HarmonicOscillator': HarmonicOscillator, 'HinderedRotor': HinderedRotor, 'FreeRotor': FreeRotor, # Thermo 'ThermoData': ThermoData, 'Wilhoit': Wilhoit, 'NASA': NASA, 'NASAPolynomial': NASAPolynomial, # Functions 'reaction': reaction, 'species': species, 'transitionState': transitionState, 'network': network, 'database': database, # Jobs 'kinetics': kinetics, 'statmech': statmech, 'thermo': thermo, 'pressureDependence': pressureDependence, 'explorer': explorer, 'bac': bac, 'ae': ae, # Miscellaneous 'SMILES': SMILES, 'adjacencyList': adjacencyList, 'InChI': InChI, 'LevelOfTheory': LevelOfTheory, 'CompositeLevelOfTheory': CompositeLevelOfTheory, } load_necessary_databases() with open(path, 'r') as f: try: exec(f.read(), global_context, local_context) except (NameError, TypeError, SyntaxError): logging.error('The input file {0!r} was invalid:'.format(path)) raise model_chemistry = local_context.get('modelChemistry', None) level_of_theory = process_model_chemistry(model_chemistry) if isinstance(model_chemistry, LOT): model_chemistry = model_chemistry.to_model_chem() author = local_context.get('author', '') if 'frequencyScaleFactor' in local_context: frequency_scale_factor = local_context.get('frequencyScaleFactor') else: logging.debug( 'Tying to assign a frequencyScaleFactor according to the ' 'level of theory {0}'.format(level_of_theory)) frequency_scale_factor = assign_frequency_scale_factor(level_of_theory) use_hindered_rotors = local_context.get('useHinderedRotors', True) use_atom_corrections = local_context.get('useAtomCorrections', True) use_bond_corrections = local_context.get('useBondCorrections', False) bac_type = local_context.get('bondCorrectionType', 'p') use_isodesmic_reactions = local_context.get('useIsodesmicReactions', False) reference_sets = local_context.get('referenceSets', None) atom_energies = local_context.get('atomEnergies', None) directory = os.path.dirname(path) for rxn in reaction_dict.values(): rxn.elementary_high_p = True for job in job_list: if isinstance(job, StatMechJob): job.path = os.path.join(directory, job.path) job.level_of_theory = level_of_theory job.frequencyScaleFactor = frequency_scale_factor job.includeHinderedRotors = use_hindered_rotors job.applyAtomEnergyCorrections = use_atom_corrections job.applyBondEnergyCorrections = use_bond_corrections job.bondEnergyCorrectionType = bac_type job.atomEnergies = atom_energies job.useIsodesmicReactions = use_isodesmic_reactions job.referenceSets = reference_sets if isinstance(job, ThermoJob): job.arkane_species.author = author job.arkane_species.level_of_theory = level_of_theory job.arkane_species.model_chemistry = model_chemistry job.arkane_species.frequency_scale_factor = frequency_scale_factor job.arkane_species.use_hindered_rotors = use_hindered_rotors job.arkane_species.use_bond_corrections = use_bond_corrections if atom_energies is not None: job.arkane_species.atom_energies = atom_energies return job_list, reaction_dict, species_dict, transition_state_dict, network_dict, level_of_theory
def to_arkane_level_of_theory( self, variant: Optional[str] = None, bac_type: str = 'p', comprehensive: bool = False, raise_error: bool = False, warn: bool = True, ) -> Optional[LevelOfTheory]: """ Convert ``Level`` to an Arkane ``LevelOfTheory`` instance. Args: variant (str, optional): Return a variant of the Arkane ``LevelOfTheory`` that matches an Arkane query. Allowed values are ``'freq'``, ``'AEC'``, ``'BEC'``. Returns ``None`` if no functioning variant was found. bac_type (str, optional): The BAC type ('p' or 'm') to use when searching for a ``LevelOfTheory`` variant for BAC. comprehensive (bool, optional): Whether to consider all relevant arguments if not looking for a variant. raise_error (bool, optional): Whether to raise an error if an AEC variant could not be found. warn (bool, optional): Whether to output a warning if an AEC variant could not be found. Returns: LevelOfTheory: The respective Arkane ``LevelOfTheory`` object """ if variant is None: if not comprehensive: # only add basis and software if needed kwargs = {'method': self.method} if self.basis is not None: kwargs['basis'] = self.basis kwargs['software'] = self.software return LevelOfTheory(**kwargs) else: # consider all relevant arguments kwargs = self.__dict__.copy() del kwargs['solvation_scheme_level'] del kwargs['method_type'] del kwargs['repr'] del kwargs['compatible_ess'] del kwargs['dispersion'] del kwargs['args'] if self.args is not None and self.args and all( [val for val in self.args.values()]): # only pass keyword arguments to Arkane (not blocks) if any([key == 'keyword' for key in self.args.keys()]): kwargs['args'] = list() for key1, val1 in self.args.items(): if key1 == 'keyword': for val2 in val1.values(): kwargs['args'].append(val2) break else: kwargs['args'] = None if self.dispersion is not None: if 'args' not in kwargs: kwargs['args'] = [self.dispersion] else: kwargs['args'].append(self.dispersion) if kwargs['method'] is not None: kwargs['method'].replace('f12a', 'f12').replace('f12b', 'f12') if kwargs['basis'] is not None: kwargs['basis'].replace('f12a', 'f12').replace('f12b', 'f12') return LevelOfTheory(**kwargs) else: # search for a functioning variant if variant not in ['freq', 'AEC', 'BAC']: raise ValueError( f'variant must be either "freq", "AEC", or "BAC", got "{variant}".' ) kwargs = {'method': self.method} if self.basis is not None: kwargs['basis'] = self.basis if standardize_name(self.method) in METHODS_THAT_REQUIRE_SOFTWARE: # add software if mandatory (otherwise, Arkane won't accept this object initialization) kwargs['software'] = self.software var_2 = LevelOfTheory(**kwargs) kwargs['software'] = self.software # add or overwrite software # start w/ the software argument (var_1) in case there are several entries that only vary by software var_1 = LevelOfTheory(**kwargs) if variant == 'freq': # if not found, the factor is set to exactly 1 if assign_frequency_scale_factor(level_of_theory=var_1) != 1: return var_1 if assign_frequency_scale_factor(level_of_theory=var_2) != 1: return var_2 return None if variant == 'AEC': try: arkane_data.atom_energies[var_1] return var_1 except KeyError: try: arkane_data.atom_energies[var_2] return var_2 except KeyError: if raise_error: raise ValueError( f'Missing Arkane atom energy corrections for {var_1}\n' f'(If you did not mean to compute thermo, set the compute_thermo ' f'argument to False to avoid this error.)') else: if warn: logger.warning( f'Missing Arkane atom energy corrections for {var_1}.' ) return None if variant == 'BAC': if bac_type not in ['p', 'm']: raise ValueError( f'bac_type must be either "p" or "m", got "{bac_type}".' ) bac = BAC(level_of_theory=var_1, bac_type=bac_type) if bac.bacs is None: bac = BAC(level_of_theory=var_2, bac_type=bac_type) if bac.bacs is None: logger.warning(f'Missing Arkane BAC for {var_2}.') return None else: return var_2 else: return var_1
def freq_scale_factor(self): if not self._freq_scale_factor: self._freq_scale_factor = assign_frequency_scale_factor( self.model_chemistry) return self._freq_scale_factor