Exemple #1
0
def main():

    args = parseCommandLineArguments()
    if args.useOriginalReactions and not args.original:
        raise InputError(
            'Cannot use original reactions without a previously run RMG job')
    maximumIsotopicAtoms = args.maximumIsotopicAtoms[0]
    useOriginalReactions = args.useOriginalReactions
    inputFile = args.input
    outputdir = os.path.abspath(
        args.output[0]) if args.output else os.path.abspath('.')
    original = os.path.abspath(args.original[0]) if args.original else None
    kie = args.kineticIsotopeEffect[0] if args.kineticIsotopeEffect else None
    supported_kie_methods = ['simple']
    if kie not in supported_kie_methods and kie is not None:
        raise InputError(
            'The kie input, {0}, is not one of the currently supported methods, {1}'
            .format(kie, supported_kie_methods))
    initializeLog(logging.INFO, os.path.join(os.getcwd(), 'RMG.log'))
    run(inputFile,
        outputdir,
        original=original,
        maximumIsotopicAtoms=maximumIsotopicAtoms,
        useOriginalReactions=useOriginalReactions,
        kineticIsotopeEffect=kie)
Exemple #2
0
def database(
    thermoLibraries=None,
    transportLibraries=None,
    reactionLibraries=None,
    frequenciesLibraries=None,
    seedMechanisms=None,
    kineticsFamilies='default',
    kineticsDepositories='default',
    kineticsEstimator='rate rules',
):
    # This function just stores the information about the database to be loaded
    # We don't actually load the database until after we're finished reading
    # the input file
    if isinstance(thermoLibraries, str): thermoLibraries = [thermoLibraries]
    if isinstance(transportLibraries, str):
        transportLibraries = [transportLibraries]
    if isinstance(reactionLibraries, str):
        reactionLibraries = [reactionLibraries]
    if isinstance(seedMechanisms, str): seedMechanisms = [seedMechanisms]
    if isinstance(frequenciesLibraries, str):
        frequenciesLibraries = [frequenciesLibraries]
    rmg.databaseDirectory = settings['database.directory']
    rmg.thermoLibraries = thermoLibraries or []
    rmg.transportLibraries = transportLibraries
    # Modify reactionLibraries if the user didn't specify tuple input
    if reactionLibraries:
        index = 0
        while index < len(reactionLibraries):
            if isinstance(reactionLibraries[index], tuple):
                pass
            elif isinstance(reactionLibraries[index], str):
                reactionLibraries[index] = (reactionLibraries[index], False)
            else:
                raise TypeError(
                    'reaction libraries must be input as tuples or strings')
            index += 1
    rmg.reactionLibraries = reactionLibraries or []
    rmg.seedMechanisms = seedMechanisms or []
    rmg.statmechLibraries = frequenciesLibraries or []
    rmg.kineticsEstimator = kineticsEstimator
    if kineticsDepositories == 'default':
        rmg.kineticsDepositories = ['training']
    elif kineticsDepositories == 'all':
        rmg.kineticsDepositories = None
    else:
        if not isinstance(kineticsDepositories, list):
            raise InputError(
                "kineticsDepositories should be either 'default', 'all', or a list of names eg. ['training','PrIMe']."
            )
        rmg.kineticsDepositories = kineticsDepositories

    if kineticsFamilies in ('default', 'all', 'none'):
        rmg.kineticsFamilies = kineticsFamilies
    else:
        if not isinstance(kineticsFamilies, list):
            raise InputError(
                "kineticsFamilies should be either 'default', 'all', 'none', or a list of names eg. ['H_Abstraction','R_Recombination'] or ['!Intra_Disproportionation']."
            )
        rmg.kineticsFamilies = kineticsFamilies
Exemple #3
0
def database(
             thermoLibraries = None,
             transportLibraries = None,
             reactionLibraries = None,
             frequenciesLibraries = None,
             kineticsFamilies = 'default',
             kineticsDepositories = 'default',
             kineticsEstimator = 'rate rules',
             ):
    if isinstance(thermoLibraries, str):
        thermoLibraries = [thermoLibraries]
    if isinstance(transportLibraries, str):
        transportLibraries = [transportLibraries]
    if isinstance(reactionLibraries, str):
        reactionLibraries = [reactionLibraries]
    if isinstance(frequenciesLibraries, str):
        frequenciesLibraries = [frequenciesLibraries]
    
    databaseDirectory = settings['database.directory']
    thermoLibraries = thermoLibraries or []
    transportLibraries = transportLibraries
    reactionLibraries = reactionLibraries or []
    kineticsEstimator = kineticsEstimator
    
    if kineticsDepositories == 'default':
        kineticsDepositories = ['training']
    elif kineticsDepositories == 'all':
        kineticsDepositories = None
    else:
        if not isinstance(kineticsDepositories,list):
            raise InputError("kineticsDepositories should be either 'default', 'all', or a list of names eg. ['training','PrIMe'].")
        kineticsDepositories = kineticsDepositories

    if kineticsFamilies in ('default', 'all', 'none'):
        kineticsFamilies = kineticsFamilies
    else:
        if not isinstance(kineticsFamilies,list):
            raise InputError("kineticsFamilies should be either 'default', 'all', 'none', or a list of names eg. ['H_Abstraction','R_Recombination'] or ['!Intra_Disproportionation'].")
        kineticsFamilies = kineticsFamilies

    database = getDB() or RMGDatabase()

    database.load(
            path = databaseDirectory,
            thermoLibraries = thermoLibraries,
            transportLibraries = transportLibraries,
            reactionLibraries = reactionLibraries,
            seedMechanisms = [],
            kineticsFamilies = kineticsFamilies,
            kineticsDepositories = kineticsDepositories,
            depository = False, # Don't bother loading the depository information, as we don't use it
        )
    
    for family in database.kinetics.families.values(): #load training
        family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo)

    for family in database.kinetics.families.values():
        family.fillKineticsRulesByAveragingUp(verbose=True)
Exemple #4
0
    def loadGeometry(self):
        """
        Return the optimum geometry of the molecular configuration from the
        QChem log file. If multiple such geometries are identified, only the
        last is returned.
        """
        atom, coord, number, mass = [], [], [], []

        with open(self.path) as f:
            log = f.read().splitlines()

        # First check that the QChem job file (not necessarily a geometry optimization)
        # has successfully completed, if not an error is thrown
        completed_job = False
        for line in reversed(log):
            if 'Total job time:' in line:
                logging.debug('Found a sucessfully completed QChem Job')
                completed_job = True
                break

        if not completed_job:
            raise InputError(
                'Could not find a successfully completed QChem job in QChem output file {0}'
                .format(self.path))

        # Now look for the geometry.
        # Will return the final geometry in the file under Standard Nuclear Orientation.
        geometry_flag = False
        for i in reversed(xrange(len(log))):
            line = log[i]
            if 'Standard Nuclear Orientation' in line:
                for line in log[(i + 3):]:
                    if '------------' not in line:
                        data = line.split()
                        atom.append(data[1])
                        coord.append([float(c) for c in data[2:]])
                        geometry_flag = True
                    else:
                        break
                if geometry_flag:
                    break

        # Assign appropriate mass to each atom in the molecule
        for atom1 in atom:
            mass1, num1 = get_element_mass(atom1)
            mass.append(mass1)
            number.append(num1)
        coord = numpy.array(coord, numpy.float64)
        number = numpy.array(number, numpy.int)
        mass = numpy.array(mass, numpy.float64)
        if len(number) == 0 or len(coord) == 0 or len(mass) == 0:
            raise InputError(
                'Unable to read atoms from QChem geometry output file {0}'.
                format(self.path))

        return coord, number, mass
Exemple #5
0
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
Exemple #6
0
def database(thermoLibraries=None,
             transportLibraries=None,
             reactionLibraries=None,
             frequenciesLibraries=None,
             kineticsFamilies='default',
             kineticsDepositories='default',
             kineticsEstimator='rate rules'):
    """Load the RMG database"""
    thermo_libraries = as_list(thermoLibraries, default=[])
    transport_libraries = as_list(transportLibraries, default=None)
    reaction_libraries = as_list(reactionLibraries, default=[])

    database_directory = settings['database.directory']

    if kineticsDepositories == 'default':
        kinetics_depositories = ['training']
    elif kineticsDepositories == 'all':
        kinetics_depositories = None
    else:
        if not isinstance(kineticsDepositories, list):
            raise InputError(
                "kinetics_depositories should be either 'default', 'all', or a list of names eg. ['training','PrIMe']."
            )
        kinetics_depositories = kineticsDepositories

    if kineticsFamilies in ('default', 'all', 'none'):
        kinetics_families = kineticsFamilies
    else:
        if not isinstance(kineticsFamilies, list):
            raise InputError(
                "kineticsFamilies should be either 'default', 'all', 'none', or a list of names eg. "
                "['H_Abstraction','R_Recombination'] or ['!Intra_Disproportionation']."
            )
        kinetics_families = kineticsFamilies

    rmg_database = get_db() or RMGDatabase()

    rmg_database.load(
        path=database_directory,
        thermo_libraries=thermo_libraries,
        transport_libraries=transport_libraries,
        reaction_libraries=reaction_libraries,
        seed_mechanisms=[],
        kinetics_families=kinetics_families,
        kinetics_depositories=kinetics_depositories,
        depository=
        False,  # Don't bother loading the depository information, as we don't use it
    )

    for family in rmg_database.kinetics.families.values():  # load training
        if not family.auto_generated:
            family.add_rules_from_training(thermo_database=rmg_database.thermo)

    for family in rmg_database.kinetics.families.values():
        family.fill_rules_by_averaging_up(verbose=True)
Exemple #7
0
def simpleReactor(temperature,
                  pressure,
                  initialMoleFractions,
                  terminationConversion=None,
                  terminationTime=None,
                  sensitivity=None,
                  sensitivityThreshold=1e-3):
    logging.debug('Found SimpleReactor reaction system')

    for value in initialMoleFractions.values():
        if value < 0:
            raise InputError('Initial mole fractions cannot be negative.')

    for spec in initialMoleFractions:
        initialMoleFractions[spec] = float(initialMoleFractions[spec])

    totalInitialMoles = sum(initialMoleFractions.values())
    if totalInitialMoles != 1:
        logging.warning(
            'Initial mole fractions do not sum to one; normalizing.')
        logging.info('')
        logging.info('Original composition:')
        for spec, molfrac in initialMoleFractions.iteritems():
            logging.info("{0} = {1}".format(spec, molfrac))
        for spec in initialMoleFractions:
            initialMoleFractions[spec] /= totalInitialMoles
        logging.info('')
        logging.info('Normalized mole fractions:')
        for spec, molfrac in initialMoleFractions.iteritems():
            logging.info("{0} = {1}".format(spec, molfrac))

    T = Quantity(temperature)
    P = Quantity(pressure)

    termination = []
    if terminationConversion is not None:
        for spec, conv in terminationConversion.iteritems():
            termination.append(TerminationConversion(speciesDict[spec], conv))
    if terminationTime is not None:
        termination.append(TerminationTime(Quantity(terminationTime)))
    if len(termination) == 0:
        raise InputError(
            'No termination conditions specified for reaction system #{0}.'.
            format(len(rmg.reactionSystems) + 2))

    sensitiveSpecies = []
    if sensitivity:
        if isinstance(sensitivity, str): sensitivity = [sensitivity]
        for spec in sensitivity:
            sensitiveSpecies.append(speciesDict[spec])
    system = SimpleReactor(T, P, initialMoleFractions, termination,
                           sensitiveSpecies, sensitivityThreshold)
    rmg.reactionSystems.append(system)
Exemple #8
0
def model(toleranceMoveToCore=None,
          toleranceMoveEdgeReactionToCore=numpy.inf,
          toleranceKeepInEdge=0.0,
          toleranceInterruptSimulation=1.0,
          toleranceMoveEdgeReactionToSurface=numpy.inf,
          toleranceMoveSurfaceSpeciesToCore=numpy.inf,
          toleranceMoveSurfaceReactionToCore=numpy.inf,
          toleranceMoveEdgeReactionToSurfaceInterrupt=None,
          toleranceMoveEdgeReactionToCoreInterrupt=None,
          maximumEdgeSpecies=1000000,
          minCoreSizeForPrune=50,
          minSpeciesExistIterationsForPrune=2,
          filterReactions=False,
          ignoreOverallFluxCriterion=False,
          maxNumSpecies=None,
          maxNumObjsPerIter=1,
          terminateAtMaxObjects=False,
          toleranceThermoKeepSpeciesInEdge=numpy.inf,
          dynamicsTimeScale=(0.0, 'sec')):
    """
    How to generate the model. `toleranceMoveToCore` must be specified. 
    toleranceMoveReactionToCore and toleranceReactionInterruptSimulation refers to an additional criterion for forcing an edge reaction to be included in the core
    by default this criterion is turned off
    Other parameters are optional and control the pruning.
    ignoreOverallFluxCriterion=True will cause the toleranceMoveToCore to be only applied
    to the pressure dependent network expansion and not movement of species from edge to core
    """
    if toleranceMoveToCore is None:
        raise InputError(
            "You must provide a toleranceMoveToCore value. It should be less than or equal to toleranceInterruptSimulation which is currently {0}"
            .format(toleranceInterruptSimulation))
    if toleranceMoveToCore > toleranceInterruptSimulation:
        raise InputError(
            "toleranceMoveToCore must be less than or equal to toleranceInterruptSimulation, which is currently {0}"
            .format(toleranceInterruptSimulation))

    rmg.modelSettingsList.append(
        ModelSettings(toleranceMoveToCore, toleranceMoveEdgeReactionToCore,
                      toleranceKeepInEdge, toleranceInterruptSimulation,
                      toleranceMoveEdgeReactionToSurface,
                      toleranceMoveSurfaceSpeciesToCore,
                      toleranceMoveSurfaceReactionToCore,
                      toleranceMoveEdgeReactionToSurfaceInterrupt,
                      toleranceMoveEdgeReactionToCoreInterrupt,
                      maximumEdgeSpecies, minCoreSizeForPrune,
                      minSpeciesExistIterationsForPrune, filterReactions,
                      ignoreOverallFluxCriterion, maxNumSpecies,
                      maxNumObjsPerIter, terminateAtMaxObjects,
                      toleranceThermoKeepSpeciesInEdge,
                      Quantity(dynamicsTimeScale)))
Exemple #9
0
def species(label, structure, reactive=True):
    logging.debug('Found {0} species "{1}" ({2})'.format('reactive' if reactive else 'nonreactive', label, structure.toSMILES()))
    
    if '+' in label:
        raise InputError('species {0} label cannot include a + sign'.format(label))
    
    spec, isNew = rmg.reactionModel.makeNewSpecies(structure, label=label, reactive=reactive)
    if not isNew:
        raise InputError("Species {0} is a duplicate of {1}. Species in input file must be unique".format(label,spec.label))
    # Force RMG to add the species to edge first, prior to where it is added to the core, in case it is found in 
    # any reaction libraries along the way
    rmg.reactionModel.addSpeciesToEdge(spec)
    rmg.initialSpecies.append(spec)
    speciesDict[label] = spec
Exemple #10
0
def process_model_chemistry(model_chemistry):
    """Process the model chemistry string representation

    Args:
        model_chemistry (str, unicode): A representation of the model chemistry in an sp//freq format
                                        e.g., 'CCSD(T)-F12a/aug-cc-pVTZ//B3LYP/6-311++G(3df,3pd)',
                                        or a composite method, e.g. 'CBS-QB3'.

    Returns:
        str, unicode: The single point energy level of theory
        str, unicode: The frequency level of theory
    """
    if model_chemistry.count('//') > 1:
        raise InputError(
            'The model chemistry seems wrong. It should either be a composite method (like CBS-QB3) '
            'or of the form sp//geometry, e.g., CCSD(T)-F12a/aug-cc-pVTZ//B3LYP/6-311++G(3df,3pd), '
            'and should not contain more than one appearance of "//".\n'
            'Got: {0}'.format(model_chemistry))
    elif '//' in model_chemistry:
        # assume this is an sp//freq format, split
        sp_level, freq_level = model_chemistry.split('//')
    else:
        # assume the sp and freq levels are the same, assign the model chemistry to both
        # (this could also be a composite method, and we'll expect the same behavior)
        sp_level = freq_level = model_chemistry
    return sp_level, freq_level
Exemple #11
0
def convertBindingEnergies(bindingEnergies):
    """
    Process the bindingEnergies from the input file.
    If "None" is passed, then it returns Pt(111) values.

    :param bindingEnergies: a dictionary of element symbol: binding energy pairs (or None)
    :return: the processed and checked dictionary
    """
    if bindingEnergies is None:
        bindingEnergies = { # default values for Pt(111)
                       'C':(-6.750, 'eV/molecule'),
                       'H':(-2.479, 'eV/molecule'),
                       'O':(-3.586, 'eV/molecule'),
                       'N':(-4.352, 'eV/molecule'),
                       }
        logging.info("Using default binding energies for Pt(111):\n{0!r}".format(bindingEnergies))
    if not isinstance(bindingEnergies, dict): raise InputError("bindingEnergies should be None (for default) or a dict.")
    newDict = {}
    for element in 'CHON':
        try:
            newDict[element] = Energy(bindingEnergies[element])
        except KeyError:
            logging.error('Element {} missing from bindingEnergies dictionary'.format(element))
            raise
    return newDict
Exemple #12
0
def explorer(source,
             explore_tol=0.01,
             energy_tol=np.inf,
             flux_tol=0.0,
             bathGas=None,
             maximumRadicalElectrons=np.inf):
    """Generate an explorer job"""
    global job_list, species_dict
    for job in job_list:
        if isinstance(job, PressureDependenceJob):
            pdepjob = job
            break
    else:
        raise InputError(
            'the explorer block must occur after the pressureDependence block')

    source = [species_dict[name] for name in source]

    bath_gas = {
        species_dict[spec]: fraction
        for spec, fraction in bathGas.items()
    } if bathGas else None

    job = ExplorerJob(source=source,
                      pdepjob=pdepjob,
                      explore_tol=explore_tol,
                      energy_tol=energy_tol,
                      flux_tol=flux_tol,
                      bath_gas=bath_gas,
                      maximum_radical_electrons=maximumRadicalElectrons)
    job_list.append(job)
Exemple #13
0
def explorer(source,
             explore_tol=(0.01, 's^-1'),
             energy_tol=np.inf,
             flux_tol=0.0,
             bathGas=None,
             maximumRadicalElectrons=np.inf):
    global jobList, speciesDict
    for job in jobList:
        if isinstance(job, PressureDependenceJob):
            pdepjob = job
            break
    else:
        raise InputError(
            'the explorer block must occur after the pressureDependence block')

    source = [speciesDict[name] for name in source]

    explore_tol = Quantity(explore_tol)

    if bathGas:
        bathGas0 = bathGas or {}
        bathGas = {}
        for spec, fraction in bathGas0.items():
            bathGas[speciesDict[spec]] = fraction

    job = ExplorerJob(source=source,
                      pdepjob=pdepjob,
                      explore_tol=explore_tol.value_si,
                      energy_tol=energy_tol,
                      flux_tol=flux_tol,
                      bathGas=bathGas,
                      maximumRadicalElectrons=maximumRadicalElectrons)
    jobList.append(job)
Exemple #14
0
def mlEstimator(thermo=True,
                name='main',
                minHeavyAtoms=1,
                maxHeavyAtoms=None,
                H298UncertaintyCutoff=(3.0, 'kcal/mol'),
                S298UncertaintyCutoff=(2.0, 'cal/(mol*K)'),
                CpUncertaintyCutoff=(2.0, 'cal/(mol*K)')):
    from rmgpy.ml.estimator import MLEstimator

    # Currently only support thermo
    if thermo:
        models_path = os.path.join(settings['database.directory'], 'thermo',
                                   'ml', name)
        if not os.path.exists(models_path):
            raise InputError(
                'Cannot find ML models folder {}'.format(models_path))
        H298_path = os.path.join(models_path, 'H298')
        S298_path = os.path.join(models_path, 'S298')
        Cp_path = os.path.join(models_path, 'Cp')
        rmg.ml_estimator = MLEstimator(H298_path, S298_path, Cp_path)

        uncertainty_cutoffs = dict(H298=Quantity(*H298UncertaintyCutoff),
                                   S298=Quantity(*S298UncertaintyCutoff),
                                   Cp=Quantity(*CpUncertaintyCutoff))
        rmg.ml_settings = dict(
            min_heavy_atoms=minHeavyAtoms,
            max_heavy_atoms=maxHeavyAtoms,
            uncertainty_cutoffs=uncertainty_cutoffs,
        )
Exemple #15
0
    def loadScanEnergies(self):
        """
        Extract the optimized energies in J/mol from a QChem log file, e.g. the
        result of a QChem "PES Scan" quantum chemistry calculation.
        """
        Vlist = []
        angle = []
        read = False
        with open(self.path, 'r') as f:
            for line in f:
                if '-----------------' in line:
                    read = False
                if read:
                    values = [float(item) for item in line.split()]
                    angle.append(values[0])
                    Vlist.append(values[1])
                if 'Summary of potential scan:' in line:
                    logging.info('found a sucessfully completed QChem Job')
                    read = True
                elif 'SCF failed to converge' in line:
                    raise InputError('QChem Job did not sucessfully complete: SCF failed to converge')
        logging.info('   Assuming {0} is the output from a QChem PES scan...'.format(os.path.basename(self.path)))

        Vlist = numpy.array(Vlist, numpy.float64)
        # check to see if the scanlog indicates that one of your reacting species may not be the lowest energy conformer
        check_conformer_energy(Vlist, self.path)
        
        # Adjust energies to be relative to minimum energy conformer
        # Also convert units from Hartree/particle to J/mol
        Vlist -= numpy.min(Vlist)
        Vlist *= constants.E_h * constants.Na
        angle = numpy.arange(0.0, 2*math.pi+0.00001, 2*math.pi/(len(Vlist)-1), numpy.float64)
        return Vlist, angle
Exemple #16
0
    def loadZeroPointEnergy(self,frequencyScaleFactor=1.):
        """
        Load the unscaled zero-point energy in J/mol from a Qchem output file.
        """

        ZPE = None
    
        f = open(self.path, 'r')
        line = f.readline()
        while line != '':
    
            # if 'Final energy is' in line:
            #     E0 = float(line.split()[3]) * constants.E_h * constants.Na
            #     print 'energy is' + str(E0)
            if 'Zero point vibrational energy' in line:
                # Qchem's ZPE is in kcal/mol
                ZPE = float(line.split()[4]) * 4184
                # scaledZPE = ZPE * frequencyScaleFactor
                logging.debug('ZPE is {}'.format(str(ZPE)))
            # Read the next line in the file
            line = f.readline()
    
        # Close file when finished
        f.close()
        
        if ZPE is not None:
            return ZPE
        else:
            raise InputError('Unable to find zero-point energy in Qchem output file.')
Exemple #17
0
    def loadEnergy(self, frequencyScaleFactor=1.):
        """
        Load the energy in J/mol from a Qchem log file. Only the last energy
        in the file is returned. The zero-point energy is *not* included in
        the returned value.
        """
        E0 = None
    
        f = open(self.path, 'r')
        line = f.readline()
        while line != '':
    
            if 'Final energy is' in line:
                E0 = float(line.split()[3]) * constants.E_h * constants.Na
                logging.debug('energy is {}'.format(str(E0)))
            
#            elif 'Zero point vibrational energy' in line:
                #Qchem's ZPE is in kcal/mol
#                ZPE = float(line.split()[4]) * 4184
#                scaledZPE = ZPE * frequencyScaleFactor
#                print 'ZPE is ' + str(ZPE)
            # Read the next line in the file
            line = f.readline()
    
        # Close file when finished
        f.close()

        if E0 is not None:
            return E0
        else:
            raise InputError('Unable to find energy in Qchem output file.')
Exemple #18
0
def determine_qm_software(fullpath):
    """
    Given a path to the log file of a QM software, determine whether it is Gaussian, Molpro, or QChem
    """
    with open(fullpath, 'r') as f:
        line = f.readline()
        software_log = None
        while line != '':
            if 'gaussian' in line.lower():
                f.close()
                software_log = GaussianLog(fullpath)
                break
            elif 'qchem' in line.lower():
                f.close()
                software_log = QChemLog(fullpath)
                break
            elif 'molpro' in line.lower():
                f.close()
                software_log = MolproLog(fullpath)
                break
            line = f.readline()
        else:
            raise InputError(
                'File at {0} could not be identified as a Gaussian, '
                'QChem or Molpro log file.'.format(fullpath))
    return software_log
Exemple #19
0
def determine_qm_software(fullpath):
    """
    Given a path to the log file of a QM software, determine whether it is
    Gaussian, Molpro, QChem, or TeraChem
    """
    with open(fullpath, 'r') as f:
        software_log = None
        if os.path.splitext(fullpath)[1] in ['.xyz', '.dat', '.geometry']:
            software_log = TeraChemLog(fullpath)
        line = f.readline()
        while software_log is None and line != '':
            if 'gaussian' in line.lower():
                software_log = GaussianLog(fullpath)
                break
            elif 'molpro' in line.lower():
                software_log = MolproLog(fullpath)
                break
            elif 'qchem' in line.lower():
                software_log = QChemLog(fullpath)
                break
            elif 'terachem' in line.lower():
                software_log = TeraChemLog(fullpath)
                break
            elif 'orca' in line.lower():
                f.close()
                software_log = OrcaLog(fullpath)
                break
            line = f.readline()
        if software_log is None:
            f.close()
            raise InputError(
                f'The file at {fullpath} could not be identified as a '
                'Gaussian, Molpro, QChem, or TeraChem log file.')
    return software_log
Exemple #20
0
    def __init__(self,
                 source,
                 pdepjob,
                 explore_tol,
                 energy_tol=np.inf,
                 flux_tol=0.0,
                 bathGas=None,
                 maximumRadicalElectrons=np.inf):
        self.source = source
        self.explore_tol = explore_tol
        self.energy_tol = energy_tol
        self.flux_tol = flux_tol
        self.maximumRadicalElectrons = maximumRadicalElectrons

        self.pdepjob = pdepjob

        if not hasattr(self.pdepjob, 'outputFile'):
            self.pdepjob.outputFile = None

        if bathGas:
            self.bathGas = bathGas
        elif self.pdepjob.network and self.pdepjob.network.bathGas:
            self.bathGas = self.pdepjob.network.bathGas
        else:
            raise InputError('bathGas not specified in explorer block')
Exemple #21
0
def get_moment_of_inertia_tensor(coords, numbers=None, symbols=None):
    """
    Calculate and return the moment of inertia tensor for the current
    geometry in amu*angstrom^2. If the coordinates are not at the center of mass,
    they are temporarily shifted there for the purposes of this calculation.
    Adapted from J.W. Allen: https://github.com/jwallen/ChemPy/blob/master/chempy/geometry.py

    Args:
        coords (np.array): Entries are 3-length lists of xyz coordinates for an atom.
        numbers (np.array, list): Entries are atomic numbers corresponding to coords.
        symbols (list): Entries are atom symbols corresponding to coords.

    Returns:
        np.array: The 3x3 moment of inertia tensor.
    Raises:
        InputError: If neither ``symbols`` nor ``numbers`` are given, or if they have a different length than ``coords``
    """
    if symbols is None and numbers is None:
        raise InputError('Either symbols or numbers must be given.')
    if numbers is not None:
        symbols = [symbol_by_number[number] for number in numbers]
    if len(coords) != len(symbols):
        raise InputError(
            f'The number of atoms ({len(symbols)}) is not equal to the number of '
            f'atomic coordinates ({len(list(coords))})')
    tensor = np.zeros((3, 3), np.float64)
    center_of_mass = get_center_of_mass(coords=coords,
                                        numbers=numbers,
                                        symbols=symbols)
    for symbol, coord in zip(symbols, coords):
        mass = get_element_mass(symbol)[0]
        cm_coord = coord - center_of_mass
        tensor[0, 0] += mass * (cm_coord[1] * cm_coord[1] +
                                cm_coord[2] * cm_coord[2])
        tensor[1, 1] += mass * (cm_coord[0] * cm_coord[0] +
                                cm_coord[2] * cm_coord[2])
        tensor[2, 2] += mass * (cm_coord[0] * cm_coord[0] +
                                cm_coord[1] * cm_coord[1])
        tensor[0, 1] -= mass * cm_coord[0] * cm_coord[1]
        tensor[0, 2] -= mass * cm_coord[0] * cm_coord[2]
        tensor[1, 2] -= mass * cm_coord[1] * cm_coord[2]
    tensor[1, 0] = tensor[0, 1]
    tensor[2, 0] = tensor[0, 2]
    tensor[2, 1] = tensor[1, 2]
    return tensor
Exemple #22
0
def liquidReactor(temperature,
                  initialConcentrations,
                  terminationConversion=None,
                  terminationTime=None,
                  sensitivity=None,
                  sensitivityThreshold=1e-3,
                  constantSpecies=None):

    logging.debug('Found LiquidReactor reaction system')
    T = Quantity(temperature)
    for spec, conc in initialConcentrations.iteritems():
        concentration = Quantity(conc)
        # check the dimensions are ok
        # convert to mol/m^3 (or something numerically nice? or must it be SI)
        initialConcentrations[spec] = concentration.value_si
    termination = []
    if terminationConversion is not None:
        for spec, conv in terminationConversion.iteritems():
            termination.append(TerminationConversion(speciesDict[spec], conv))
    if terminationTime is not None:
        termination.append(TerminationTime(Quantity(terminationTime)))
    if len(termination) == 0:
        raise InputError(
            'No termination conditions specified for reaction system #{0}.'.
            format(len(rmg.reactionSystems) + 2))

    sensitiveSpecies = []
    if sensitivity:
        for spec in sensitivity:
            sensitiveSpecies.append(speciesDict[spec])

    ##chatelak: check the constant species exist
    if constantSpecies is not None:
        logging.debug('  Generation with constant species:')
        for constantSpecie in constantSpecies:
            logging.debug("  {0}".format(constantSpecie))
            if not speciesDict.has_key(constantSpecie):
                raise InputError(
                    'Species {0} not found in the input file'.format(
                        constantSpecie))

    system = LiquidReactor(T, initialConcentrations, termination,
                           sensitiveSpecies, sensitivityThreshold,
                           constantSpecies)
    rmg.reactionSystems.append(system)
Exemple #23
0
    def loadGeometry(self):
        """
        Return the optimum geometry of the molecular configuration from the
        Molpro .out file. If multiple such geometries are identified, only the
        last is returned.
        """

        symbol, coord, mass, number = [], [], [], []

        f = open(self.path, 'r')
        line = f.readline()
        while line != '':
            # Automatically determine the number of atoms
            if 'Current geometry' in line:
                symbol, coord = [], []
                while 'ENERGY' not in line:
                    line = f.readline()
                line = f.readline()
                while line != '\n':
                    data = line.split()
                    symbol.append(str(data[0]))
                    coord.append([float(data[1]), float(data[2]), float(data[3])])
                    line = f.readline()
                line = f.readline()
            line = f.readline()
        # Close file when finished
        f.close()

        # If no optimized coordinates were found, uses the input geometry
        # (for example if reading the geometry from a frequency file)
        if not coord:
            f = open(self.path, 'r')
            line = f.readline()
            while line != '':
                if 'atomic coordinates' in line.lower():
                    symbol, coord = [], []
                    for i in range(4):
                        line = f.readline()
                    while line != '\n':
                        data = line.split()
                        symbol.append(str(data[1]))
                        coord.append([float(data[3]), float(data[4]), float(data[5])])
                        line = f.readline()
                line = f.readline()

        # Assign appropriate mass to each atom in the molecule
        for atom1 in symbol:
            mass1, num1 = get_element_mass(atom1)
            mass.append(mass1)
            number.append(num1)
        number = numpy.array(number, numpy.int)
        mass = numpy.array(mass, numpy.float64)
        coord = numpy.array(coord, numpy.float64)
        if len(number) == 0 or len(coord) == 0 or len(mass) == 0:
            raise InputError('Unable to read atoms from Molpro geometry output file {0}'.format(self.path))

        return coord, number, mass
Exemple #24
0
def pressureDependence(
    method,
    temperatures,
    pressures,
    maximumGrainSize=0.0,
    minimumNumberOfGrains=0,
    interpolation=None,
    maximumAtoms=None,
):

    from rmgpy.cantherm.pdep import PressureDependenceJob

    # Setting the pressureDependence attribute to non-None enables pressure dependence
    rmg.pressureDependence = PressureDependenceJob(network=None)

    # Process method
    rmg.pressureDependence.method = method

    # Process interpolation model
    if isinstance(interpolation, str):
        interpolation = (interpolation, )
    if interpolation[0].lower() not in ("chebyshev", "pdeparrhenius"):
        raise InputError(
            "Interpolation model must be set to either 'Chebyshev' or 'PDepArrhenius'."
        )
    rmg.pressureDependence.interpolationModel = interpolation

    # Process temperatures
    Tmin, Tmax, Tunits, Tcount = temperatures
    rmg.pressureDependence.Tmin = Quantity(Tmin, Tunits)
    rmg.pressureDependence.Tmax = Quantity(Tmax, Tunits)
    rmg.pressureDependence.Tcount = Tcount
    rmg.pressureDependence.generateTemperatureList()

    # Process pressures
    Pmin, Pmax, Punits, Pcount = pressures
    rmg.pressureDependence.Pmin = Quantity(Pmin, Punits)
    rmg.pressureDependence.Pmax = Quantity(Pmax, Punits)
    rmg.pressureDependence.Pcount = Pcount
    rmg.pressureDependence.generatePressureList()

    # Process grain size and count
    rmg.pressureDependence.maximumGrainSize = Quantity(maximumGrainSize)
    rmg.pressureDependence.minimumGrainCount = minimumNumberOfGrains

    # Process maximum atoms
    rmg.pressureDependence.maximumAtoms = maximumAtoms

    rmg.pressureDependence.activeJRotor = True
    rmg.pressureDependence.activeKRotor = True
    rmg.pressureDependence.rmgmode = True
Exemple #25
0
 def loadZeroPointEnergy(self,frequencyScaleFactor=1.):
     """
     Load the unscaled zero-point energy in J/mol from a QChem output file.
     """
     ZPE = None
     with open(self.path, 'r') as f:
         for line in f:
             if 'Zero point vibrational energy' in line:
                 ZPE = float(line.split()[4]) * 4184  # QChem's ZPE is in kcal/mol
                 # scaledZPE = ZPE * frequencyScaleFactor
                 logging.debug('ZPE is {}'.format(str(ZPE)))
     if ZPE is not None:
         return ZPE
     else:
         raise InputError('Unable to find zero-point energy in QChem output file.')
Exemple #26
0
def generatedSpeciesConstraints(**kwargs):

    validConstraints = [
        'allowed', 'maximumCarbonAtoms', 'maximumOxygenAtoms',
        'maximumNitrogenAtoms', 'maximumSiliconAtoms', 'maximumSulfurAtoms',
        'maximumHeavyAtoms', 'maximumRadicalElectrons',
        'maximumSingletCarbenes', 'maximumCarbeneRadicals', 'allowSingletO2',
        'maximumIsotopicAtoms'
    ]

    for key, value in kwargs.items():
        if key not in validConstraints:
            raise InputError(
                'Invalid generated species constraint {0!r}.'.format(key))

        rmg.speciesConstraints[key] = value
Exemple #27
0
 def loadNegativeFrequency(self):
     """
     Return the imaginary frequency from a transition state frequency
     calculation in cm^-1.
     """
     frequency = 0
     with open(self.path, 'r') as f:
         for line in f:
             # Read imaginary frequency
             if ' Frequency:' in line:
                 frequency = float((line.split()[1]))
                 break
     # Make sure the frequency is imaginary:
     if frequency < 0:
         return frequency
     else:
         raise InputError('Unable to find imaginary frequency in QChem output file {0}'.format(self.path))
Exemple #28
0
 def loadZeroPointEnergy(self):
     """
     Load the unscaled zero-point energy in J/mol from a QChem output file.
     """
     zpe = None
     with open(self.path, 'r') as f:
         for line in f:
             if 'Zero point vibrational energy' in line:
                 zpe = float(
                     line.split()[4]
                 ) * 4184  # QChem's ZPE is in kcal/mol, convert to J/mol
                 logging.debug('ZPE is {}'.format(str(zpe)))
     if zpe is not None:
         return zpe
     else:
         raise InputError(
             'Unable to find zero-point energy in QChem output file.')
Exemple #29
0
def ess_factory(fullpath: str,
                check_for_errors: bool = True,
                ) -> Type[ESSAdapter]:
    """
    A factory generating the ESS adapter corresponding to ``ess_adapter``.
    Given a path to the log file of a QM software, determine whether it is
    Gaussian, Molpro, QChem, Orca, or TeraChem

    Args:
        fullpath (str): The disk location of the output file of interest.
        check_for_errors (bool): Boolean indicating whether to check the QM log for common errors
                                 before parsing relevant information.

    Returns:
        Type[ESSAdapter]: The requested ESSAdapter child, initialized with the respective arguments.
    """

    ess_name = None
    if os.path.splitext(fullpath)[-1] in ['.xyz', '.dat', '.geometry']:
        ess_name = 'TeraChemLog'
    else:
        with open(fullpath, 'r') as f:
            line = f.readline()
            while ess_name is None and line != '':
                if 'gaussian' in line.lower():
                    ess_name = 'GaussianLog'
                    break
                elif 'molpro' in line.lower():
                    ess_name = 'MolproLog'
                    break
                elif 'O   R   C   A' in line or 'orca' in line.lower():
                    ess_name = 'OrcaLog'
                    break
                elif 'qchem' in line.lower():
                    ess_name = 'QChemLog'
                    break
                elif 'terachem' in line.lower():
                    ess_name = 'TeraChemLog'
                    break
                line = f.readline()
    if ess_name is None:
        raise InputError(f'The file at {fullpath} could not be identified as a '
                         f'Gaussian, Molpro, Orca, QChem, or TeraChem log file.')

    return _registered_ess_adapters[ess_name](path=fullpath, check_for_errors=check_for_errors)
Exemple #30
0
 def loadEnergy(self, frequencyScaleFactor=1.):
     """
     Load the energy in J/mol from a QChem log file. Only the last energy
     in the file is returned. The zero-point energy is *not* included in
     the returned value.
     """
     e0 = None
     with open(self.path, 'r') as f:
         a = b = 0
         for line in f:
             if 'Final energy is' in line:
                 a = float(line.split()[3]) * constants.E_h * constants.Na
             if 'Total energy in the final basis set' in line:
                 b = float(line.split()[8]) * constants.E_h * constants.Na
             e0 = a or b
     if e0 is None:
         raise InputError('Unable to find energy in QChem output file.')
     return e0