示例#1
0
 def _run_statmech(self,
                   arkane_spc,
                   arkane_file,
                   output_file_path=None,
                   use_bac=False,
                   kinetics=False,
                   plot=False):
     """
     A helper function for running an Arkane statmech job
     `arkane_spc` is the species() function from Arkane's input.py
     `arkane_file` is the Arkane species file (either .py or YAML form)
     `output_file_path` is a path to the Arkane output.py file
     `use_bac` is a bool flag indicating whether or not to use bond additivity corrections
     `kinetics` is a bool flag indicating whether this specie sis part of a kinetics job, in which case..??
     `plot` is a bool flag indicating whether or not to plot a PDF of the calculated thermo properties
     """
     success = True
     stat_mech_job = StatMechJob(arkane_spc, arkane_file)
     stat_mech_job.applyBondEnergyCorrections = use_bac and not kinetics and self.model_chemistry
     if not kinetics or kinetics and self.model_chemistry:
         # currently we have to use a model chemistry for thermo
         stat_mech_job.modelChemistry = self.model_chemistry
     else:
         # if this is a klinetics computation and we don't have a valid model chemistry, don't bother about it
         stat_mech_job.applyAtomEnergyCorrections = False
     stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor(
         self.model_chemistry)
     try:
         stat_mech_job.execute(outputFile=output_file_path, plot=plot)
     except Exception:
         success = False
     return success
示例#2
0
    def _run_statmech(self, arkane_spc, arkane_file, output_path=None, use_bac=False, kinetics=False, plot=False):
        """
        A helper function for running an Arkane statmech job.

        Args:
            arkane_spc (str): An Arkane species() function representor.
            arkane_file (str): The path to the Arkane species file (either in .py or YAML form).
            output_path (str): The path to the folder containing the Arkane output.py file.
            use_bac (bool): A flag indicating whether or not to use bond additivity corrections (True to use).
            kinetics (bool) A flag indicating whether this specie is part of a kinetics job.
            plot (bool): A flag indicating whether to plot a PDF of the calculated thermo properties (True to plot)

        Returns:
            bool: Whether the job was successful (True for successful).
        """
        success = True
        stat_mech_job = StatMechJob(arkane_spc, arkane_file)
        stat_mech_job.applyBondEnergyCorrections = use_bac and not kinetics and self.sp_level
        if not kinetics or (kinetics and self.sp_level):
            # currently we have to use a model chemistry for thermo
            stat_mech_job.modelChemistry = self.sp_level
        else:
            # if this is a kinetics computation and we don't have a valid model chemistry, don't bother about it
            stat_mech_job.applyAtomEnergyCorrections = False
        # Use the scaling factor if given, else try determining it from Arkane
        # (defaults to 1 and prints a warning if not found)
        stat_mech_job.frequencyScaleFactor = self.freq_scale_factor or assign_frequency_scale_factor(self.freq_level)
        try:
            stat_mech_job.execute(output_directory=os.path.join(output_path, 'output.py'), plot=plot)
        except Exception:
            success = False
        return success
示例#3
0
    def test_specifying_absolute_file_paths(self):
        """Test specifying absolute file paths of statmech files"""
        h2o2_input = """#!/usr/bin/env python
# -*- coding: utf-8 -*-

bonds = {{'H-O': 2, 'O-O': 1}}

externalSymmetry = 2

spinMultiplicity = 1

opticalIsomers = 1

energy = {{'b3lyp/6-311+g(3df,2p)': Log('{energy}')}}

geometry = Log('{freq}')

frequencies = Log('{freq}')

rotors = [HinderedRotor(scanLog=Log('{scan}'), pivots=[1, 2], top=[1, 3], symmetry=1, fit='fourier')]

"""
        abs_arkane_path = os.path.abspath(os.path.dirname(
            __file__))  # this is the absolute path to `.../RMG-Py/arkane`
        energy_path = os.path.join('arkane', 'data', 'H2O2', 'sp_a19032.out')
        freq_path = os.path.join('arkane', 'data', 'H2O2', 'freq_a19031.out')
        scan_path = os.path.join('arkane', 'data', 'H2O2', 'scan_a19034.out')
        h2o2_input = h2o2_input.format(energy=energy_path,
                                       freq=freq_path,
                                       scan=scan_path)
        h2o2_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'H2O2.py')
        if not os.path.exists(os.path.dirname(h2o2_path)):
            os.makedirs(os.path.dirname(h2o2_path))
        with open(h2o2_path, 'w') as f:
            f.write(h2o2_input)
        h2o2 = Species(label='H2O2', smiles='OO')
        self.assertIsNone(h2o2.conformer)
        statmech_job = StatMechJob(species=h2o2, path=h2o2_path)
        statmech_job.level_of_theory = LevelOfTheory('b3lyp',
                                                     '6-311+g(3df,2p)')
        statmech_job.load(pdep=False, plot=False)
        self.assertAlmostEqual(h2o2.conformer.E0.value_si, -146031.49933673252)
        os.remove(h2o2_path)
示例#4
0
文件: input.py 项目: qize/RMG-Py
def transitionState(label, *args, **kwargs):
    """Load a transition state from an input file"""
    global transition_state_dict
    if label in transition_state_dict:
        raise ValueError(
            'Multiple occurrences of transition state with label {0!r}.'.
            format(label))
    logging.info('Loading transition state {0}...'.format(label))
    ts = TransitionState(label=label)
    transition_state_dict[label] = ts

    if len(args) == 1 and len(kwargs) == 0:
        # The argument is a path to a conformer input file
        path = args[0]
        job = StatMechJob(species=ts, path=path)
        job_list.append(job)

    elif len(args) == 0:
        # The species parameters are given explicitly
        E0 = None
        modes = []
        spin_multiplicity = 1
        optical_isomers = 1
        frequency = None
        for key, value in kwargs.items():
            if key == 'E0':
                E0 = value
            elif key == 'modes':
                modes = value
            elif key == 'spinMultiplicity':
                spin_multiplicity = value
            elif key == 'opticalIsomers':
                optical_isomers = value
            elif key == 'frequency':
                frequency = value
            else:
                raise TypeError(
                    'transition_state() got an unexpected keyword argument {0!r}.'
                    .format(key))

        ts.conformer = Conformer(E0=E0,
                                 modes=modes,
                                 spin_multiplicity=spin_multiplicity,
                                 optical_isomers=optical_isomers)
        ts.frequency = frequency
    else:
        if len(args) == 0 and len(kwargs) == 0:
            raise InputError(
                'The transition_state needs to reference a quantum job file or contain kinetic information.'
            )
        raise InputError(
            'The transition_state can only link a quantum job or directly input information, not both.'
        )

    return ts
示例#5
0
文件: input.py 项目: qize/RMG-Py
def species(label, *args, **kwargs):
    """Load a species from an input file"""
    global species_dict, job_list
    if label in species_dict:
        raise ValueError(
            'Multiple occurrences of species with label {0!r}.'.format(label))
    logging.info('Loading species {0}...'.format(label))

    spec = Species(label=label)
    species_dict[label] = spec

    path = None
    if len(args) == 1:
        # The argument is a path to a conformer input file
        path = args[0]
        job = StatMechJob(species=spec, path=path)
        logging.debug('Added species {0} to a stat mech job.'.format(label))
        job_list.append(job)
    elif len(args) > 1:
        raise InputError('species {0} can only have two non-keyword argument '
                         'which should be the species label and the '
                         'path to a quantum file.'.format(spec.label))

    if len(kwargs) > 0:
        # The species parameters are given explicitly
        structure = None
        E0 = None
        modes = []
        spin_multiplicity = 0
        optical_isomers = 1
        molecular_weight = None
        collision_model = None
        energy_transfer_model = None
        thermo = None
        reactive = True
        for key, value in kwargs.items():
            if key == 'structure':
                structure = value
            elif key == 'E0':
                E0 = value
            elif key == 'modes':
                modes = value
            elif key == 'spinMultiplicity':
                spin_multiplicity = value
            elif key == 'opticalIsomers':
                optical_isomers = value
            elif key == 'molecularWeight':
                molecular_weight = value
            elif key == 'collisionModel':
                collision_model = value
            elif key == 'energyTransferModel':
                energy_transfer_model = value
            elif key == 'thermo':
                thermo = value
            elif key == 'reactive':
                reactive = value
            else:
                raise TypeError(
                    'species() got an unexpected keyword argument {0!r}.'.
                    format(key))

        if structure:
            spec.molecule = [structure]
        spec.conformer = Conformer(E0=E0,
                                   modes=modes,
                                   spin_multiplicity=spin_multiplicity,
                                   optical_isomers=optical_isomers)
        if molecular_weight is not None:
            spec.molecular_weight = molecular_weight
        elif spec.molecular_weight is None and is_pdep(job_list):
            # If a structure was given, simply calling spec.molecular_weight will calculate the molecular weight
            # If one of the jobs is pdep and no molecular weight is given or calculated, raise an error
            raise ValueError(
                "No molecularWeight was entered for species {0}. Since a structure wasn't given"
                " as well, the molecularWeight, which is important for pressure dependent jobs,"
                " cannot be reconstructed.".format(spec.label))
        spec.transport_data = collision_model
        spec.energy_transfer_model = energy_transfer_model
        spec.thermo = thermo
        spec.reactive = reactive

        if spec.reactive and path is None and spec.thermo is None and spec.conformer.E0 is None:
            if not spec.molecule:
                raise InputError(
                    'Neither thermo, E0, species file path, nor structure specified, cannot estimate'
                    ' thermo properties of species {0}'.format(spec.label))
            try:
                db = get_db('thermo')
                if db is None:
                    raise DatabaseError('Thermo database is None.')
            except DatabaseError:
                logging.warning(
                    "The database isn't loaded, cannot estimate thermo for {0}. "
                    "If it is a bath gas, set reactive = False to avoid generating "
                    "thermo.".format(spec.label))
            else:
                logging.info(
                    'No E0 or thermo found, estimating thermo and E0 of species {0} using'
                    ' RMG-Database...'.format(spec.label))
                spec.thermo = db.get_thermo_data(spec)
                if spec.thermo.E0 is None:
                    th = spec.thermo.to_wilhoit()
                    spec.conformer.E0 = th.E0
                    spec.thermo.E0 = th.E0
                else:
                    spec.conformer.E0 = spec.thermo.E0

        if spec.reactive and spec.thermo and not spec.has_statmech(
        ) and structure is not None:
            # generate stat mech info if it wasn't provided before
            spec.generate_statmech()

        if not energy_transfer_model:
            # default to RMG's method of generating energy_transfer_model
            spec.generate_energy_transfer_model()

    return spec
示例#6
0
    def process(self):
        """Process ARC outputs and generate thermo and kinetics"""
        # Thermo:
        species_list_for_thermo_parity = list()
        species_for_thermo_lib = list()
        for species in self.species_dict.values():
            if not species.is_ts and 'ALL converged' in self.output[
                    species.label]['status']:
                species_for_thermo_lib.append(species)
                output_file_path = self._generate_arkane_species_file(species)
                arkane_spc = arkane_species(str(species.label),
                                            species.arkane_file)
                if species.mol_list:
                    arkane_spc.molecule = species.mol_list
                stat_mech_job = StatMechJob(arkane_spc, species.arkane_file)
                stat_mech_job.applyBondEnergyCorrections = self.use_bac
                stat_mech_job.modelChemistry = self.model_chemistry
                stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor(
                    self.model_chemistry)
                stat_mech_job.execute(outputFile=output_file_path, plot=False)
                if species.generate_thermo:
                    thermo_job = ThermoJob(arkane_spc, 'NASA')
                    thermo_job.execute(outputFile=output_file_path, plot=False)
                    species.thermo = arkane_spc.getThermoData()
                    plotter.log_thermo(species.label, path=output_file_path)

                species.rmg_species = Species(molecule=[species.mol])
                species.rmg_species.reactive = True
                if species.mol_list:
                    species.rmg_species.molecule = species.mol_list  # add resonance structures for thermo determination
                try:
                    species.rmg_thermo = self.rmgdb.thermo.getThermoData(
                        species.rmg_species)
                except ValueError:
                    logging.info(
                        'Could not retrieve RMG thermo for species {0}, possibly due to missing 2D structure '
                        '(bond orders). Not including this species in the parity plots.'
                        .format(species.label))
                else:
                    if species.generate_thermo:
                        species_list_for_thermo_parity.append(species)
        # Kinetics:
        rxn_list_for_kinetics_plots = list()
        arkane_spc_dict = dict()  # a dictionary with all species and the TSs
        for rxn in self.rxn_list:
            logging.info('\n\n')
            species = self.species_dict[rxn.ts_label]  # The TS
            if 'ALL converged' in self.output[
                    species.label]['status'] and rxn.check_ts():
                self.copy_freq_output_for_ts(species.label)
                success = True
                rxn_list_for_kinetics_plots.append(rxn)
                output_file_path = self._generate_arkane_species_file(species)
                arkane_ts = arkane_transition_state(str(species.label),
                                                    species.arkane_file)
                arkane_spc_dict[species.label] = arkane_ts
                stat_mech_job = StatMechJob(arkane_ts, species.arkane_file)
                stat_mech_job.applyBondEnergyCorrections = False
                if not self.model_chemistry:
                    stat_mech_job.modelChemistry = self.model_chemistry
                else:
                    stat_mech_job.applyAtomEnergyCorrections = False
                stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor(
                    self.model_chemistry)
                stat_mech_job.execute(outputFile=None, plot=False)
                for spc in rxn.r_species + rxn.p_species:
                    if spc.label not in arkane_spc_dict.keys():
                        # add an extra character to the arkane_species label to distinguish between species calculated
                        #  for thermo and species calculated for kinetics (where we don't want to use BAC)
                        arkane_spc = arkane_species(str(spc.label + '_'),
                                                    spc.arkane_file)
                        stat_mech_job = StatMechJob(arkane_spc,
                                                    spc.arkane_file)
                        arkane_spc_dict[spc.label] = arkane_spc
                        stat_mech_job.applyBondEnergyCorrections = False
                        if not self.model_chemistry:
                            stat_mech_job.modelChemistry = self.model_chemistry
                        else:
                            stat_mech_job.applyAtomEnergyCorrections = False
                        stat_mech_job.frequencyScaleFactor = assign_frequency_scale_factor(
                            self.model_chemistry)
                        stat_mech_job.execute(outputFile=None, plot=False)
                        # thermo_job = ThermoJob(arkane_spc, 'NASA')
                        # thermo_job.execute(outputFile=None, plot=False)
                        # arkane_spc.thermo = arkane_spc.getThermoData()
                rxn.dh_rxn298 = sum([product.thermo.getEnthalpy(298) for product in arkane_spc_dict.values()
                                     if product.label in rxn.products])\
                                - sum([reactant.thermo.getEnthalpy(298) for reactant in arkane_spc_dict.values()
                                       if reactant.label in rxn.reactants])
                arkane_rxn = arkane_reaction(
                    label=str(rxn.label),
                    reactants=[
                        str(label + '_') for label in arkane_spc_dict.keys()
                        if label in rxn.reactants
                    ],
                    products=[
                        str(label + '_') for label in arkane_spc_dict.keys()
                        if label in rxn.products
                    ],
                    transitionState=rxn.ts_label,
                    tunneling='Eckart')
                kinetics_job = KineticsJob(reaction=arkane_rxn,
                                           Tmin=self.t_min,
                                           Tmax=self.t_max,
                                           Tcount=self.t_count)
                logging.info('Calculating rate for reaction {0}'.format(
                    rxn.label))
                try:
                    kinetics_job.execute(outputFile=output_file_path,
                                         plot=False)
                except ValueError as e:
                    """
                    ValueError: One or both of the barrier heights of -9.35259 and 62.6834 kJ/mol encountered in Eckart
                    method are invalid.
                    """
                    logging.error(
                        'Failed to generate kinetics for {0} with message:\n{1}'
                        .format(rxn.label, e))
                    success = False
                if success:
                    rxn.kinetics = kinetics_job.reaction.kinetics
                    plotter.log_kinetics(species.label, path=output_file_path)
                    rxn.rmg_reactions = rmgdb.determine_rmg_kinetics(
                        rmgdb=self.rmgdb,
                        reaction=rxn.rmg_reaction,
                        dh_rxn298=rxn.dh_rxn298)

        logging.info('\n\n')
        output_dir = os.path.join(self.project_directory, 'output')

        if species_list_for_thermo_parity:
            plotter.draw_thermo_parity_plots(species_list_for_thermo_parity,
                                             path=output_dir)
            libraries_path = os.path.join(output_dir, 'RMG libraries')
            # species_list = [spc for spc in self.species_dict.values()]
            plotter.save_thermo_lib(species_for_thermo_lib,
                                    path=libraries_path,
                                    name=self.project,
                                    lib_long_desc=self.lib_long_desc)
        if rxn_list_for_kinetics_plots:
            plotter.draw_kinetics_plots(rxn_list_for_kinetics_plots,
                                        path=output_dir,
                                        t_min=self.t_min,
                                        t_max=self.t_max,
                                        t_count=self.t_count)
            libraries_path = os.path.join(output_dir, 'RMG libraries')
            plotter.save_kinetics_lib(rxn_list=rxn_list_for_kinetics_plots,
                                      path=libraries_path,
                                      name=self.project,
                                      lib_long_desc=self.lib_long_desc)

        self.clean_output_directory()
示例#7
0
文件: arkane.py 项目: rvkmr1989/ARC
    def run_statmech(self,
                     arkane_species: Type[Species],
                     arkane_file_path: str,
                     arkane_output_path: str = None,
                     bac_type: Optional[str] = None,
                     sp_level: Optional[Level] = None,
                     plot: bool = False,
                     ) -> bool:
        """
        A helper function for running an Arkane statmech job.

        Args:
            arkane_species (arkane_input_species): An instance of an Arkane species() object.
            arkane_file_path (str): The path to the Arkane species file (either in .py or YAML form).
            arkane_output_path (str): The path to the folder in which the Arkane output.py file will be saved.
            bac_type (str, optional): The bond additivity correction type. 'p' for Petersson- or 'm' for Melius-type BAC.
                                      ``None`` to not use BAC.
            sp_level (Level, optional): The level of theory used for energy corrections.
            plot (bool): A flag indicating whether to plot a PDF of the calculated thermo properties (True to plot)

        Returns:
            bool: Whether the statmech job was successful.
        """
        success = True
        stat_mech_job = StatMechJob(arkane_species, arkane_file_path)
        stat_mech_job.applyBondEnergyCorrections = bac_type is not None and sp_level is not None
        if bac_type is not None:
            stat_mech_job.bondEnergyCorrectionType = bac_type
        if sp_level is None:
            # if this is a kinetics computation and we don't have a valid model chemistry, don't bother about it
            stat_mech_job.applyAtomEnergyCorrections = False
        else:
            stat_mech_job.level_of_theory = sp_level.to_arkane_level_of_theory()
        stat_mech_job.frequencyScaleFactor = self.freq_scale_factor
        try:
            stat_mech_job.execute(output_directory=arkane_output_path, plot=plot)
        except Exception as e:
            logger.error(f'Arkane statmech job for species {arkane_species.label} failed with the error message:\n{e}')
            if stat_mech_job.applyBondEnergyCorrections \
                    and 'missing' in str(e).lower() and 'bac parameters for model chemistry' in str(e).lower():
                # try executing Arkane w/o BACs
                logger.warning('Trying to run Arkane without BACs')
                stat_mech_job.applyBondEnergyCorrections = False
                try:
                    stat_mech_job.execute(output_directory=arkane_output_path, plot=plot)
                except Exception as e:
                    logger.error(f'Arkane statmech job for {arkane_species.label} failed with the error message:\n{e}')
                    success = False
            else:
                success = False
        return success