Exemplo n.º 1
0
    def test_remove_isotope_for_reactions(self):
        """
        Test that remove isotope algorithm works with Reaction objects.
        """

        eth = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")

        ethi = Species().from_adjacency_list("""
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 i13 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
""")
        unlabeled_rxn = Reaction(reactants=[eth], products=[eth])
        labeled_rxn = Reaction(reactants=[ethi], products=[ethi])
        stripped = remove_isotope(labeled_rxn)

        self.assertTrue(unlabeled_rxn.is_isomorphic(stripped))
Exemplo n.º 2
0
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              kinetics=None,
              reversible=True,
              transitionState=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              library=None,
              entry=None):
     Reaction.__init__(self,
                       index=index,
                       reactants=reactants,
                       products=products,
                       kinetics=kinetics,
                       reversible=reversible,
                       transitionState=transitionState,
                       duplicate=duplicate,
                       degeneracy=degeneracy,
                       pairs=pairs)
     self.library = library
     self.family = library
     self.entry = entry
Exemplo n.º 3
0
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              specificCollider=None,
              kinetics=None,
              network_kinetics=None,
              reversible=True,
              transitionState=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              library=None,
              allow_pdep_route=False,
              elementary_high_p=False,
              entry=None):
     Reaction.__init__(
         self,
         index=index,
         reactants=reactants,
         products=products,
         specificCollider=specificCollider,
         kinetics=kinetics,
         network_kinetics=network_kinetics,
         reversible=reversible,
         transitionState=transitionState,
         duplicate=duplicate,
         degeneracy=degeneracy,
         pairs=pairs,
         allow_pdep_route=allow_pdep_route,
         elementary_high_p=elementary_high_p,
     )
     self.library = library
     self.family = library
     self.entry = entry
Exemplo n.º 4
0
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              specific_collider=None,
              kinetics=None,
              reversible=True,
              transition_state=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              depository=None,
              family=None,
              entry=None):
     Reaction.__init__(self,
                       index=index,
                       reactants=reactants,
                       products=products,
                       specific_collider=specific_collider,
                       kinetics=kinetics,
                       reversible=reversible,
                       transition_state=transition_state,
                       duplicate=duplicate,
                       degeneracy=degeneracy,
                       pairs=pairs)
     self.depository = depository
     self.family = family
     self.entry = entry
Exemplo n.º 5
0
 def fitInterpolationModels(self):
         
     configurations = []
     configurations.extend(self.network.isomers)
     configurations.extend(self.network.reactants)
     configurations.extend(self.network.products)
     
     self.network.netReactions = []
     
     Nreac = self.network.Nisom + self.network.Nreac
     Nprod = Nreac + self.network.Nprod
     
     Tmin = self.Tmin.value_si
     Tmax = self.Tmax.value_si
     Tdata = self.Tlist.value_si
     Pmin = self.Pmin.value_si
     Pmax = self.Pmax.value_si
     Pdata = self.Plist.value_si
     
     for prod in range(Nprod):
         for reac in range(Nreac):
             if reac == prod: continue
             reaction = Reaction(
                 reactants = configurations[reac].species,
                 products = configurations[prod].species,
             )
             
             kdata = self.K[:,:,prod,reac].copy()
             order = len(reaction.reactants)
             kdata *= 1e6 ** (order-1)
             kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order]
             
             reaction.kinetics = self.fitInterpolationModel(Tdata, Pdata, kdata, kunits)
             
             self.network.netReactions.append(reaction)
Exemplo n.º 6
0
    def fit_interpolation_models(self):
        """Fit all pressure dependent rates with interpolation models"""
        configurations = []
        configurations.extend(self.network.isomers)
        configurations.extend(self.network.reactants)
        configurations.extend(self.network.products)

        self.network.net_reactions = []

        n_reac = self.network.n_isom + self.network.n_reac
        n_prod = n_reac + self.network.n_prod

        Tdata, Pdata = self.Tlist.value_si, self.Plist.value_si

        for prod in range(n_prod):
            for reac in range(n_reac):
                if reac == prod:
                    continue
                reaction = Reaction(reactants=configurations[reac].species,
                                    products=configurations[prod].species)

                kdata = self.K[:, :, prod, reac].copy()
                order = len(reaction.reactants)
                kdata *= 1e6 ** (order - 1)
                k_units = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order]
                logging.debug('Fitting master eqn data to kinetics for reaction {}.'.format(reaction))
                reaction.kinetics = self.fit_interpolation_model(Tdata, Pdata, kdata, k_units)

                self.network.net_reactions.append(reaction)
Exemplo n.º 7
0
def reaction(index,
             label,
             reactant1,
             product1,
             forwardDegeneracy,
             reverseDegeneracy,
             reactant2=None,
             product2=None):
    global forwardReaction, reverseReaction, reactionIndex, reactionLabel

    reactants = []
    reactants.append(Species().fromAdjacencyList(reactant1))
    if reactant2: reactants.append(Species().fromAdjacencyList(reactant2))
    for reactant in reactants:
        if reactant.label == '':
            reactant.label = reactant.molecule[0].toSMILES()

    products = []
    products.append(Species().fromAdjacencyList(product1))
    if product2: products.append(Species().fromAdjacencyList(product2))
    for product in products:
        if product.label == '':
            product.label = product.molecule[0].toSMILES()

    reactionIndex = index
    reactionLabel = label
    forwardReaction = Reaction(reactants=reactants,
                               products=products,
                               degeneracy=forwardDegeneracy)
    reverseReaction = Reaction(reactants=products,
                               products=reactants,
                               degeneracy=reverseDegeneracy)
Exemplo n.º 8
0
    def loadEntry(self,
                  index,
                  reactant1,
                  product1,
                  kinetics,
                  reactant2=None,
                  reactant3=None,
                  product2=None,
                  product3=None,
                  degeneracy=1,
                  label='',
                  duplicate=False,
                  reversible=True,
                  reference=None,
                  referenceType='',
                  shortDesc='',
                  longDesc='',
                  history=None
                  ):
        
        reactants = [Species(label=reactant1.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(reactant1)])]
        if reactant2 is not None: reactants.append(Species(label=reactant2.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(reactant2)]))
        if reactant3 is not None: reactants.append(Species(label=reactant3.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(reactant3)]))

        products = [Species(label=product1.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(product1)])]
        if product2 is not None: products.append(Species(label=product2.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(product2)]))
        if product3 is not None: products.append(Species(label=product3.strip().splitlines()[0].strip(), molecule=[Molecule().fromAdjacencyList(product3)]))
        
        comment = "Reaction and kinetics from {0}.".format(self.label)
        if shortDesc.strip(): 
            comment += "{0!s}\n".format(shortDesc.strip())
        if longDesc.strip():
            comment += str(re.sub('\s*\n\s*','\n',longDesc))
        kinetics.comment = comment.strip()
        
        # Perform mass balance check on the reaction
        rxn = Reaction(reactants=reactants, products=products, degeneracy=degeneracy, duplicate=duplicate, reversible=reversible)
        if not rxn.isBalanced():
            raise DatabaseError('Reaction {0} in kinetics library {1} was not balanced! Please reformulate.'.format(rxn, self.label))        

        assert index not in self.entries, "Reaction with index {0} already present!".format(index)
        self.entries[index] = Entry(
            index = index,
            label = label,
            item = rxn,
            data = kinetics,
            reference = reference,
            referenceType = referenceType,
            shortDesc = shortDesc,
            longDesc = longDesc.strip(),
            history = history or [],
        )
        
        # Convert SMILES to Molecule objects in collision efficiencies
        if isinstance(kinetics, PDepKineticsModel):
            efficiencies = {}
            for smiles, eff in kinetics.efficiencies.items():
                if isinstance(smiles, str):
                    efficiencies[Molecule().fromSMILES(smiles)] = eff
            kinetics.efficiencies = efficiencies
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              specificCollider=None,
              kinetics=None,
              reversible=True,
              transitionState=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              depository=None,
              family=None,
              entry=None
              ):
     Reaction.__init__(self,
                       index=index,
                       reactants=reactants,
                       products=products,
                       specificCollider=specificCollider,
                       kinetics=kinetics,
                       reversible=reversible,
                       transitionState=transitionState,
                       duplicate=duplicate,
                       degeneracy=degeneracy,
                       pairs=pairs
                       )
     self.depository = depository
     self.family = family
     self.entry = entry
Exemplo n.º 10
0
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              kinetics=None,
              reversible=True,
              transitionState=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              library=None,
              entry=None
              ):
     Reaction.__init__(self,
                       index=index,
                       reactants=reactants,
                       products=products,
                       kinetics=kinetics,
                       reversible=reversible,
                       transitionState=transitionState,
                       duplicate=duplicate,
                       degeneracy=degeneracy,
                       pairs=pairs
                       )
     self.library = library
     self.family = library
     self.entry = entry
Exemplo n.º 11
0
 def fitInterpolationModels(self):
         
     configurations = []
     configurations.extend(self.network.isomers)
     configurations.extend(self.network.reactants)
     configurations.extend(self.network.products)
     
     self.network.netReactions = []
     
     Nreac = self.network.Nisom + self.network.Nreac
     Nprod = Nreac + self.network.Nprod
     
     Tmin = self.Tmin.value_si
     Tmax = self.Tmax.value_si
     Tdata = self.Tlist.value_si
     Pmin = self.Pmin.value_si
     Pmax = self.Pmax.value_si
     Pdata = self.Plist.value_si
     
     for prod in range(Nprod):
         for reac in range(Nreac):
             if reac == prod: continue
             reaction = Reaction(
                 reactants = configurations[reac].species,
                 products = configurations[prod].species,
             )
             
             kdata = self.K[:,:,prod,reac].copy()
             order = len(reaction.reactants)
             kdata *= 1e6 ** (order-1)
             kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order]
             
             reaction.kinetics = self.fitInterpolationModel(Tdata, Pdata, kdata, kunits)
             
             self.network.netReactions.append(reaction)
    def testRemoveIsotopeForReactions(self):
        """
        Test that remove isotope algorithm works with Reaction objects.
        """

        eth = Species().fromAdjacencyList(
        """
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
        """
    )

        ethi = Species().fromAdjacencyList(
        """
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 i13 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
        """
    )
        unlabeledRxn = Reaction(reactants=[eth], products = [eth])
        labeledRxn = Reaction(reactants=[ethi], products = [ethi])
        stripped = remove_isotope(labeledRxn)

        self.assertTrue(unlabeledRxn.isIsomorphic(stripped))
Exemplo n.º 13
0
    def test_compute_derivative(self):

        rxnList = []
        rxnList.append(Reaction(reactants=[self.C2H6], products=[self.CH3,self.CH3], kinetics=Arrhenius(A=(686.375e6,'1/s'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K')))) 
        rxnList.append(Reaction(reactants=[self.C2H6,self.CH3], products=[self.C2H5,self.CH4], kinetics=Arrhenius(A=(46.375*6,'m^3/(mol*s)'), n=3.40721, Ea=(6.82799,'kcal/mol'), T0=(298.15,'K'))))        
        rxnList.append(Reaction(reactants=[self.C2H6,self.CH3,self.CH3], products=[self.C2H5,self.C2H5,self.H2], kinetics=Arrhenius(A=(146.375*6,'m^6/(mol^2*s)'), n=2.40721, Ea=(8.82799,'kcal/mol'), T0=(298.15,'K'))))
        
        
        coreSpecies = [self.CH4,self.CH3,self.C2H6,self.C2H5, self.H2]
        edgeSpecies = []
        coreReactions = rxnList
        edgeReactions = []
        numCoreSpecies = len(coreSpecies)
        
        c0={self.CH4:0.2,self.CH3:0.1,self.C2H6:0.35,self.C2H5:0.15, self.H2:0.2}

        rxnSystem0 = LiquidReactor(self.T, c0,termination=[])
        rxnSystem0.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions)
        dfdt0 = rxnSystem0.residual(0.0, rxnSystem0.y, numpy.zeros(rxnSystem0.y.shape))[0]
        solver_dfdk = rxnSystem0.computeRateDerivative()
        #print 'Solver d(dy/dt)/dk'
        #print solver_dfdk
        
        integrationTime = 1e-8
        
        modelSettings = ModelSettings(toleranceKeepInEdge = 0,toleranceMoveToCore=1,toleranceInterruptSimulation=0)
        simulatorSettings = SimulatorSettings()
        
        rxnSystem0.termination.append(TerminationTime((integrationTime,'s')))
        
        rxnSystem0.simulate(coreSpecies, coreReactions, [], [], [],[], modelSettings=modelSettings,simulatorSettings=simulatorSettings)

        y0 = rxnSystem0.y
        
        dfdk = numpy.zeros((numCoreSpecies,len(rxnList)))   # d(dy/dt)/dk
        
        c0={self.CH4:0.2,self.CH3:0.1,self.C2H6:0.35,self.C2H5:0.15, self.H2:0.2}

        for i in xrange(len(rxnList)):
            k0 = rxnList[i].getRateCoefficient(self.T)
            rxnList[i].kinetics.A.value_si = rxnList[i].kinetics.A.value_si*(1+1e-3)               
            dk = rxnList[i].getRateCoefficient(self.T) - k0

            rxnSystem = LiquidReactor(self.T, c0,termination=[])
            rxnSystem.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions)

            dfdt = rxnSystem.residual(0.0, rxnSystem.y, numpy.zeros(rxnSystem.y.shape))[0]  
            dfdk[:,i]=(dfdt-dfdt0)/dk          
            
            
            rxnSystem.termination.append(TerminationTime((integrationTime,'s')))
            modelSettings = ModelSettings(toleranceKeepInEdge = 0,toleranceMoveToCore=1,toleranceInterruptSimulation=0)
            simulatorSettings = SimulatorSettings()
            rxnSystem.simulate(coreSpecies, coreReactions,[],[],[],[], modelSettings=modelSettings,simulatorSettings=simulatorSettings)
            
            rxnList[i].kinetics.A.value_si = rxnList[i].kinetics.A.value_si/(1+1e-3)  # reset A factor
            
        for i in xrange(numCoreSpecies):
            for j in xrange(len(rxnList)):
                self.assertAlmostEqual(dfdk[i,j], solver_dfdk[i,j], delta=abs(1e-3*dfdk[i,j]))
Exemplo n.º 14
0
 def setUpClass(cls):
     """
     A method that is run before all unit tests in this class.
     """
     cls.maxDiff = None
     cls.rmgdb = rmgdb.make_rmg_database_object()
     rmgdb.load_families_only(cls.rmgdb)
     cls.rxn1 = ARCReaction(reactants=['CH4', 'OH'],
                            products=['CH3', 'H2O'])
     cls.rxn1.rmg_reaction = Reaction(reactants=[
         Species().fromSMILES(str('C')),
         Species().fromSMILES(str('[OH]'))
     ],
                                      products=[
                                          Species().fromSMILES(
                                              str('[CH3]')),
                                          Species().fromSMILES(str('O'))
                                      ])
     cls.rxn2 = ARCReaction(reactants=['C2H5', 'OH'],
                            products=['C2H4', 'H2O'])
     cls.rxn2.rmg_reaction = Reaction(reactants=[
         Species().fromSMILES(str('C[CH2]')),
         Species().fromSMILES(str('[OH]'))
     ],
                                      products=[
                                          Species().fromSMILES(str('C=C')),
                                          Species().fromSMILES(str('O'))
                                      ])
     cls.rxn3 = ARCReaction(reactants=['CH3CH2NH'], products=['CH2CH2NH2'])
     cls.rxn3.rmg_reaction = Reaction(
         reactants=[Species().fromSMILES(str('CC[NH]'))],
         products=[Species().fromSMILES(str('[CH2]CN'))])
Exemplo n.º 15
0
def determine_rmg_kinetics(
    rmgdb: RMGDatabase,
    reaction: Reaction,
    dh_rxn298: float,
) -> List[Reaction]:
    """
    Determine kinetics for `reaction` (an RMG Reaction object) from RMG's database, if possible.
    Assigns a list of all matching entries from both libraries and families.

    Args:
        rmgdb (RMGDatabase): The RMG database instance.
        reaction (Reaction): The RMG Reaction object.
        dh_rxn298 (float): The heat of reaction at 298 K in J/mol.

    Returns: List[Reaction]
        All matching RMG reactions (both libraries and families) with a populated ``.kinetics`` attribute.
    """
    reaction = reaction.copy(
    )  # use a copy to avoid changing atom order in the molecules by RMG
    rmg_reactions = list()
    # Libraries:
    for library in rmgdb.kinetics.libraries.values():
        library_reactions = library.get_library_reactions()
        for library_reaction in library_reactions:
            if reaction.is_isomorphic(library_reaction):
                library_reaction.comment = f'Library: {library.label}'
                rmg_reactions.append(library_reaction)
                break
    # Families:
    fam_list = loop_families(rmgdb, reaction)
    for family, degenerate_reactions in fam_list:
        for deg_rxn in degenerate_reactions:
            template = family.retrieve_template(deg_rxn.template)
            kinetics = family.estimate_kinetics_using_rate_rules(template)[0]
            kinetics.change_rate(deg_rxn.degeneracy)
            kinetics = kinetics.to_arrhenius(
                dh_rxn298
            )  # Convert ArrheniusEP to Arrhenius using the dHrxn at 298K
            deg_rxn.kinetics = kinetics
            deg_rxn.comment = f'Family: {deg_rxn.family}'
            deg_rxn.reactants = reaction.reactants
            deg_rxn.products = reaction.products
        rmg_reactions.extend(degenerate_reactions)
    worked_through_nist_fams = []
    # NIST:
    for family, degenerate_reactions in fam_list:
        if family not in worked_through_nist_fams:
            worked_through_nist_fams.append(family)
            for depo in family.depositories:
                if 'NIST' in depo.label:
                    for entry in depo.entries.values():
                        rxn = entry.item
                        rxn.kinetics = entry.data
                        rxn.comment = f'NIST: {entry.index}'
                        if entry.reference is not None:
                            rxn.comment += f'{entry.reference.authors[0]} {entry.reference.year}'
                        rmg_reactions.append(rxn)
    return rmg_reactions
Exemplo n.º 16
0
def reaction(label, reactants, products, transitionState=None, kinetics=None, tunneling=''):
    """Load a reaction from an input file"""
    global reaction_dict, species_dict, transition_state_dict
    if label in reaction_dict:
        label = label + transitionState
        if label in reaction_dict:
            raise ValueError('Multiple occurrences of reaction with label {0!r}.'.format(label))
    logging.info('Loading reaction {0}...'.format(label))
    reactants = sorted([species_dict[spec] for spec in reactants])
    products = sorted([species_dict[spec] for spec in products])
    if transitionState:
        transitionState = transition_state_dict[transitionState]
    if transitionState and (tunneling == '' or tunneling is None):
        transitionState.tunneling = None
    elif tunneling.lower() == 'wigner':
        transitionState.tunneling = Wigner(frequency=None)
    elif tunneling.lower() == 'eckart':
        transitionState.tunneling = Eckart(frequency=None, E0_reac=None, E0_TS=None, E0_prod=None)

    elif transitionState and not isinstance(tunneling, TunnelingModel):
        raise ValueError('Unknown tunneling model {0!r}.'.format(tunneling))
    rxn = Reaction(label=label, reactants=reactants, products=products, transition_state=transitionState,
                   kinetics=kinetics)

    if rxn.transition_state is None and rxn.kinetics is None:
        logging.info('estimating rate of reaction {0} using RMG-database')
        if not all([m.molecule != [] for m in rxn.reactants + rxn.products]):
            raise ValueError('chemical structures of reactants and products not available for RMG estimation of '
                             'reaction {0}'.format(label))
        db = get_db('kinetics')
        rxns = db.generate_reactions_from_libraries(reactants=rxn.reactants, products=rxn.products)
        rxns = [r for r in rxns if r.elementary_high_p]

        if rxns:
            for r in rxns:
                if isinstance(rxn.kinetics, PDepKineticsModel):
                    boo = rxn.generate_high_p_limit_kinetics()
                if boo:
                    rxn = r
                    break

        if rxns == [] or not boo:
            logging.info('No library reactions tagged with elementary_high_p found for reaction {0}, generating '
                         'reactions from RMG families'.format(label))
            rxn = list(db.generate_reactions_from_families(reactants=rxn.reactants, products=rxn.products))
            model = CoreEdgeReactionModel()
            model.verbose_comments = True
            for r in rxn:
                model.apply_kinetics_to_reaction(r)

    if isinstance(rxn, Reaction):
        reaction_dict[label] = rxn
    else:
        for i in range(len(rxn)):
            reaction_dict[label + str(i)] = rxn[i]

    return rxn
Exemplo n.º 17
0
    def compute(self):
        """
        Compute the pressure-dependent rate coefficients :math:`k(T,P)` for
        the loaded MEASURE calculation.
        """
        
        # Only proceed if the input network is valid
        if self.network is None or self.network.errorString != '':
            raise PDepError('Attempted to run MEASURE calculation with invalid input.')
    
        Nisom = len(self.network.isomers)
        Nreac = len(self.network.reactants)
        Nprod = len(self.network.products)

        network = self.network   
        Tmin = self.Tmin.value_si
        Tmax = self.Tmax.value_si
        Tlist = self.Tlist.value_si
        Pmin = self.Pmin.value_si
        Pmax = self.Pmax.value_si
        Plist = self.Plist.value_si
        method = self.method
        model = self.model
        
        # Calculate the rate coefficients
        K = network.calculateRateCoefficients(Tlist, Plist, method, grainCount=self.grainCount, grainSize=self.grainSize.value_si)

        # Fit interpolation model
        from rmgpy.reaction import Reaction
        from rmgpy.measure.reaction import fitInterpolationModel
        if model[0] != '':
            logging.info('Fitting {0} interpolation models...'.format(model[0]))
        configurations = []
        configurations.extend([[isom] for isom in network.isomers])
        configurations.extend([reactants for reactants in network.reactants])
        configurations.extend([products for products in network.products])
        for i in range(Nisom+Nreac+Nprod):
            for j in range(Nisom+Nreac):
                if i != j:
                    # Check that we have nonzero k(T,P) values
                    if (numpy.any(K[:,:,i,j]) and not numpy.all(K[:,:,i,j])):
                        raise NetworkError('Zero rate coefficient encountered while updating network {0}.'.format(network))

                    # Make a new net reaction
                    netReaction = Reaction(
                        reactants=configurations[j],
                        products=configurations[i],
                        kinetics=None,
                        reversible=(i<Nisom+Nreac),
                    )
                    network.netReactions.append(netReaction)
                    
                    # Set/update the net reaction kinetics using interpolation model
                    netReaction.kinetics = fitInterpolationModel(netReaction, Tlist, Plist,
                        K[:,:,i,j],
                        model, Tmin, Tmax, Pmin, Pmax, errorCheck=True)
        logging.info('')
Exemplo n.º 18
0
    def compute(self):
        """
        Compute the pressure-dependent rate coefficients :math:`k(T,P)` for
        the loaded MEASURE calculation.
        """
        
        # Only proceed if the input network is valid
        if self.network is None or self.network.errorString != '':
            raise PDepError('Attempted to run MEASURE calculation with invalid input.')
    
        Nisom = len(self.network.isomers)
        Nreac = len(self.network.reactants)
        Nprod = len(self.network.products)

        network = self.network   
        Tmin = self.Tmin.value
        Tmax = self.Tmax.value
        Tlist = self.Tlist.values
        Pmin = self.Pmin.value
        Pmax = self.Pmax.value
        Plist = self.Plist.values
        method = self.method
        model = self.model
        
        # Calculate the rate coefficients
        K = network.calculateRateCoefficients(Tlist, Plist, method, grainCount=self.grainCount, grainSize=self.grainSize.value)

        # Fit interpolation model
        from rmgpy.reaction import Reaction
        from rmgpy.measure.reaction import fitInterpolationModel
        if model[0] != '':
            logging.info('Fitting {0} interpolation models...'.format(model[0]))
        configurations = []
        configurations.extend([[isom] for isom in network.isomers])
        configurations.extend([reactants for reactants in network.reactants])
        configurations.extend([products for products in network.products])
        for i in range(Nisom+Nreac+Nprod):
            for j in range(Nisom+Nreac):
                if i != j:
                    # Check that we have nonzero k(T,P) values
                    if (numpy.any(K[:,:,i,j]) and not numpy.all(K[:,:,i,j])):
                        raise NetworkError('Zero rate coefficient encountered while updating network {0}.'.format(network))

                    # Make a new net reaction
                    netReaction = Reaction(
                        reactants=configurations[j],
                        products=configurations[i],
                        kinetics=None,
                        reversible=(i<Nisom+Nreac),
                    )
                    network.netReactions.append(netReaction)
                    
                    # Set/update the net reaction kinetics using interpolation model
                    netReaction.kinetics = fitInterpolationModel(netReaction, Tlist, Plist,
                        K[:,:,i,j],
                        model, Tmin, Tmax, Pmin, Pmax, errorCheck=True)
        logging.info('')
Exemplo n.º 19
0
def loadReaction(label, reactants, products, transitionState, degeneracy=1):
    global speciesDict, transitionStateDict, reactionDict
    logging.info('Loading reaction %s...' % label)
    rxn = Reaction(
        reactants=[speciesDict[s] for s in reactants],
        products=[speciesDict[s] for s in products],
        transitionState=transitionStateDict[transitionState],
    )
    rxn.degeneracy = degeneracy
    reactionDict[label] = rxn
Exemplo n.º 20
0
def reaction(label, reactants, products, transitionState=None, kinetics=None, tunneling=''):
    global reactionDict, speciesDict, transitionStateDict
    if label in reactionDict:
        label = label + transitionState
        if label in reactionDict:
            raise ValueError('Multiple occurrences of reaction with label {0!r}.'.format(label))
    logging.info('Loading reaction {0}...'.format(label))
    reactants = sorted([speciesDict[spec] for spec in reactants])
    products = sorted([speciesDict[spec] for spec in products])
    if transitionState:
        transitionState = transitionStateDict[transitionState]
    if tunneling.lower() == 'wigner':
        transitionState.tunneling = Wigner(frequency=None)
    elif tunneling.lower() == 'eckart':
        transitionState.tunneling = Eckart(frequency=None, E0_reac=None, E0_TS=None, E0_prod=None)
    elif transitionState and (tunneling == '' or tunneling is None):
        transitionState.tunneling = None
    elif transitionState and not isinstance(tunneling, TunnelingModel):
        raise ValueError('Unknown tunneling model {0!r}.'.format(tunneling))
    rxn = Reaction(label=label, reactants=reactants, products=products, transitionState=transitionState, kinetics=kinetics)
    
    if rxn.transitionState is None and rxn.kinetics is None:
        logging.info('estimating rate of reaction {0} using RMG-database')
        if not all([m.molecule != [] for m in rxn.reactants+rxn.products]):
            raise ValueError('chemical structures of reactants and products not available for RMG estimation of reaction {0}'.format(label))
        for spc in rxn.reactants+rxn.products:
            print spc.label
            print spc.molecule
        db = getDB('kinetics')
        rxns = db.generate_reactions_from_libraries(reactants=rxn.reactants,products=rxn.products)
        rxns = [r for r in rxns if r.elementary_high_p]
        
        if rxns != []:
            for r in rxns:
                if isinstance(rxn.kinetics, PDepKineticsModel):
                    boo = rxn.generate_high_p_limit_kinetics()
                if boo:
                    rxn = r
                    break
                
        if rxns == [] or not boo:
            logging.info('No library reactions tagged with elementary_high_p found for reaction {0}, generating reactions from RMG families'.format(label))
            rxn = list(db.generate_reactions_from_families(reactants=rxn.reactants,products=rxn.products))
            model = CoreEdgeReactionModel()
            model.verboseComments = True
            for r in rxn:
                model.applyKineticsToReaction(r)
    
    if isinstance(rxn,Reaction):
        reactionDict[label] = rxn
    else:
        for i in xrange(len(rxn)):
            reactionDict[label+str(i)] = rxn[i]
    
    return rxn
Exemplo n.º 21
0
    def test_rmg_reaction(self):
        test_reaction = RMGReaction(
            reactants=[RMGMolecule(smiles="CC"),
                       RMGMolecule(smiles="[O]O")],
            products=[RMGMolecule(smiles="[CH2]C"),
                      RMGMolecule(smiles="OO")])

        self.assertTrue(
            test_reaction.is_isomorphic(self.reaction.get_rmg_reaction()))
        self.assertTrue(
            test_reaction.is_isomorphic(self.reaction2.get_rmg_reaction()))
Exemplo n.º 22
0
    def getKinetics(self):
        """
        Extracts the kinetic data from the chemkin file for plotting purposes.
        """
        from rmgpy.chemkin import loadChemkinFile
        from rmgpy.kinetics import ArrheniusEP, Chebyshev
        from rmgpy.reaction import Reaction
        from rmgpy.data.base import Entry

        kineticsDataList = []
        chemkinPath = self.path + "/chemkin/chem.inp"
        dictionaryPath = self.path + "RMG_Dictionary.txt"
        speciesList, reactionList = loadChemkinFile(chemkinPath, dictionaryPath)

        for reaction in reactionList:
            # If the kinetics are ArrheniusEP, replace them with Arrhenius
            if isinstance(reaction.kinetics, ArrheniusEP):
                reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298))

            reactants = " + ".join([moleculeToInfo(reactant) for reactant in reaction.reactants])
            arrow = "&hArr;" if reaction.reversible else "&rarr;"
            products = " + ".join([moleculeToInfo(reactant) for reactant in reaction.products])

            source = str(reaction).replace("<=>", "=")
            href = reaction.getURL()
            entry = Entry()
            entry.result = reactionList.index(reaction) + 1
            forwardKinetics = reaction.kinetics
            forward = True
            chemkin = reaction.toChemkin(speciesList)

            reverseKinetics = reaction.generateReverseRateCoefficient()
            reverseKinetics.comment = "Fitted reverse reaction. " + reaction.kinetics.comment

            rev_reaction = Reaction(reactants=reaction.products, products=reaction.reactants, kinetics=reverseKinetics)
            chemkin_rev = rev_reaction.toChemkin(speciesList)

            kineticsDataList.append(
                [
                    reactants,
                    arrow,
                    products,
                    entry,
                    forwardKinetics,
                    source,
                    href,
                    forward,
                    chemkin,
                    reverseKinetics,
                    chemkin_rev,
                ]
            )

        return kineticsDataList
Exemplo n.º 23
0
    def getKinetics(self):
        """
        Extracts the kinetic data from the chemkin file for plotting purposes.
        """
        from rmgpy.chemkin import loadChemkinFile
        from rmgpy.kinetics import ArrheniusEP, Chebyshev
        from rmgpy.reaction import Reaction
        from rmgpy.data.base import Entry
        
        kineticsDataList = []    
        chemkinPath= self.path + '/chemkin/chem.inp'
        dictionaryPath = self.path + 'RMG_Dictionary.txt' 
        if self.Foreign:
            readComments = False
        else:
            readComments = True
        if os.path.exists(dictionaryPath):
            speciesList, reactionList = loadChemkinFile(chemkinPath, dictionaryPath, readComments=readComments)
        else:
            speciesList, reactionList = loadChemkinFile(chemkinPath, readComments=readComments)
            
        for reaction in reactionList:            
            # If the kinetics are ArrheniusEP, replace them with Arrhenius
            if isinstance(reaction.kinetics, ArrheniusEP):
                reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298))

            if os.path.exists(dictionaryPath):
                reactants = ' + '.join([moleculeToInfo(reactant) for reactant in reaction.reactants])
                arrow = '&hArr;' if reaction.reversible else '&rarr;'
                products = ' + '.join([moleculeToInfo(product) for product in reaction.products])
                href = reaction.getURL()
            else:
                reactants = ' + '.join([reactant.label for reactant in reaction.reactants])
                arrow = '&hArr;' if reaction.reversible else '&rarr;'
                products = ' + '.join([product.label for product in reaction.products])
                href = ''
                
            source = str(reaction).replace('<=>','=')
            entry = Entry()   
            entry.result = reactionList.index(reaction)+1
            forwardKinetics = reaction.kinetics     
            forward = True
            chemkin = reaction.toChemkin(speciesList)
            
            reverseKinetics = reaction.generateReverseRateCoefficient()
            reverseKinetics.comment = 'Fitted reverse reaction. ' + reaction.kinetics.comment
            
            rev_reaction = Reaction(reactants = reaction.products, products = reaction.reactants, kinetics = reverseKinetics)
            chemkin_rev = rev_reaction.toChemkin(speciesList)
            
            kineticsDataList.append([reactants, arrow, products, entry, forwardKinetics, source, href, forward, chemkin, reverseKinetics, chemkin_rev])

        return kineticsDataList
Exemplo n.º 24
0
    def getKinetics(self):
        """
        Extracts the kinetic data from the chemkin file for plotting purposes.
        """
        from rmgpy.chemkin import loadChemkinFile
        from rmgpy.kinetics import ArrheniusEP, Chebyshev
        from rmgpy.reaction import Reaction
        from rmgpy.data.base import Entry
        
        kineticsDataList = []    
        chemkinPath= os.path.join(self.path, 'chemkin','chem.inp')
        dictionaryPath = os.path.join(self.path, 'RMG_Dictionary.txt' )
        if self.Foreign:
            readComments = False
        else:
            readComments = True
        if os.path.exists(dictionaryPath):
            speciesList, reactionList = loadChemkinFile(chemkinPath, dictionaryPath, readComments=readComments)
        else:
            speciesList, reactionList = loadChemkinFile(chemkinPath, readComments=readComments)
            
        for reaction in reactionList:            
            # If the kinetics are ArrheniusEP, replace them with Arrhenius
            if isinstance(reaction.kinetics, ArrheniusEP):
                reaction.kinetics = reaction.kinetics.toArrhenius(reaction.getEnthalpyOfReaction(298))

            if os.path.exists(dictionaryPath):
                reactants = ' + '.join([moleculeToInfo(reactant) for reactant in reaction.reactants])
                arrow = '&hArr;' if reaction.reversible else '&rarr;'
                products = ' + '.join([moleculeToInfo(product) for product in reaction.products])
                href = reaction.getURL()
            else:
                reactants = ' + '.join([reactant.label for reactant in reaction.reactants])
                arrow = '&hArr;' if reaction.reversible else '&rarr;'
                products = ' + '.join([product.label for product in reaction.products])
                href = ''
                
            source = str(reaction).replace('<=>','=')
            entry = Entry()   
            entry.result = reactionList.index(reaction)+1
            forwardKinetics = reaction.kinetics     
            forward = True
            chemkin = reaction.toChemkin(speciesList)
            
            reverseKinetics = reaction.generateReverseRateCoefficient()
            reverseKinetics.comment = 'Fitted reverse reaction. ' + reaction.kinetics.comment
            
            rev_reaction = Reaction(reactants = reaction.products, products = reaction.reactants, kinetics = reverseKinetics)
            chemkin_rev = rev_reaction.toChemkin(speciesList)
            
            kineticsDataList.append([reactants, arrow, products, entry, forwardKinetics, source, href, forward, chemkin, reverseKinetics, chemkin_rev])

        return kineticsDataList
def getKineticsDepository(FullDatabase, family, depositoryLabel):
    """
    Retrieve dictionaries of exact kinetics from NIST depository and approximated kinetics 
    for those same reactions from RMG.  
    Note: does NOT average up the database or create any rate rules from training data.  
    If that is desired it must be done prior to entering this function.
    """
    
    depository = None
    for tempDepository in family.depositories:
        if re.search(re.escape(depositoryLabel), tempDepository.label):
            depository=tempDepository
            break
    else:
        print 'Depository {} not found in {} family.'.format(depositoryLabel, family.label)
        return
            
    
    exactKinetics={}
    approxKinetics={}
    
    for key, entry in depository.entries.iteritems():
        try:
            reaction=entry.item
            template=family.getReactionTemplate(reaction)
            exactKinetics[key]=entry.data
            approxKinetics[key]=family.rules.estimateKinetics(template)[0]
        except UndeterminableKineticsError:
            # See if the reaction was written in the reverse direction
            reaction = Reaction(reactants = copy.deepcopy(entry.item.products),
                                products = copy.deepcopy(entry.item.reactants),
                                kinetics = copy.deepcopy(entry.data)
                                )
            
            template=family.getReactionTemplate(reaction)

            # Getting thermo data erases the atomLabels, so do this after finding the template
            # But we need it for setting the reverse kinetics
            for spec in reaction.reactants + reaction.products:
                spec.getThermoData()

            reverseKinetics = reaction.generateReverseRateCoefficient()
            reaction.kinetics = reverseKinetics
            
            exactKinetics[key]=reaction.kinetics
            approxKinetics[key]=family.rules.estimateKinetics(template)[0]

    return exactKinetics, approxKinetics
Exemplo n.º 26
0
    def test_corespeciesRate(self):
        "Test if a specific core species rate is equal to 0 over time"    
                
        c0={self.C2H5: 0.1, self.CH3: 0.1, self.CH4: 0.4, self.C2H6: 0.4}
        rxn1 = Reaction(reactants=[self.C2H6,self.CH3], products=[self.C2H5,self.CH4], kinetics=Arrhenius(A=(686.375*6,'m^3/(mol*s)'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K')))
 
        coreSpecies = [self.CH4,self.CH3,self.C2H6,self.C2H5]
        edgeSpecies = []
        coreReactions = [rxn1]
        edgeReactions = []
        sensitivity=[]
        terminationConversion = []
        sensitivityThreshold=0.001
        ConstSpecies = ["CH4"]
        
        rxnSystem = LiquidReactor(self.T, c0, terminationConversion, sensitivity,sensitivityThreshold,ConstSpecies)
        ##The test regarding the writting of constantSPCindices from input file is check with the previous test.
        rxnSystem.constSPCIndices=[0]
        
        rxnSystem.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions)
 
        tlist = numpy.array([10**(i/10.0) for i in range(-130, -49)], numpy.float64)
 
        # Integrate to get the solution at each time point
        t = []; y = []; reactionRates = []; speciesRates = []
        for t1 in tlist:
            rxnSystem.advance(t1)
            t.append(rxnSystem.t)
            self.assertEqual(rxnSystem.coreSpeciesRates[0], 0,"Core species rate has to be equal to 0 for species hold constant. Here it is equal to {0}".format(rxnSystem.coreSpeciesRates[0]))
Exemplo n.º 27
0
    def load_old(self, path, groups, num_labels):
        """
        Load a set of old rate rules for kinetics groups into this depository.
        """
        warnings.warn("The old kinetics databases are no longer supported and may be"
                      " removed in version 2.3.", DeprecationWarning)
        # Parse the old library
        entries = self.parse_old_library(os.path.join(path, 'rateLibrary.txt'), num_parameters=10, num_labels=num_labels)

        self.entries = {}
        for entry in entries:
            index, label, data, shortDesc = entry
            if isinstance(data, str):
                kinetics = data
                rank = 0
            elif isinstance(data, tuple) and len(data) == 2:
                kinetics, rank = data
            else:
                raise DatabaseError('Unexpected data {0!r} for entry {1!s}.'.format(data, entry))
            reactants = [groups.entries[l].item for l in label.split(';')]
            item = Reaction(reactants=reactants, products=[])
            entry = Entry(
                index=index,
                label=label,
                item=item,
                data=kinetics,
                rank=rank,
                short_desc=shortDesc
            )
            try:
                self.entries[label].append(entry)
            except KeyError:
                self.entries[label] = [entry]
        self._load_old_comments(path)
Exemplo n.º 28
0
    def test_compute_flux(self):
        """
        Test the liquid batch reactor with a simple kinetic model. 
        """

        rxn1 = Reaction(reactants=[self.C2H6, self.CH3],
                        products=[self.C2H5, self.CH4],
                        kinetics=Arrhenius(A=(686.375 * 6, 'm^3/(mol*s)'),
                                           n=4.40721,
                                           Ea=(7.82799, 'kcal/mol'),
                                           T0=(298.15, 'K')))

        core_species = [self.CH4, self.CH3, self.C2H6, self.C2H5]
        edge_species = []
        core_reactions = [rxn1]
        edge_reactions = []

        c0 = {self.C2H5: 0.1, self.CH3: 0.1, self.CH4: 0.4, self.C2H6: 0.4}

        rxn_system = LiquidReactor(self.T, c0, 1, termination=[])

        rxn_system.initialize_model(core_species, core_reactions, edge_species,
                                    edge_reactions)

        tlist = np.array([10**(i / 10.0) for i in range(-130, -49)],
                         np.float64)

        # Integrate to get the solution at each time point
        t, y, reaction_rates, species_rates = [], [], [], []
        for t1 in tlist:
            rxn_system.advance(t1)
            t.append(rxn_system.t)
            # You must make a copy of y because it is overwritten by DASSL at
            # each call to advance()
            y.append(rxn_system.y.copy())
            reaction_rates.append(rxn_system.core_reaction_rates.copy())
            species_rates.append(rxn_system.core_species_rates.copy())

        # Convert the solution vectors to np arrays
        t = np.array(t, np.float64)
        reaction_rates = np.array(reaction_rates, np.float64)
        species_rates = np.array(species_rates, np.float64)

        # Check that we're computing the species fluxes correctly
        for i in range(t.shape[0]):
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   species_rates[i, 0],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   -species_rates[i, 1],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   -species_rates[i, 2],
                                   delta=1e-6 * reaction_rates[i, 0])
            self.assertAlmostEqual(reaction_rates[i, 0],
                                   species_rates[i, 3],
                                   delta=1e-6 * reaction_rates[i, 0])

        # Check that we've reached equilibrium
        self.assertAlmostEqual(reaction_rates[-1, 0], 0.0, delta=1e-2)
Exemplo n.º 29
0
    def testDuplicateReaction(self):
        """
        Test that the radical addition reaction

        HCJ=O + CH2O = [CH2]OC=O

        present in the reaction library "Methylformate",
        only appears once in the model.

        """

        from rmgpy.reaction import Reaction
        from rmgpy.molecule import Molecule
        folder = os.path.join(os.path.dirname(rmgpy.__file__),'tools/data/generate/duplicates')
        
        inputFile = os.path.join(folder,'input.py')

        rmg = RMG()
        rmg = execute(rmg, inputFile, folder)

        self.assertIsNotNone(rmg)
        
        rxnFlagged = Reaction(reactants=[Molecule(SMILES='[CH]=O'),Molecule(SMILES='C=O')],
                       products=[Molecule(SMILES='[CH2]OC=O')])

        count = 0
        for reaction in rmg.reactionModel.core.reactions:
            if reaction.isIsomorphic(rxnFlagged):
                count += 1

        self.assertEquals(count, 1)

        shutil.rmtree(os.path.join(folder,'pdep'))
Exemplo n.º 30
0
 def test_determining_rmg_kinetics(self):
     """Test the determine_rmg_kinetics() function"""
     r1 = Species().from_smiles('C')
     r2 = Species().from_smiles('O[O]')
     p1 = Species().from_smiles('[CH3]')
     p2 = Species().from_smiles('OO')
     r1.thermo = self.rmgdb.thermo.get_thermo_data(r1)
     r2.thermo = self.rmgdb.thermo.get_thermo_data(r2)
     p1.thermo = self.rmgdb.thermo.get_thermo_data(p1)
     p2.thermo = self.rmgdb.thermo.get_thermo_data(p2)
     rxn = Reaction(reactants=[r1, r2], products=[p1, p2])
     dh_rxn298 = sum([product.get_enthalpy(298) for product in rxn.products])\
         - sum([reactant.get_enthalpy(298) for reactant in rxn.reactants])
     rmg_reactions = rmgdb.determine_rmg_kinetics(rmgdb=self.rmgdb,
                                                  reaction=rxn,
                                                  dh_rxn298=dh_rxn298)
     self.assertFalse(rmg_reactions[0].kinetics.is_pressure_dependent())
     found_rxn = False
     for rxn in rmg_reactions:
         if isinstance(rxn, LibraryReaction
                       ) and rxn.library == 'Klippenstein_Glarborg2016':
             self.assertAlmostEqual(
                 rxn.kinetics.get_rate_coefficient(1000, 1e5),
                 38.2514795642, 7)
             found_rxn = True
     self.assertTrue(found_rxn)
Exemplo n.º 31
0
    def loadOld(self, path, groups, numLabels):
        """
        Load a set of old rate rules for kinetics groups into this depository.
        """
        # Parse the old library
        entries = self.parseOldLibrary(os.path.join(path, 'rateLibrary.txt'),
                                       numParameters=10,
                                       numLabels=numLabels)

        self.entries = {}
        for entry in entries:
            index, label, data, shortDesc = entry
            if isinstance(data, (str, unicode)):
                kinetics = data
                rank = 0
            elif isinstance(data, tuple) and len(data) == 2:
                kinetics, rank = data
            else:
                raise DatabaseError(
                    'Unexpected data {0!r} for entry {1!s}.'.format(
                        data, entry))
            reactants = [groups.entries[l].item for l in label.split(';')]
            item = Reaction(reactants=reactants, products=[])
            entry = Entry(index=index,
                          label=label,
                          item=item,
                          data=kinetics,
                          rank=rank,
                          shortDesc=shortDesc)
            try:
                self.entries[label].append(entry)
            except KeyError:
                self.entries[label] = [entry]
        self.__loadOldComments(path)
Exemplo n.º 32
0
def getKineticsDepository(FullDatabase, family, depositoryLabel):
    """
    Retrieve dictionaries of exact kinetics from NIST depository and approximated kinetics 
    for those same reactions from RMG.  
    Note: does NOT average up the database or create any rate rules from training data.  
    If that is desired it must be done prior to entering this function.
    """

    depository = None
    for tempDepository in family.depositories:
        if re.search(re.escape(depositoryLabel), tempDepository.label):
            depository = tempDepository
            break
    else:
        print 'Depository {} not found in {} family.'.format(
            depositoryLabel, family.label)
        return

    exactKinetics = {}
    approxKinetics = {}

    for key, entry in depository.entries.iteritems():
        try:
            reaction = entry.item
            template = family.getReactionTemplate(reaction)
            exactKinetics[key] = entry.data
            approxKinetics[key] = family.rules.estimateKinetics(template)[0]
        except UndeterminableKineticsError:
            # See if the reaction was written in the reverse direction
            reaction = Reaction(reactants=copy.deepcopy(entry.item.products),
                                products=copy.deepcopy(entry.item.reactants),
                                kinetics=copy.deepcopy(entry.data))

            template = family.getReactionTemplate(reaction)

            # Getting thermo data erases the atomLabels, so do this after finding the template
            # But we need it for setting the reverse kinetics
            for spec in reaction.reactants + reaction.products:
                spec.getThermoData()

            reverseKinetics = reaction.generateReverseRateCoefficient()
            reaction.kinetics = reverseKinetics

            exactKinetics[key] = reaction.kinetics
            approxKinetics[key] = family.rules.estimateKinetics(template)[0]

    return exactKinetics, approxKinetics
Exemplo n.º 33
0
    def load_entry(
        self,
        index,
        label,
        kinetics,
        degeneracy=1,
        duplicate=False,
        reversible=True,
        reference=None,
        referenceType='',
        shortDesc='',
        longDesc='',
        allow_pdep_route=False,
        elementary_high_p=False,
        allow_max_rate_violation=False,
        metal=None,
        site=None,
        facet=None,
    ):
        """
        Method for parsing entries in database files.
        Note that these argument names are retained for backward compatibility.
        """

        # reactants = [Species(label=reactant1.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(reactant1)])]
        # if reactant2 is not None: reactants.append(Species(label=reactant2.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(reactant2)]))
        # if reactant3 is not None: reactants.append(Species(label=reactant3.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(reactant3)]))
        #
        # products = [Species(label=product1.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(product1)])]
        # if product2 is not None: products.append(Species(label=product2.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(product2)]))
        # if product3 is not None: products.append(Species(label=product3.strip().splitlines()[0].strip(), molecule=[Molecule().from_adjacency_list(product3)]))

        # Make a blank reaction
        rxn = Reaction(reactants=[],
                       products=[],
                       degeneracy=degeneracy,
                       duplicate=duplicate,
                       reversible=reversible,
                       allow_pdep_route=allow_pdep_route,
                       elementary_high_p=elementary_high_p,
                       allow_max_rate_violation=allow_max_rate_violation)
        # if not rxn.is_balanced():
        #    raise DatabaseError('Reaction {0} in kinetics library {1} was not balanced! Please reformulate.'.format(rxn, self.label))
        # label = str(rxn)
        assert index not in self.entries, "Index of reaction {0} is not unique!".format(
            label)
        self.entries[index] = Entry(
            index=index,
            label=label,
            item=rxn,
            data=kinetics,
            reference=reference,
            reference_type=referenceType,
            short_desc=shortDesc,
            long_desc=longDesc.strip(),
            metal=metal,
            site=site,
            facet=facet,
        )
Exemplo n.º 34
0
 def makeReaction(self, reaction_string):
     """"
     Make a Reaction (containing PseudoSpecies) of from a string like 'Ab=CD'
     """
     reactants, products = reaction_string.split('=')
     reactants = [PseudoSpecies(i) for i in reactants]
     products = [PseudoSpecies(i) for i in products]
     return Reaction(reactants=reactants, products=products)
Exemplo n.º 35
0
 def testIsDissociation(self):
     """
     Test the Reaction.isDissociation() method.
     """
     isomerization = Reaction(reactants=[Species()], products=[Species()])
     association = Reaction(reactants=[Species(),Species()], products=[Species()])
     dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
     bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
     self.assertFalse(isomerization.isDissociation())
     self.assertFalse(association.isDissociation())
     self.assertTrue(dissociation.isDissociation())
     self.assertFalse(bimolecular.isDissociation())
Exemplo n.º 36
0
 def rmg_reaction_from_str(self, reaction_string: str):
     """A helper function for regenerating the RMG Reaction object from a string representation"""
     reactants, products = reaction_string.split(self.arrow)
     reactants = [
         Species(smiles=smiles) for smiles in reactants.split(self.plus)
     ]
     products = [
         Species(smiles=smiles) for smiles in products.split(self.plus)
     ]
     self.rmg_reaction = Reaction(reactants=reactants, products=products)
Exemplo n.º 37
0
 def test_give_tlist_for_kineticsjob(self):
     """
     Ensures that the proper temperature ranges are set when Tlist is specified
     """
     rxn = Reaction(transition_state=TransitionState())
     t_list = [50.7, 100, 300, 800, 1255]
     kjob = KineticsJob(rxn, Tlist=(t_list, 'K'))
     self.assertEqual(min(t_list), kjob.Tmin.value_si)
     self.assertEqual(max(t_list), kjob.Tmax.value_si)
     self.assertEqual(len(t_list), kjob.Tcount)
Exemplo n.º 38
0
def get_reaction_for_entry(entry, database):
    """
    Return a Reaction object for a given entry that uses Species instead of
    Molecules (so that we can compute the reaction thermo).
    """
    reaction = Reaction(reactants=[], products=[])
    for reactant in entry.item.reactants:
        reactant.generate_resonance_structures()
        reactant.thermo = generate_thermo_data(reactant, database)
        reaction.reactants.append(reactant)
    for product in entry.item.products:
        product.generate_resonance_structures()
        product.thermo = generate_thermo_data(product, database)
        reaction.products.append(product)

    reaction.kinetics = entry.data
    reaction.degeneracy = entry.item.degeneracy

    return reaction
Exemplo n.º 39
0
def pdepreaction(reactants, products, kinetics=None):
    global network
    try:
        rxn = Reaction(
            reactants = reactants,
            products = products,
            kinetics=kinetics,
        )
    except KeyError, e:
        raise InputError('A reaction was encountered with species "{0}", but that species was not found in the input file.'.format(e.args[0]))
Exemplo n.º 40
0
    def testDeflateReaction(self):
        """
        Test if the deflateReaction function works.
        """

        molA = Species().fromSMILES('[OH]')
        molB = Species().fromSMILES('CC')
        molC = Species().fromSMILES('[CH3]')

        reactants = [molA, molB]

        # both reactants were already part of the core:
        reactantIndices = [1, 2]
        molDict = {molA.molecule[0]: 1, molB.molecule[0]: 2}

        rxn = Reaction(reactants=[molA, molB],
                       products=[molC],
                       pairs=[(molA, molC), (molB, molC)])

        deflateReaction(rxn, molDict)

        for spc, t in zip(rxn.reactants, [int, int]):
            self.assertTrue(isinstance(spc, t))
        self.assertEquals(rxn.reactants, reactantIndices)
        for spc in rxn.products:
            self.assertTrue(isinstance(spc, Species))

        # one of the reactants was not yet part of the core:
        reactantIndices = [-1, 2]
        molDict = {molA.molecule[0]: molA, molB.molecule[0]: 2}

        rxn = Reaction(reactants=[molA, molB],
                       products=[molC],
                       pairs=[(molA, molC), (molB, molC)])

        deflateReaction(rxn, molDict)

        for spc, t in zip(rxn.reactants, [Species, int]):
            self.assertTrue(isinstance(spc, t),
                            'Species {} is not of type {}'.format(spc, t))
        for spc in rxn.products:
            self.assertTrue(isinstance(spc, Species))
Exemplo n.º 41
0
 def test_rmg_reaction_to_str(self):
     """Test the rmg_reaction_to_str() method and the reaction label generated"""
     spc1 = Species().fromSMILES(str('CON=O'))
     spc1.label = str('CONO')
     spc2 = Species().fromSMILES(str('C[N+](=O)[O-]'))
     spc2.label = str('CNO2')
     rmg_reaction = Reaction(reactants=[spc1], products=[spc2])
     rxn = ARCReaction(rmg_reaction=rmg_reaction)
     rxn_str = rxn.rmg_reaction_to_str()
     self.assertEqual(rxn_str, 'CON=O <=> [O-][N+](=O)C')
     self.assertEqual(rxn.label, 'CONO <=> CNO2')
Exemplo n.º 42
0
    def setUp(self):
        from rmgpy.reaction import Reaction

        mol1 = MockMolecule(label='mol1')
        mol2 = MockMolecule(label='mol2')
        mol3 = MockMolecule(label='mol3')
        mol4 = MockMolecule(label='mol4')

        self.rxn = Reaction(reactants=[mol1, mol2], products=[mol3, mol4])

        self.rrxn = ReductionReaction(self.rxn)
    def testInplaceRemoveIsotopeForReactions(self):
        """
        Test that removeIsotope and redoIsotope works with reactions
        """

        eth = Species().fromAdjacencyList(
        """
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
        """
    )

        ethi = Species().fromAdjacencyList(
        """
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 C u0 p0 c0 i13 {1,S} {6,S} {7,S} {8,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
        """
    )
        unlabeledRxn = Reaction(reactants=[eth], products = [eth])
        labeledRxn = Reaction(reactants=[ethi], products = [ethi])
        storedLabeledRxn = labeledRxn.copy()
        modifiedAtoms = remove_isotope(labeledRxn, inplace=True)

        self.assertTrue(unlabeledRxn.isIsomorphic(labeledRxn))

        redo_isotope(modifiedAtoms)

        self.assertTrue(storedLabeledRxn.isIsomorphic(labeledRxn))
Exemplo n.º 44
0
def getReactionForEntry(entry, database):
    """
    Return a Reaction object for a given entry that uses Species instead of
    Molecules (so that we can compute the reaction thermo).
    """
    reaction = Reaction(reactants=[], products=[])
    for molecule in entry.item.reactants:
        molecule.makeHydrogensExplicit()
        reactant = Species(molecule=[molecule], label=molecule.toSMILES())
        reactant.generateResonanceIsomers()
        reactant.thermo = generateThermoData(reactant, database)
        reaction.reactants.append(reactant)
    for molecule in entry.item.products:
        molecule.makeHydrogensExplicit()
        product = Species(molecule=[molecule], label=molecule.toSMILES())
        product.generateResonanceIsomers()
        product.thermo = generateThermoData(product, database)
        reaction.products.append(product)
    
    reaction.kinetics = entry.data
    reaction.degeneracy = entry.item.degeneracy
    
    return reaction
Exemplo n.º 45
0
 def __init__(self,
              index=-1,
              reactants=None,
              products=None,
              specificCollider=None,
              kinetics=None,
              network_kinetics=None,
              reversible=True,
              transitionState=None,
              duplicate=False,
              degeneracy=1,
              pairs=None,
              library=None,
              allow_pdep_route=False,
              elementary_high_p=False,
              allow_max_rate_violation=False,
              entry=None,
              ):
     Reaction.__init__(self,
                       index=index,
                       reactants=reactants,
                       products=products,
                       specificCollider=specificCollider,
                       kinetics=kinetics,
                       network_kinetics=network_kinetics,
                       reversible=reversible,
                       transitionState=transitionState,
                       duplicate=duplicate,
                       degeneracy=degeneracy,
                       pairs=pairs,
                       allow_pdep_route=allow_pdep_route,
                       elementary_high_p=elementary_high_p,
                       allow_max_rate_violation=allow_max_rate_violation,
                       )
     self.library = library
     self.family = library
     self.entry = entry
Exemplo n.º 46
0
class TestReaction(unittest.TestCase):
    """
    Contains unit tests of the Reaction class.
    """

    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label="C2H4",
            conformer=Conformer(
                E0=(44.7127, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(28.0313, "amu")),
                    NonlinearRotor(inertia=([3.41526, 16.6498, 20.065], "amu*angstrom^2"), symmetry=4),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                828.397,
                                970.652,
                                977.223,
                                1052.93,
                                1233.55,
                                1367.56,
                                1465.09,
                                1672.25,
                                3098.46,
                                3111.7,
                                3165.79,
                                3193.54,
                            ],
                            "cm^-1",
                        )
                    ),
                ],
                spinMultiplicity=1,
                opticalIsomers=1,
            ),
        )

        hydrogen = Species(
            label="H",
            conformer=Conformer(
                E0=(211.794, "kJ/mol"),
                modes=[IdealGasTranslation(mass=(1.00783, "amu"))],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        ethyl = Species(
            label="C2H5",
            conformer=Conformer(
                E0=(111.603, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(29.0391, "amu")),
                    NonlinearRotor(inertia=([4.8709, 22.2353, 23.9925], "amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                482.224,
                                791.876,
                                974.355,
                                1051.48,
                                1183.21,
                                1361.36,
                                1448.65,
                                1455.07,
                                1465.48,
                                2688.22,
                                2954.51,
                                3033.39,
                                3101.54,
                                3204.73,
                            ],
                            "cm^-1",
                        )
                    ),
                    HinderedRotor(
                        inertia=(1.11481, "amu*angstrom^2"),
                        symmetry=6,
                        barrier=(0.244029, "kJ/mol"),
                        semiclassical=None,
                    ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
        )

        TS = TransitionState(
            label="TS",
            conformer=Conformer(
                E0=(266.694, "kJ/mol"),
                modes=[
                    IdealGasTranslation(mass=(29.0391, "amu")),
                    NonlinearRotor(inertia=([6.78512, 22.1437, 22.2114], "amu*angstrom^2"), symmetry=1),
                    HarmonicOscillator(
                        frequencies=(
                            [
                                412.75,
                                415.206,
                                821.495,
                                924.44,
                                982.714,
                                1024.16,
                                1224.21,
                                1326.36,
                                1455.06,
                                1600.35,
                                3101.46,
                                3110.55,
                                3175.34,
                                3201.88,
                            ],
                            "cm^-1",
                        )
                    ),
                ],
                spinMultiplicity=2,
                opticalIsomers=1,
            ),
            frequency=(-750.232, "cm^-1"),
        )

        self.reaction = Reaction(
            reactants=[hydrogen, ethylene],
            products=[ethyl],
            kinetics=Arrhenius(
                A=(501366000.0, "cm^3/(mol*s)"),
                n=1.637,
                Ea=(4.32508, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(300, "K"),
                Tmax=(2500, "K"),
            ),
            transitionState=TS,
        )

        # CC(=O)O[O]
        acetylperoxy = Species(
            label="acetylperoxy",
            thermo=Wilhoit(
                Cp0=(4.0 * constants.R, "J/(mol*K)"),
                CpInf=(21.0 * constants.R, "J/(mol*K)"),
                a0=-3.95,
                a1=9.26,
                a2=-15.6,
                a3=8.55,
                B=(500.0, "K"),
                H0=(-6.151e04, "J/mol"),
                S0=(-790.2, "J/(mol*K)"),
            ),
        )

        # C[C]=O
        acetyl = Species(
            label="acetyl",
            thermo=Wilhoit(
                Cp0=(4.0 * constants.R, "J/(mol*K)"),
                CpInf=(15.5 * constants.R, "J/(mol*K)"),
                a0=0.2541,
                a1=-0.4712,
                a2=-4.434,
                a3=2.25,
                B=(500.0, "K"),
                H0=(-1.439e05, "J/mol"),
                S0=(-524.6, "J/(mol*K)"),
            ),
        )

        # [O][O]
        oxygen = Species(
            label="oxygen",
            thermo=Wilhoit(
                Cp0=(3.5 * constants.R, "J/(mol*K)"),
                CpInf=(4.5 * constants.R, "J/(mol*K)"),
                a0=-0.9324,
                a1=26.18,
                a2=-70.47,
                a3=44.12,
                B=(500.0, "K"),
                H0=(1.453e04, "J/mol"),
                S0=(-12.19, "J/(mol*K)"),
            ),
        )

        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen],
            products=[acetylperoxy],
            kinetics=Arrhenius(
                A=(2.65e12, "cm^3/(mol*s)"), n=0.0, Ea=(0.0, "kJ/mol"), T0=(1, "K"), Tmin=(300, "K"), Tmax=(2000, "K")
            ),
        )

    def testIsIsomerization(self):
        """
        Test the Reaction.isIsomerization() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertTrue(isomerization.isIsomerization())
        self.assertFalse(association.isIsomerization())
        self.assertFalse(dissociation.isIsomerization())
        self.assertFalse(bimolecular.isIsomerization())

    def testIsAssociation(self):
        """
        Test the Reaction.isAssociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertFalse(isomerization.isAssociation())
        self.assertTrue(association.isAssociation())
        self.assertFalse(dissociation.isAssociation())
        self.assertFalse(bimolecular.isAssociation())

    def testIsDissociation(self):
        """
        Test the Reaction.isDissociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(), Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(), Species()])
        bimolecular = Reaction(reactants=[Species(), Species()], products=[Species(), Species()])
        self.assertFalse(isomerization.isDissociation())
        self.assertFalse(association.isDissociation())
        self.assertTrue(dissociation.isDissociation())
        self.assertFalse(bimolecular.isDissociation())

    def testHasTemplate(self):
        """
        Test the Reaction.hasTemplate() method.
        """
        reactants = self.reaction.reactants[:]
        products = self.reaction.products[:]
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))

        reactants = self.reaction2.reactants[:]
        products = self.reaction2.products[:]
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

        reactants.reverse()
        products.reverse()
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

    def testEnthalpyOfReaction(self):
        """
        Test the Reaction.getEnthalpyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Hlist0 = [
            float(v)
            for v in [
                "-146007",
                "-145886",
                "-144195",
                "-141973",
                "-139633",
                "-137341",
                "-135155",
                "-133093",
                "-131150",
                "-129316",
            ]
        ]
        Hlist = self.reaction2.getEnthalpiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Hlist[i] / 1000.0, Hlist0[i] / 1000.0, 2)

    def testEntropyOfReaction(self):
        """
        Test the Reaction.getEntropyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Slist0 = [
            float(v)
            for v in [
                "-156.793",
                "-156.872",
                "-153.504",
                "-150.317",
                "-147.707",
                "-145.616",
                "-143.93",
                "-142.552",
                "-141.407",
                "-140.441",
            ]
        ]
        Slist = self.reaction2.getEntropiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Slist[i], Slist0[i], 2)

    def testFreeEnergyOfReaction(self):
        """
        Test the Reaction.getFreeEnergyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Glist0 = [
            float(v)
            for v in [
                "-114648",
                "-83137.2",
                "-52092.4",
                "-21719.3",
                "8073.53",
                "37398.1",
                "66346.8",
                "94990.6",
                "123383",
                "151565",
            ]
        ]
        Glist = self.reaction2.getFreeEnergiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Glist[i] / 1000.0, Glist0[i] / 1000.0, 2)

    def testEquilibriumConstantKa(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kalist0 = [
            float(v)
            for v in [
                "8.75951e+29",
                "7.1843e+10",
                "34272.7",
                "26.1877",
                "0.378696",
                "0.0235579",
                "0.00334673",
                "0.000792389",
                "0.000262777",
                "0.000110053",
            ]
        ]
        Kalist = self.reaction2.getEquilibriumConstants(Tlist, type="Ka")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kalist[i] / Kalist0[i], 1.0, 4)

    def testEquilibriumConstantKc(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kclist0 = [
            float(v)
            for v in [
                "1.45661e+28",
                "2.38935e+09",
                "1709.76",
                "1.74189",
                "0.0314866",
                "0.00235045",
                "0.000389568",
                "0.000105413",
                "3.93273e-05",
                "1.83006e-05",
            ]
        ]
        Kclist = self.reaction2.getEquilibriumConstants(Tlist, type="Kc")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kclist[i] / Kclist0[i], 1.0, 4)

    def testEquilibriumConstantKp(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kplist0 = [
            float(v)
            for v in [
                "8.75951e+24",
                "718430",
                "0.342727",
                "0.000261877",
                "3.78696e-06",
                "2.35579e-07",
                "3.34673e-08",
                "7.92389e-09",
                "2.62777e-09",
                "1.10053e-09",
            ]
        ]
        Kplist = self.reaction2.getEquilibriumConstants(Tlist, type="Kp")
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kplist[i] / Kplist0[i], 1.0, 4)

    def testStoichiometricCoefficient(self):
        """
        Test the Reaction.getStoichiometricCoefficient() method.
        """
        for reactant in self.reaction.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), -1)
        for product in self.reaction.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 1)
        for reactant in self.reaction2.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), 0)
        for product in self.reaction2.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 0)

    def testRateCoefficient(self):
        """
        Test the Reaction.getRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            self.assertAlmostEqual(
                self.reaction.getRateCoefficient(T, P) / self.reaction.kinetics.getRateCoefficient(T), 1.0, 6
            )

    def testGenerateReverseRateCoefficient(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        reverseKinetics = self.reaction2.generateReverseRateCoefficient()
        for T in Tlist:
            kr0 = self.reaction2.getRateCoefficient(T, P) / self.reaction2.getEquilibriumConstant(T)
            kr = reverseKinetics.getRateCoefficient(T)
            self.assertAlmostEqual(kr0 / kr, 1.0, 0)

    def testGenerateReverseRateCoefficientArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Arrhenius format.
        """
        original_kinetics = Arrhenius(
            A=(2.65e12, "cm^3/(mol*s)"), n=0.0, Ea=(0.0, "kJ/mol"), T0=(1, "K"), Tmin=(300, "K"), Tmax=(2000, "K")
        )
        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(original_kinetics.Tmin.value_si, original_kinetics.Tmax.value_si, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    @work_in_progress
    def testGenerateReverseRateCoefficientArrheniusEP(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the ArrheniusEP format.
        """
        from rmgpy.kinetics import ArrheniusEP

        original_kinetics = ArrheniusEP(
            A=(2.65e12, "cm^3/(mol*s)"), n=0.0, alpha=0.5, E0=(41.84, "kJ/mol"), Tmin=(300, "K"), Tmax=(2000, "K")
        )
        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(original_kinetics.Tmin, original_kinetics.Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientPDepArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the PDepArrhenius format.
        """
        from rmgpy.kinetics import PDepArrhenius

        arrhenius0 = Arrhenius(
            A=(1.0e6, "s^-1"),
            n=1.0,
            Ea=(10.0, "kJ/mol"),
            T0=(300.0, "K"),
            Tmin=(300.0, "K"),
            Tmax=(2000.0, "K"),
            comment="""This data is completely made up""",
        )

        arrhenius1 = Arrhenius(
            A=(1.0e12, "s^-1"),
            n=1.0,
            Ea=(20.0, "kJ/mol"),
            T0=(300.0, "K"),
            Tmin=(300.0, "K"),
            Tmax=(2000.0, "K"),
            comment="""This data is completely made up""",
        )

        pressures = numpy.array([0.1, 10.0])
        arrhenius = [arrhenius0, arrhenius1]
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.1
        Pmax = 10.0
        comment = """This data is completely made up"""

        original_kinetics = PDepArrhenius(
            pressures=(pressures, "bar"),
            arrhenius=arrhenius,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            comment=comment,
        )

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientMultiArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the MultiArrhenius format.
        """
        from rmgpy.kinetics import MultiArrhenius

        pressures = numpy.array([0.1, 10.0])
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.1
        Pmax = 10.0
        comment = """This data is completely made up"""

        arrhenius = [
            Arrhenius(
                A=(9.3e-14, "cm^3/(molecule*s)"),
                n=0.0,
                Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                comment=comment,
            ),
            Arrhenius(
                A=(1.4e-9, "cm^3/(molecule*s)"),
                n=0.0,
                Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                T0=(1, "K"),
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                comment=comment,
            ),
        ]

        original_kinetics = MultiArrhenius(arrhenius=arrhenius, Tmin=(Tmin, "K"), Tmax=(Tmax, "K"), comment=comment)

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientMultiPDepArrhenius(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the MultiPDepArrhenius format.
        """
        from rmgpy.kinetics import PDepArrhenius, MultiPDepArrhenius

        Tmin = 350.0
        Tmax = 1500.0
        Pmin = 1e-1
        Pmax = 1e1
        pressures = numpy.array([1e-1, 1e1])
        comment = "CH3 + C2H6 <=> CH4 + C2H5 (Baulch 2005)"
        arrhenius = [
            PDepArrhenius(
                pressures=(pressures, "bar"),
                arrhenius=[
                    Arrhenius(
                        A=(9.3e-16, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                    Arrhenius(
                        A=(9.3e-14, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(4740 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                ],
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                Pmin=(Pmin, "bar"),
                Pmax=(Pmax, "bar"),
                comment=comment,
            ),
            PDepArrhenius(
                pressures=(pressures, "bar"),
                arrhenius=[
                    Arrhenius(
                        A=(1.4e-11, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                    Arrhenius(
                        A=(1.4e-9, "cm^3/(molecule*s)"),
                        n=0.0,
                        Ea=(11200 * constants.R * 0.001, "kJ/mol"),
                        T0=(1, "K"),
                        Tmin=(Tmin, "K"),
                        Tmax=(Tmax, "K"),
                        comment=comment,
                    ),
                ],
                Tmin=(Tmin, "K"),
                Tmax=(Tmax, "K"),
                Pmin=(Pmin, "bar"),
                Pmax=(Pmax, "bar"),
                comment=comment,
            ),
        ]

        original_kinetics = MultiPDepArrhenius(
            arrhenius=arrhenius,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            comment=comment,
        )

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientThirdBody(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the ThirdBody format.
        """

        from rmgpy.kinetics import ThirdBody

        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        thirdBody = ThirdBody(
            arrheniusLow=arrheniusLow,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = thirdBody

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientLindemann(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Lindemann format.
        """

        from rmgpy.kinetics import Lindemann

        arrheniusHigh = Arrhenius(A=(1.39e16, "cm^3/(mol*s)"), n=-0.534, Ea=(2.243, "kJ/mol"), T0=(1, "K"))
        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        lindemann = Lindemann(
            arrheniusHigh=arrheniusHigh,
            arrheniusLow=arrheniusLow,
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = lindemann

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testGenerateReverseRateCoefficientTroe(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method works for the Troe format.
        """

        from rmgpy.kinetics import Troe

        arrheniusHigh = Arrhenius(A=(1.39e16, "cm^3/(mol*s)"), n=-0.534, Ea=(2.243, "kJ/mol"), T0=(1, "K"))
        arrheniusLow = Arrhenius(A=(2.62e33, "cm^6/(mol^2*s)"), n=-4.76, Ea=(10.21, "kJ/mol"), T0=(1, "K"))
        alpha = 0.783
        T3 = 74
        T1 = 2941
        T2 = 6964
        efficiencies = {"C": 3, "C(=O)=O": 2, "CC": 3, "O": 6, "[Ar]": 0.7, "[C]=O": 1.5, "[H][H]": 2}
        Tmin = 300.0
        Tmax = 2000.0
        Pmin = 0.01
        Pmax = 100.0
        comment = """H + CH3 -> CH4"""
        troe = Troe(
            arrheniusHigh=arrheniusHigh,
            arrheniusLow=arrheniusLow,
            alpha=alpha,
            T3=(T3, "K"),
            T1=(T1, "K"),
            T2=(T2, "K"),
            Tmin=(Tmin, "K"),
            Tmax=(Tmax, "K"),
            Pmin=(Pmin, "bar"),
            Pmax=(Pmax, "bar"),
            efficiencies=efficiencies,
            comment=comment,
        )

        original_kinetics = troe

        self.reaction2.kinetics = original_kinetics

        reverseKinetics = self.reaction2.generateReverseRateCoefficient()

        self.reaction2.kinetics = reverseKinetics
        # reverse reactants, products to ensure Keq is correctly computed
        self.reaction2.reactants, self.reaction2.products = self.reaction2.products, self.reaction2.reactants
        reversereverseKinetics = self.reaction2.generateReverseRateCoefficient()

        # check that reverting the reverse yields the original
        Tlist = numpy.arange(Tmin, Tmax, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            korig = original_kinetics.getRateCoefficient(T, P)
            krevrev = reversereverseKinetics.getRateCoefficient(T, P)
            self.assertAlmostEqual(korig / krevrev, 1.0, 0)

    def testTSTCalculation(self):
        """
        A test of the transition state theory k(T) calculation function,
        using the reaction H + C2H4 -> C2H5.
        """
        Tlist = 1000.0 / numpy.arange(0.4, 3.35, 0.01)
        klist = numpy.array([self.reaction.calculateTSTRateCoefficient(T) for T in Tlist])
        arrhenius = Arrhenius().fitToData(Tlist, klist, kunits="m^3/(mol*s)")
        klist2 = numpy.array([arrhenius.getRateCoefficient(T) for T in Tlist])

        # Check that the correct Arrhenius parameters are returned
        self.assertAlmostEqual(arrhenius.A.value_si, 2265.2488, delta=1e-2)
        self.assertAlmostEqual(arrhenius.n.value_si, 1.45419, delta=1e-4)
        self.assertAlmostEqual(arrhenius.Ea.value_si, 6645.24, delta=1e-2)
        # Check that the fit is satisfactory (defined here as always within 5%)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(klist[i], klist2[i], delta=5e-2 * klist[i])

    def testPickle(self):
        """
        Test that a Reaction object can be successfully pickled and
        unpickled with no loss of information.
        """
        import cPickle

        reaction = cPickle.loads(cPickle.dumps(self.reaction, -1))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6,
            2,
        )
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2
        )
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)

    def testOutput(self):
        """
        Test that a Reaction object can be successfully reconstructed
        from its repr() output with no loss of information.
        """
        exec("reaction = %r" % (self.reaction))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.conformer.E0.value_si / 1e6,
            reaction.transitionState.conformer.E0.value_si / 1e6,
            2,
        )
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(
            self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2
        )
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)

        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)
Exemplo n.º 47
0
def loadFAMEInput(path, moleculeDict=None):
    """
    Load the contents of a FAME input file into the MEASURE object. FAME
    is an early version of MEASURE written in Fortran and used by RMG-Java.
    This script enables importing FAME input files into MEASURE so we can
    use the additional functionality that MEASURE provides. Note that it
    is mostly designed to load the FAME input files generated automatically
    by RMG-Java, and may not load hand-crafted FAME input files. If you
    specify a `moleculeDict`, then this script will use it to associate
    the species with their structures.
    """
    
    def readMeaningfulLine(f):
        line = f.readline()
        while line != '':
            line = line.strip()
            if len(line) > 0 and line[0] != '#':
                return line
            else:
                line = f.readline()
        return ''

    moleculeDict = moleculeDict or {}

    logging.info('Loading file "{0}"...'.format(path))
    f = open(path)

    job = PressureDependenceJob(network=None)
    
    # Read method
    method = readMeaningfulLine(f).lower()
    if method == 'modifiedstrongcollision': 
        job.method = 'modified strong collision'
    elif method == 'reservoirstate': 
        job.method = 'reservoir state'

    # Read temperatures
    Tcount, Tunits, Tmin, Tmax = readMeaningfulLine(f).split()
    job.Tmin = Quantity(float(Tmin), Tunits) 
    job.Tmax = Quantity(float(Tmax), Tunits)
    job.Tcount = int(Tcount)
    Tlist = []
    for i in range(int(Tcount)):
        Tlist.append(float(readMeaningfulLine(f)))
    job.Tlist = Quantity(Tlist, Tunits)
    
    # Read pressures
    Pcount, Punits, Pmin, Pmax = readMeaningfulLine(f).split()
    job.Pmin = Quantity(float(Pmin), Punits) 
    job.Pmax = Quantity(float(Pmax), Punits)
    job.Pcount = int(Pcount)
    Plist = []
    for i in range(int(Pcount)):
        Plist.append(float(readMeaningfulLine(f)))
    job.Plist = Quantity(Plist, Punits)
    
    # Read interpolation model
    model = readMeaningfulLine(f).split()
    if model[0].lower() == 'chebyshev':
        job.model = ['chebyshev', int(model[1]), int(model[2])]
    elif model[0].lower() == 'pdeparrhenius':
        job.model = ['pdeparrhenius']
    
    # Read grain size or number of grains
    job.grainCount = 0
    job.grainSize = Quantity(0.0, "J/mol")
    for i in range(2):
        data = readMeaningfulLine(f).split()
        if data[0].lower() == 'numgrains':
            job.grainCount = int(data[1])
        elif data[0].lower() == 'grainsize':
            job.grainSize = Quantity(float(data[2]), data[1])

    # Create the Network
    job.network = Network()

    # Read collision model
    data = readMeaningfulLine(f)
    assert data.lower() == 'singleexpdown'
    alpha0units, alpha0 = readMeaningfulLine(f).split()
    T0units, T0 = readMeaningfulLine(f).split()
    n = readMeaningfulLine(f)
    energyTransferModel = SingleExponentialDown(
        alpha0 = Quantity(float(alpha0), alpha0units),
        T0 = Quantity(float(T0), T0units),
        n = float(n),
    )
    
    speciesDict = {}

    # Read bath gas parameters
    bathGas = Species(label='bath_gas', energyTransferModel=energyTransferModel)
    molWtunits, molWt = readMeaningfulLine(f).split()
    if molWtunits == 'u': molWtunits = 'amu'
    bathGas.molecularWeight = Quantity(float(molWt), molWtunits)
    sigmaLJunits, sigmaLJ = readMeaningfulLine(f).split()
    epsilonLJunits, epsilonLJ = readMeaningfulLine(f).split()
    assert epsilonLJunits == 'J'
    bathGas.lennardJones = LennardJones(
        sigma = Quantity(float(sigmaLJ), sigmaLJunits),
        epsilon = Quantity(float(epsilonLJ) / constants.kB, 'K'),
    )
    job.network.bathGas = {bathGas: 1.0}
    
    # Read species data
    Nspec = int(readMeaningfulLine(f))
    for i in range(Nspec):
        species = Species()
        species.conformer = Conformer()
        
        # Read species label
        species.label = readMeaningfulLine(f)
        speciesDict[species.label] = species
        if species.label in moleculeDict:
            species.molecule = [moleculeDict[species.label]]
        
        # Read species E0
        E0units, E0 = readMeaningfulLine(f).split()
        species.conformer.E0 = Quantity(float(E0), E0units)
        species.conformer.E0.units = 'kJ/mol'
        
        # Read species thermo data
        H298units, H298 = readMeaningfulLine(f).split()
        S298units, S298 = readMeaningfulLine(f).split()
        Cpcount, Cpunits = readMeaningfulLine(f).split()
        Cpdata = []
        for i in range(int(Cpcount)):
            Cpdata.append(float(readMeaningfulLine(f)))
        if S298units == 'J/mol*K': S298units = 'J/(mol*K)'
        if Cpunits == 'J/mol*K': Cpunits = 'J/(mol*K)'
        species.thermo = ThermoData(
            H298 = Quantity(float(H298), H298units),
            S298 = Quantity(float(S298), S298units),
            Tdata = Quantity([300,400,500,600,800,1000,1500], "K"),
            Cpdata = Quantity(Cpdata, Cpunits),
        )
        
        # Read species collision parameters
        molWtunits, molWt = readMeaningfulLine(f).split()
        if molWtunits == 'u': molWtunits = 'amu'
        species.molecularWeight = Quantity(float(molWt), molWtunits)
        sigmaLJunits, sigmaLJ = readMeaningfulLine(f).split()
        epsilonLJunits, epsilonLJ = readMeaningfulLine(f).split()
        assert epsilonLJunits == 'J'
        species.lennardJones = LennardJones(
            sigma = Quantity(float(sigmaLJ), sigmaLJunits),
            epsilon = Quantity(float(epsilonLJ) / constants.kB, 'K'),
        )
        
        # Read species vibrational frequencies
        freqCount, freqUnits = readMeaningfulLine(f).split()
        frequencies = []
        for j in range(int(freqCount)):
            frequencies.append(float(readMeaningfulLine(f)))
        species.conformer.modes.append(HarmonicOscillator(
            frequencies = Quantity(frequencies, freqUnits),
        ))
        
        # Read species external rotors
        rotCount, rotUnits = readMeaningfulLine(f).split()
        if int(rotCount) > 0:
            raise NotImplementedError('Cannot handle external rotational modes in FAME input.')
        
        # Read species internal rotors
        freqCount, freqUnits = readMeaningfulLine(f).split()
        frequencies = []
        for j in range(int(freqCount)):
            frequencies.append(float(readMeaningfulLine(f)))
        barrCount, barrUnits = readMeaningfulLine(f).split()
        barriers = []
        for j in range(int(barrCount)):
            barriers.append(float(readMeaningfulLine(f)))
        if barrUnits == 'cm^-1':
            barrUnits = 'J/mol'
            barriers = [barr * constants.h * constants.c * constants.Na * 100. for barr in barriers]
        elif barrUnits in ['Hz', 's^-1']:
            barrUnits = 'J/mol'
            barriers = [barr * constants.h * constants.Na for barr in barriers]
        elif barrUnits != 'J/mol':
            raise Exception('Unexpected units "{0}" for hindered rotor barrier height.'.format(barrUnits))
        inertia = [V0 / 2.0 / (nu * constants.c * 100.)**2 / constants.Na for nu, V0 in zip(frequencies, barriers)]
        for I, V0 in zip(inertia, barriers):
            species.conformer.modes.append(HinderedRotor(
                inertia = Quantity(I,"kg*m^2"), 
                barrier = Quantity(V0,barrUnits), 
                symmetry = 1,
            ))
            
        # Read overall symmetry number
        species.conformer.spinMultiplicity = int(readMeaningfulLine(f))
        
    # Read isomer, reactant channel, and product channel data
    Nisom = int(readMeaningfulLine(f))
    Nreac = int(readMeaningfulLine(f))
    Nprod = int(readMeaningfulLine(f))
    for i in range(Nisom):
        data = readMeaningfulLine(f).split()
        assert data[0] == '1'
        job.network.isomers.append(speciesDict[data[1]])
    for i in range(Nreac):
        data = readMeaningfulLine(f).split()
        assert data[0] == '2'
        job.network.reactants.append([speciesDict[data[1]], speciesDict[data[2]]])
    for i in range(Nprod):
        data = readMeaningfulLine(f).split()
        if data[0] == '1':
            job.network.products.append([speciesDict[data[1]]])
        elif data[0] == '2':
            job.network.products.append([speciesDict[data[1]], speciesDict[data[2]]])

    # Read path reactions
    Nrxn = int(readMeaningfulLine(f))
    for i in range(Nrxn):
        
        # Read and ignore reaction equation
        equation = readMeaningfulLine(f)
        reaction = Reaction(transitionState=TransitionState(), reversible=True)
        job.network.pathReactions.append(reaction)
        reaction.transitionState.conformer = Conformer()
        
        # Read reactant and product indices
        data = readMeaningfulLine(f).split()
        reac = int(data[0]) - 1
        prod = int(data[1]) - 1
        if reac < Nisom:
            reaction.reactants = [job.network.isomers[reac]]
        elif reac < Nisom+Nreac:
            reaction.reactants = job.network.reactants[reac-Nisom]
        else:
            reaction.reactants = job.network.products[reac-Nisom-Nreac]
        if prod < Nisom:
            reaction.products = [job.network.isomers[prod]]
        elif prod < Nisom+Nreac:
            reaction.products = job.network.reactants[prod-Nisom]
        else:
            reaction.products = job.network.products[prod-Nisom-Nreac]
        
        # Read reaction E0
        E0units, E0 = readMeaningfulLine(f).split()
        reaction.transitionState.conformer.E0 = Quantity(float(E0), E0units)
        reaction.transitionState.conformer.E0.units = 'kJ/mol'
        
        # Read high-pressure limit kinetics
        data = readMeaningfulLine(f)
        assert data.lower() == 'arrhenius'
        Aunits, A = readMeaningfulLine(f).split()
        if '/' in Aunits:
            index = Aunits.find('/')
            Aunits = '{0}/({1})'.format(Aunits[0:index], Aunits[index+1:])
        Eaunits, Ea = readMeaningfulLine(f).split()
        n = readMeaningfulLine(f)
        reaction.kinetics = Arrhenius(
            A = Quantity(float(A), Aunits),
            Ea = Quantity(float(Ea), Eaunits),
            n = Quantity(float(n)),
        )
        reaction.kinetics.Ea.units = 'kJ/mol'

    f.close()
    
    job.network.isomers = [Configuration(isomer) for isomer in job.network.isomers]
    job.network.reactants = [Configuration(*reactants) for reactants in job.network.reactants]
    job.network.products = [Configuration(*products) for products in job.network.products]

    return job
Exemplo n.º 48
0
class TestReaction(unittest.TestCase):
    """
    Contains unit tests of the Reaction class.
    """
    
    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label = 'C2H4',
            conformer = Conformer(
                E0 = (44.7127, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (28.0313, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [3.41526, 16.6498, 20.065],
                            'amu*angstrom^2',
                        ),
                        symmetry = 4,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [828.397, 970.652, 977.223, 1052.93, 1233.55, 1367.56, 1465.09, 1672.25, 3098.46, 3111.7, 3165.79, 3193.54],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
        )
        
        hydrogen = Species(          
            label = 'H',
            conformer = Conformer(
                E0 = (211.794, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (1.00783, 'amu'),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        ethyl = Species(
            label = 'C2H5',
            conformer = Conformer(
                E0 = (111.603, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [4.8709, 22.2353, 23.9925],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [482.224, 791.876, 974.355, 1051.48, 1183.21, 1361.36, 1448.65, 1455.07, 1465.48, 2688.22, 2954.51, 3033.39, 3101.54, 3204.73],
                            'cm^-1',
                        ),
                    ),
                    HinderedRotor(
                        inertia = (1.11481, 'amu*angstrom^2'),
                        symmetry = 6,
                        barrier = (0.244029, 'kJ/mol'),
                        semiclassical = None,
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        TS = TransitionState(
            label = 'TS',
            conformer = Conformer(
                E0 = (266.694, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [6.78512, 22.1437, 22.2114],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [412.75, 415.206, 821.495, 924.44, 982.714, 1024.16, 1224.21, 1326.36, 1455.06, 1600.35, 3101.46, 3110.55, 3175.34, 3201.88],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
            frequency = (-750.232, 'cm^-1'),
        )
        
        self.reaction = Reaction(
            reactants = [hydrogen, ethylene],
            products = [ethyl], 
            kinetics = Arrhenius(
                A = (501366000.0, 'cm^3/(mol*s)'),
                n = 1.637,
                Ea = (4.32508, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2500, 'K'),
            ),
            transitionState = TS,
        )
    
        # CC(=O)O[O]
        acetylperoxy = Species(
            label='acetylperoxy',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(21.0*constants.R,"J/(mol*K)"), a0=-3.95, a1=9.26, a2=-15.6, a3=8.55, B=(500.0,"K"), H0=(-6.151e+04,"J/mol"), S0=(-790.2,"J/(mol*K)")),
        )

        # C[C]=O
        acetyl = Species(
            label='acetyl',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(15.5*constants.R,"J/(mol*K)"), a0=0.2541, a1=-0.4712, a2=-4.434, a3=2.25, B=(500.0,"K"), H0=(-1.439e+05,"J/mol"), S0=(-524.6,"J/(mol*K)")),
        )

        # [O][O]
        oxygen = Species(
            label='oxygen',
            thermo=Wilhoit(Cp0=(3.5*constants.R,"J/(mol*K)"), CpInf=(4.5*constants.R,"J/(mol*K)"), a0=-0.9324, a1=26.18, a2=-70.47, a3=44.12, B=(500.0,"K"), H0=(1.453e+04,"J/mol"), S0=(-12.19,"J/(mol*K)")),
        )
        
        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen], 
            products=[acetylperoxy], 
            kinetics = Arrhenius(
                A = (2.65e12, 'cm^3/(mol*s)'),
                n = 0.0,
                Ea = (0.0, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2000, 'K'),
            ),
        )
        
    def testIsIsomerization(self):
        """
        Test the Reaction.isIsomerization() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertTrue(isomerization.isIsomerization())
        self.assertFalse(association.isIsomerization())
        self.assertFalse(dissociation.isIsomerization())
        self.assertFalse(bimolecular.isIsomerization())
        
    def testIsAssociation(self):
        """
        Test the Reaction.isAssociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertFalse(isomerization.isAssociation())
        self.assertTrue(association.isAssociation())
        self.assertFalse(dissociation.isAssociation())
        self.assertFalse(bimolecular.isAssociation())

    def testIsDissociation(self):
        """
        Test the Reaction.isDissociation() method.
        """
        isomerization = Reaction(reactants=[Species()], products=[Species()])
        association = Reaction(reactants=[Species(),Species()], products=[Species()])
        dissociation = Reaction(reactants=[Species()], products=[Species(),Species()])
        bimolecular = Reaction(reactants=[Species(),Species()], products=[Species(),Species()])
        self.assertFalse(isomerization.isDissociation())
        self.assertFalse(association.isDissociation())
        self.assertTrue(dissociation.isDissociation())
        self.assertFalse(bimolecular.isDissociation())

    def testHasTemplate(self):
        """
        Test the Reaction.hasTemplate() method.
        """
        reactants = self.reaction.reactants[:]
        products = self.reaction.products[:]
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))
        
        reactants.reverse()
        products.reverse()
        self.assertTrue(self.reaction.hasTemplate(reactants, products))
        self.assertTrue(self.reaction.hasTemplate(products, reactants))
        self.assertFalse(self.reaction2.hasTemplate(reactants, products))
        self.assertFalse(self.reaction2.hasTemplate(products, reactants))
        
        reactants = self.reaction2.reactants[:]
        products = self.reaction2.products[:]
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))
        
        reactants.reverse()
        products.reverse()
        self.assertFalse(self.reaction.hasTemplate(reactants, products))
        self.assertFalse(self.reaction.hasTemplate(products, reactants))
        self.assertTrue(self.reaction2.hasTemplate(reactants, products))
        self.assertTrue(self.reaction2.hasTemplate(products, reactants))

    def testEnthalpyOfReaction(self):
        """
        Test the Reaction.getEnthalpyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Hlist0 = [float(v) for v in ['-146007', '-145886', '-144195', '-141973', '-139633', '-137341', '-135155', '-133093', '-131150', '-129316']]
        Hlist = self.reaction2.getEnthalpiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Hlist[i] / 1000., Hlist0[i] / 1000., 2)

    def testEntropyOfReaction(self):
        """
        Test the Reaction.getEntropyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Slist0 = [float(v) for v in ['-156.793', '-156.872', '-153.504', '-150.317', '-147.707', '-145.616', '-143.93', '-142.552', '-141.407', '-140.441']]
        Slist = self.reaction2.getEntropiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Slist[i], Slist0[i], 2)

    def testFreeEnergyOfReaction(self):
        """
        Test the Reaction.getFreeEnergyOfReaction() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Glist0 = [float(v) for v in ['-114648', '-83137.2', '-52092.4', '-21719.3', '8073.53', '37398.1', '66346.8', '94990.6', '123383', '151565']]
        Glist = self.reaction2.getFreeEnergiesOfReaction(Tlist)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Glist[i] / 1000., Glist0[i] / 1000., 2)

    def testEquilibriumConstantKa(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kalist0 = [float(v) for v in ['8.75951e+29', '7.1843e+10', '34272.7', '26.1877', '0.378696', '0.0235579', '0.00334673', '0.000792389', '0.000262777', '0.000110053']]
        Kalist = self.reaction2.getEquilibriumConstants(Tlist, type='Ka')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kalist[i] / Kalist0[i], 1.0, 4)

    def testEquilibriumConstantKc(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kclist0 = [float(v) for v in ['1.45661e+28', '2.38935e+09', '1709.76', '1.74189', '0.0314866', '0.00235045', '0.000389568', '0.000105413', '3.93273e-05', '1.83006e-05']]
        Kclist = self.reaction2.getEquilibriumConstants(Tlist, type='Kc')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kclist[i] / Kclist0[i], 1.0, 4)

    def testEquilibriumConstantKp(self):
        """
        Test the Reaction.getEquilibriumConstant() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        Kplist0 = [float(v) for v in ['8.75951e+24', '718430', '0.342727', '0.000261877', '3.78696e-06', '2.35579e-07', '3.34673e-08', '7.92389e-09', '2.62777e-09', '1.10053e-09']]
        Kplist = self.reaction2.getEquilibriumConstants(Tlist, type='Kp')
        for i in range(len(Tlist)):
            self.assertAlmostEqual(Kplist[i] / Kplist0[i], 1.0, 4)

    def testStoichiometricCoefficient(self):
        """
        Test the Reaction.getStoichiometricCoefficient() method.
        """
        for reactant in self.reaction.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), -1)
        for product in self.reaction.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 1)
        for reactant in self.reaction2.reactants:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(reactant), 0)
        for product in self.reaction2.products:
            self.assertEqual(self.reaction.getStoichiometricCoefficient(product), 0)

    def testRateCoefficient(self):
        """
        Test the Reaction.getRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        for T in Tlist:
            self.assertAlmostEqual(self.reaction.getRateCoefficient(T, P) / self.reaction.kinetics.getRateCoefficient(T), 1.0, 6)
    
    def testGenerateReverseRateCoefficient(self):
        """
        Test the Reaction.generateReverseRateCoefficient() method.
        """
        Tlist = numpy.arange(200.0, 2001.0, 200.0, numpy.float64)
        P = 1e5
        reverseKinetics = self.reaction2.generateReverseRateCoefficient()
        for T in Tlist:
            kr0 = self.reaction2.getRateCoefficient(T, P) / self.reaction2.getEquilibriumConstant(T)
            kr = reverseKinetics.getRateCoefficient(T)
            self.assertAlmostEqual(kr0 / kr, 1.0, 0)

    def testTSTCalculation(self):
        """
        A test of the transition state theory k(T) calculation function,
        using the reaction H + C2H4 -> C2H5.
        """
        Tlist = 1000.0/numpy.arange(0.4, 3.35, 0.01)
        klist = numpy.array([self.reaction.calculateTSTRateCoefficient(T) for T in Tlist])
        arrhenius = Arrhenius().fitToData(Tlist, klist, kunits='m^3/(mol*s)')
        klist2 = numpy.array([arrhenius.getRateCoefficient(T) for T in Tlist])
        
        # Check that the correct Arrhenius parameters are returned
        self.assertAlmostEqual(arrhenius.A.value_si, 2265.2488, delta=1e-2)
        self.assertAlmostEqual(arrhenius.n.value_si, 1.45419, delta=1e-4)
        self.assertAlmostEqual(arrhenius.Ea.value_si, 6645.24, delta=1e-2)
        # Check that the fit is satisfactory (defined here as always within 5%)
        for i in range(len(Tlist)):
            self.assertAlmostEqual(klist[i], klist2[i], delta=5e-2 * klist[i])
        
    def testPickle(self):
        """
        Test that a Reaction object can be successfully pickled and
        unpickled with no loss of information.
        """
        import cPickle
        reaction = cPickle.loads(cPickle.dumps(self.reaction,-1))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.conformer.E0.value_si / 1e6, reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)
        
        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)

        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)        

    def testOutput(self):
        """
        Test that a Reaction object can be successfully reconstructed
        from its repr() output with no loss of information.
        """
        exec('reaction = %r' % (self.reaction))

        self.assertEqual(len(self.reaction.reactants), len(reaction.reactants))
        self.assertEqual(len(self.reaction.products), len(reaction.products))
        for reactant0, reactant in zip(self.reaction.reactants, reaction.reactants):
            self.assertAlmostEqual(reactant0.conformer.E0.value_si / 1e6, reactant.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(reactant0.conformer.E0.units, reactant.conformer.E0.units)
        for product0, product in zip(self.reaction.products, reaction.products):
            self.assertAlmostEqual(product0.conformer.E0.value_si / 1e6, product.conformer.E0.value_si / 1e6, 2)
            self.assertEqual(product0.conformer.E0.units, product.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.conformer.E0.value_si / 1e6, reaction.transitionState.conformer.E0.value_si / 1e6, 2)
        self.assertEqual(self.reaction.transitionState.conformer.E0.units, reaction.transitionState.conformer.E0.units)
        self.assertAlmostEqual(self.reaction.transitionState.frequency.value_si, reaction.transitionState.frequency.value_si, 2)
        self.assertEqual(self.reaction.transitionState.frequency.units, reaction.transitionState.frequency.units)
        
        self.assertAlmostEqual(self.reaction.kinetics.A.value_si, reaction.kinetics.A.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.n.value_si, reaction.kinetics.n.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.T0.value_si, reaction.kinetics.T0.value_si, delta=1e-6)
        self.assertAlmostEqual(self.reaction.kinetics.Ea.value_si, reaction.kinetics.Ea.value_si, delta=1e-6)
        self.assertEqual(self.reaction.kinetics.comment, reaction.kinetics.comment)
        
        self.assertEqual(self.reaction.duplicate, reaction.duplicate)
        self.assertEqual(self.reaction.degeneracy, reaction.degeneracy)   
Exemplo n.º 49
0
    def getForwardReactionForFamilyEntry(self, entry, family, thermoDatabase):
        """
        For a given `entry` for a reaction of the given reaction `family` (the
        string label of the family), return the reaction with kinetics and
        degeneracy for the "forward" direction as defined by the reaction 
        family. For families that are their own reverse, the direction the
        kinetics is given in will be preserved. If the entry contains 
        functional groups for the reactants, assume that it is given in the 
        forward direction and do nothing. Returns the reaction in the direction
        consistent with the reaction family template, and the matching template.
        Note that the returned reaction will have its kinetics and degeneracy
        set appropriately.
        
        In order to reverse the reactions that are given in the reverse of the
        direction the family is defined, we need to compute the thermodynamics
        of the reactants and products. For this reason you must also pass
        the `thermoDatabase` to use to generate the thermo data.
        """

        def generateThermoData(species, thermoDatabase):
            thermoData = [thermoDatabase.getThermoData(species)]
            thermoData.sort(key=lambda x: x.getEnthalpy(298))
            return thermoData[0]
        
        def matchSpeciesToMolecules(species, molecules):
            if len(species) == len(molecules) == 1:
                return species[0].isIsomorphic(molecules[0])
            elif len(species) == len(molecules) == 2:
                if species[0].isIsomorphic(molecules[0]) and species[1].isIsomorphic(molecules[1]):
                    return True
                elif species[0].isIsomorphic(molecules[1]) and species[1].isIsomorphic(molecules[0]):
                    return True
            return False

        reaction = None; template = None

        # Get the indicated reaction family
        try:
            groups = self.families[family].groups
        except KeyError:
            raise ValueError('Invalid value "{0}" for family parameter.'.format(family))

        if all([(isinstance(reactant, Group) or isinstance(reactant, LogicNode)) for reactant in entry.item.reactants]):
            # The entry is a rate rule, containing functional groups only
            # By convention, these are always given in the forward direction and
            # have kinetics defined on a per-site basis
            reaction = Reaction(
                reactants = entry.item.reactants[:],
                products = [],
                kinetics = entry.data,
                degeneracy = 1,
            )
            template = [groups.entries[label] for label in entry.label.split(';')]

        elif (all([isinstance(reactant, Molecule) for reactant in entry.item.reactants]) and
            all([isinstance(product, Molecule) for product in entry.item.products])):
            # The entry is a real reaction, containing molecules
            # These could be defined for either the forward or reverse direction
            # and could have a reaction-path degeneracy

            reaction = Reaction(reactants=[], products=[])
            for molecule in entry.item.reactants:
                reactant = Species(molecule=[molecule])
                reactant.generateResonanceIsomers()
                reactant.thermo = generateThermoData(reactant, thermoDatabase)
                reaction.reactants.append(reactant)
            for molecule in entry.item.products:
                product = Species(molecule=[molecule])
                product.generateResonanceIsomers()
                product.thermo = generateThermoData(product, thermoDatabase)
                reaction.products.append(product)

            # Generate all possible reactions involving the reactant species
            generatedReactions = self.generateReactionsFromFamilies([reactant.molecule for reactant in reaction.reactants], [], only_families=[family])

            # Remove from that set any reactions that don't produce the desired reactants and products
            forward = []; reverse = []
            for rxn in generatedReactions:
                if matchSpeciesToMolecules(reaction.reactants, rxn.reactants) and matchSpeciesToMolecules(reaction.products, rxn.products):
                    forward.append(rxn)
                if matchSpeciesToMolecules(reaction.reactants, rxn.products) and matchSpeciesToMolecules(reaction.products, rxn.reactants):
                    reverse.append(rxn)

            # We should now know whether the reaction is given in the forward or
            # reverse direction
            if len(forward) == 1 and len(reverse) == 0:
                # The reaction is in the forward direction, so use as-is
                reaction = forward[0]
                template = reaction.template
                # Don't forget to overwrite the estimated kinetics from the database with the kinetics for this entry
                reaction.kinetics = entry.data
            elif len(reverse) == 1 and len(forward) == 0:
                # The reaction is in the reverse direction
                # First fit Arrhenius kinetics in that direction
                Tdata = 1000.0 / numpy.arange(0.5, 3.301, 0.1, numpy.float64)
                kdata = numpy.zeros_like(Tdata)
                for i in range(Tdata.shape[0]):
                    kdata[i] = entry.data.getRateCoefficient(Tdata[i]) / reaction.getEquilibriumConstant(Tdata[i])
                kunits = 'm^3/(mol*s)' if len(reverse[0].reactants) == 2 else 's^-1'
                kinetics = Arrhenius().fitToData(Tdata, kdata, kunits, T0=1.0)
                kinetics.Tmin = entry.data.Tmin
                kinetics.Tmax = entry.data.Tmax
                kinetics.Pmin = entry.data.Pmin
                kinetics.Pmax = entry.data.Pmax
                # Now flip the direction
                reaction = reverse[0]
                reaction.kinetics = kinetics
                template = reaction.template
            elif len(reverse) > 0 and len(forward) > 0:
                print 'FAIL: Multiple reactions found for {0!r}.'.format(entry.label)
            elif len(reverse) == 0 and len(forward) == 0:
                print 'FAIL: No reactions found for "%s".' % (entry.label)
            else:
                print 'FAIL: Unable to estimate kinetics for {0!r}.'.format(entry.label)

        assert reaction is not None
        assert template is not None
        return reaction, template
    def testSolveCH3(self):
        """
        Test the surface batch reactor with a nondissociative adsorption of CH3

        Here we choose a kinetic model consisting of the  adsorption reaction
        CH3 + X <=>  CH3X
        We use a sticking coefficient for the rate expression.
        """

        CH3 = Species(
            molecule=[Molecule().fromSMILES("[CH3]")],
            thermo=NASA(polynomials=[NASAPolynomial(coeffs=[3.91547, 0.00184155, 3.48741e-06, -3.32746e-09, 8.49953e-13, 16285.6, 0.351743], Tmin=(100, 'K'), Tmax=(1337.63, 'K')),
                                     NASAPolynomial(coeffs=[3.54146, 0.00476786, -1.82148e-06, 3.28876e-10, -2.22545e-14, 16224, 1.66032], Tmin=(1337.63, 'K'), Tmax=(5000, 'K'))],
                       Tmin=(100, 'K'), Tmax=(5000, 'K'), E0=(135.382, 'kJ/mol'),
                       comment="""Thermo library: primaryThermoLibrary + radical(CH3)"""
                       ),
            molecularWeight=(15.0345, 'amu'),
                    )

        X = Species(
            molecule=[Molecule().fromAdjacencyList("1 X u0 p0")],
            thermo=NASA(polynomials=[NASAPolynomial(coeffs=[0, 0, 0, 0, 0, 0, 0], Tmin=(298, 'K'), Tmax=(1000, 'K')),
                                    NASAPolynomial(coeffs=[0, 0, 0, 0, 0, 0, 0], Tmin=(1000, 'K'), Tmax=(2000, 'K'))],
                        Tmin=(298, 'K'), Tmax=(2000, 'K'), E0=(-6.19426, 'kJ/mol'),
                        comment="""Thermo library: surfaceThermo""")
                    )

        CH3X = Species(
            molecule=[Molecule().fromAdjacencyList("1 H u0 p0 {2,S} \n 2 X u0 p0 {1,S}")],
            thermo=NASA(polynomials=[NASAPolynomial(coeffs=[-0.552219, 0.026442, -3.55617e-05, 2.60044e-08, -7.52707e-12, -4433.47, 0.692144], Tmin=(298, 'K'), Tmax=(1000, 'K')),
                                     NASAPolynomial(coeffs=[3.62557, 0.00739512, -2.43797e-06, 1.86159e-10, 3.6485e-14, -5187.22, -18.9668], Tmin=(1000, 'K'), Tmax=(2000, 'K'))],
                        Tmin=(298, 'K'), Tmax=(2000, 'K'), E0=(-39.1285, 'kJ/mol'),
                        comment="""Thermo library: surfaceThermo""")
                    )

        rxn1 = Reaction(reactants=[CH3, X],
                        products=[CH3X],
                        kinetics=StickingCoefficient(A=0.1, n=0, Ea=(0, 'kcal/mol'),
                                                     T0=(1, 'K'),
                                                     Tmin=(200, 'K'), Tmax=(3000, 'K'),
                                                     comment="""Exact match found for rate rule (Adsorbate;VacantSite)"""
                                                     )
#                        kinetics=SurfaceArrhenius(A=(2.7e10, 'cm^3/(mol*s)'),
#                                           n=0.5,
#                                           Ea=(5.0, 'kJ/mol'),
#                                           T0=(1.0, 'K'))
                        )
        coreSpecies = [CH3, X, CH3X]
        edgeSpecies = []
        coreReactions = [rxn1]
        edgeReactions = []

        T = 800.
        initialP = 1.0e5
        rxnSystem = SurfaceReactor(
            T, initialP,
            nSims=1,
            initialGasMoleFractions={CH3: 1.0},
            initialSurfaceCoverages={X: 1.0},
            surfaceVolumeRatio=(1., 'm^-1'),
            surfaceSiteDensity=(2.72e-9, 'mol/cm^2'),
            termination=[])
        # in chemkin, the sites are mostly occupied in about 1e-8 seconds.

        rxnSystem.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions)

        tlist = numpy.logspace(-13, -5, 81, dtype=numpy.float64)

        print "Surface site density:", rxnSystem.surfaceSiteDensity.value_si

        print "rxn1 rate coefficient", rxn1.getSurfaceRateCoefficient(rxnSystem.T.value_si,
                                            rxnSystem.surfaceSiteDensity.value_si
                                            )

        # Integrate to get the solution at each time point
        t = []
        y = []
        reactionRates = []
        speciesRates = []
        t.append(rxnSystem.t)
        # You must make a copy of y because it is overwritten by DASSL at
        # each call to advance()
        y.append(rxnSystem.y.copy())
        reactionRates.append(rxnSystem.coreReactionRates.copy())
        speciesRates.append(rxnSystem.coreSpeciesRates.copy())
        print "time: ", t
        print "moles:", y
        print "reaction rates:", reactionRates
        print "species rates:", speciesRates
        for t1 in tlist:
            rxnSystem.advance(t1)
            t.append(rxnSystem.t)
            # You must make a copy of y because it is overwritten by DASSL at
            # each call to advance()
            y.append(rxnSystem.y.copy())
            reactionRates.append(rxnSystem.coreReactionRates.copy())
            speciesRates.append(rxnSystem.coreSpeciesRates.copy())

        # Convert the solution vectors to numpy arrays
        t = numpy.array(t, numpy.float64)
        y = numpy.array(y, numpy.float64)
        reactionRates = numpy.array(reactionRates, numpy.float64)
        speciesRates = numpy.array(speciesRates, numpy.float64)
        V = constants.R * rxnSystem.T.value_si * numpy.sum(y) / rxnSystem.initialP.value_si

        # Check that we're computing the species fluxes correctly
        for i in range(t.shape[0]):
            self.assertAlmostEqual(reactionRates[i, 0], -speciesRates[i, 0],
                                   delta=1e-6 * reactionRates[i, 0])
            self.assertAlmostEqual(reactionRates[i, 0], -speciesRates[i, 1],
                                   delta=1e-6 * reactionRates[i, 0])
            self.assertAlmostEqual(reactionRates[i, 0], speciesRates[i, 2],
                                   delta=1e-6 * reactionRates[i, 0])

        # Check that we've reached equilibrium by the end
        self.assertAlmostEqual(reactionRates[-1, 0], 0.0, delta=1e-2)
Exemplo n.º 51
0
    def setUp(self):
        """
        A method that is called prior to each unit test in this class.
        """
        ethylene = Species(
            label = 'C2H4',
            conformer = Conformer(
                E0 = (44.7127, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (28.0313, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [3.41526, 16.6498, 20.065],
                            'amu*angstrom^2',
                        ),
                        symmetry = 4,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [828.397, 970.652, 977.223, 1052.93, 1233.55, 1367.56, 1465.09, 1672.25, 3098.46, 3111.7, 3165.79, 3193.54],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 1,
                opticalIsomers = 1,
            ),
        )
        
        hydrogen = Species(          
            label = 'H',
            conformer = Conformer(
                E0 = (211.794, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (1.00783, 'amu'),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        ethyl = Species(
            label = 'C2H5',
            conformer = Conformer(
                E0 = (111.603, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [4.8709, 22.2353, 23.9925],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [482.224, 791.876, 974.355, 1051.48, 1183.21, 1361.36, 1448.65, 1455.07, 1465.48, 2688.22, 2954.51, 3033.39, 3101.54, 3204.73],
                            'cm^-1',
                        ),
                    ),
                    HinderedRotor(
                        inertia = (1.11481, 'amu*angstrom^2'),
                        symmetry = 6,
                        barrier = (0.244029, 'kJ/mol'),
                        semiclassical = None,
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
        )
        
        TS = TransitionState(
            label = 'TS',
            conformer = Conformer(
                E0 = (266.694, 'kJ/mol'),
                modes = [
                    IdealGasTranslation(
                        mass = (29.0391, 'amu'),
                    ),
                    NonlinearRotor(
                        inertia = (
                            [6.78512, 22.1437, 22.2114],
                            'amu*angstrom^2',
                        ),
                        symmetry = 1,
                    ),
                    HarmonicOscillator(
                        frequencies = (
                            [412.75, 415.206, 821.495, 924.44, 982.714, 1024.16, 1224.21, 1326.36, 1455.06, 1600.35, 3101.46, 3110.55, 3175.34, 3201.88],
                            'cm^-1',
                        ),
                    ),
                ],
                spinMultiplicity = 2,
                opticalIsomers = 1,
            ),
            frequency = (-750.232, 'cm^-1'),
        )
        
        self.reaction = Reaction(
            reactants = [hydrogen, ethylene],
            products = [ethyl], 
            kinetics = Arrhenius(
                A = (501366000.0, 'cm^3/(mol*s)'),
                n = 1.637,
                Ea = (4.32508, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2500, 'K'),
            ),
            transitionState = TS,
        )
    
        # CC(=O)O[O]
        acetylperoxy = Species(
            label='acetylperoxy',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(21.0*constants.R,"J/(mol*K)"), a0=-3.95, a1=9.26, a2=-15.6, a3=8.55, B=(500.0,"K"), H0=(-6.151e+04,"J/mol"), S0=(-790.2,"J/(mol*K)")),
        )

        # C[C]=O
        acetyl = Species(
            label='acetyl',
            thermo=Wilhoit(Cp0=(4.0*constants.R,"J/(mol*K)"), CpInf=(15.5*constants.R,"J/(mol*K)"), a0=0.2541, a1=-0.4712, a2=-4.434, a3=2.25, B=(500.0,"K"), H0=(-1.439e+05,"J/mol"), S0=(-524.6,"J/(mol*K)")),
        )

        # [O][O]
        oxygen = Species(
            label='oxygen',
            thermo=Wilhoit(Cp0=(3.5*constants.R,"J/(mol*K)"), CpInf=(4.5*constants.R,"J/(mol*K)"), a0=-0.9324, a1=26.18, a2=-70.47, a3=44.12, B=(500.0,"K"), H0=(1.453e+04,"J/mol"), S0=(-12.19,"J/(mol*K)")),
        )
        
        self.reaction2 = Reaction(
            reactants=[acetyl, oxygen], 
            products=[acetylperoxy], 
            kinetics = Arrhenius(
                A = (2.65e12, 'cm^3/(mol*s)'),
                n = 0.0,
                Ea = (0.0, 'kJ/mol'),
                T0 = (1, 'K'),
                Tmin = (300, 'K'),
                Tmax = (2000, 'K'),
            ),
        )