def get_rmg_reaction(self): """ Convert PrIMeReaction to an RMG reaction. """ if not all((self.reactants, self.products, self.kinetics)): raise ConversionError( 'Missing reactants, products, or kinetics for reaction {}.'. format(self.prime_id)) if not self._direction_matched: self.match_direction() reaction = Reaction() if self.rmg_reactants is None or self.rmg_products is None: reaction.reactants = [s.get_rmg_species() for s in self.reactants] reaction.products = [s.get_rmg_species() for s in self.products] else: reaction.reactants = self.rmg_reactants reaction.products = self.rmg_products reaction.kinetics = self.kinetics.expression return reaction
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.interpolationModel = ('chebyshev', int(model[1]), int(model[2])) elif model[0].lower() == 'pdeparrhenius': job.interpolationModel = ('pdeparrhenius',) # Read grain size or number of grains job.minimumGrainCount = 0 job.maximumGrainSize = None for i in range(2): data = readMeaningfulLine(f).split() if data[0].lower() == 'numgrains': job.minimumGrainCount = int(data[1]) elif data[0].lower() == 'grainsize': job.maximumGrainSize = (float(data[2]), data[1]) # A FAME file is almost certainly created during an RMG job, so use RMG mode job.rmgmode = True # 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.transportData = TransportData( 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() species.energyTransferModel = energyTransferModel # 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), Cp0 = (Cpdata[0], Cpunits), CpInf = (Cpdata[-1], 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.transportData = TransportData( 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, semiclassical = False, )) # 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
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
def get_labeled_reaction(self): """ A method that will return a labeled reaction given a reaction label or rmg_reaction A label or an rmg_reaction needs to be provided in order for this method to work. If both are provided, we assert that the label matches the reaction. Variables: - label (str): the reaction label of interest - rmg_reaction (RMGReaction): the reaction of interest Returns: - reaction (RMGReaction): An RMGReaction with labeled reactants and products - name (str): The string corresponding to the reaction family matched to the reaction of interest """ if not (self.rmg_database or self.ts_databases): self.rmg_database, self.ts_databases = self.load_databases() assert (self.label or self.rmg_reaction ), "You must provide a reaction or a reaction label" match = False if self.label: rmg_reactants = [] rmg_products = [] r, p = self.label.split("_") for react in r.split("+"): s = RMGMolecule(SMILES=react) rmg_reactants.append(s) for prod in p.split("+"): s = RMGMolecule(SMILES=prod) rmg_products.append(s) test_reaction = RMGReaction(reactants=rmg_reactants, products=rmg_products) if self.rmg_reaction: assert self.rmg_reaction.isIsomorphic( test_reaction ), "The reaction label provided does not match the RMGReaction provided..." for name, family in list( self.rmg_database.kinetics.families.items()): if match: break try: labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.reactants, test_reaction.products) except ValueError: continue if not (labeled_r and labeled_p): continue if ((len(labeled_r) > 0) and (len(labeled_p) > 0)): logging.info("Matched reaction to {} family".format(name)) labeled_reactants = deepcopy(labeled_r) labeled_products = deepcopy(labeled_p) test_reaction.reactants = labeled_r[:] test_reaction.products = labeled_p[:] match = True final_family = family final_name = name break elif self.rmg_reaction: #RMGReaction but no label rmg_reactants = [] rmg_products = [] for react in self.rmg_reaction.reactants: if isinstance(react, RMGSpecies): rmg_reactants.append(react.molecule) elif isinstance(react, RMGMolecule): rmg_reactants.append([react]) for prod in self.rmg_reaction.products: if isinstance(prod, RMGSpecies): rmg_products.append(prod.molecule) elif isinstance(prod, RMGMolecule): rmg_products.append([prod]) test_reactants = [] test_products = [] if len(rmg_reactants) == 1: for l1 in rmg_reactants[0]: test_reactants.append([l1]) elif len(rmg_reactants) == 2: l1, l2 = rmg_reactants for i in l1: for j in l2: test_reactants.append([i, j]) if len(rmg_products) == 1: for l1 in rmg_products[0]: test_products.append([l1]) elif len(rmg_products) == 2: l1, l2 = rmg_products for i in l1: for j in l2: test_products.append([i, j]) reacts = test_reactants[:] prods = test_products[:] for name, family in list( self.rmg_database.kinetics.families.items()): logging.info("Trying to match {} to {}".format( self.rmg_reaction, family)) if match: continue test_reactants = reacts[:] test_products = prods[:] for test_reactant in test_reactants: for test_product in test_products: if match: continue test_reaction = RMGReaction(reactants=test_reactant, products=test_product) try: labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.reactants, test_reaction.products) if not (labeled_r and labeled_p): logging.info( "Unable to determine a reaction for the forward direction. Trying the reverse direction." ) raise ActionError except (ValueError, ActionError, IndexError): try: # Trying the reverse reaction if the forward reaction doesn't work # This is useful for R_Addition reactions labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.products, test_reaction.reactants) except (ValueError, ActionError, IndexError): continue if not (labeled_r and labeled_p): labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.products, test_reaction.reactants) continue if ((len(labeled_r) > 0) and (len(labeled_p) > 0)) and ( self.rmg_reaction.isIsomorphic(test_reaction)): logging.info( "Matched reaction to {} family".format(name)) labeled_reactants = deepcopy(labeled_r) labeled_products = deepcopy(labeled_p) test_reaction.reactants = labeled_r[:] test_reaction.products = labeled_p[:] logging.info("{}".format(labeled_r)) logging.info("{}".format(labeled_p)) match = True final_family = family print final_family final_name = name assert match, "Could not idetify labeled reactants and products" #try: reaction_list = final_family.generateReactions(test_reaction.reactants, test_reaction.products) #except KeyError: # reaction_list = None # logging.info("For some reason, RMG is having trouble generating reactions for {}".format(test_reaction)) assert reaction_list, "Could not match a reaction to a reaction family..." for reaction in reaction_list: if test_reaction.isIsomorphic(reaction): reaction.reactants = labeled_reactants reaction.products = labeled_products break self.rmg_reaction = reaction self.reaction_family = final_name return self.rmg_reaction, self.reaction_family
def get_labeled_reaction(self, label=None, rmg_reaction=None): """ A method that will return a labeled reaction given a reaction label or rmg_reaction A label or an rmg_reaction needs to be provided in order for this method to work. If both are provided, we assert that the label matches the reaction. Variables: - label (str): the reaction label of interest - rmg_reaction (RMGReaction): the reaction of interest Returns: - reaction (RMGReaction): An RMGReaction with labeled reactants and products - name (str): The string corresponding to the reaction family matched to the reaction of interest """ assert ( label or rmg_reaction), "You must provide a reaction or a reaction label" label_reaction = None rmg_reaction_reaction = None test_reactions = [] match = False if label: rmg_reactants = [] rmg_products = [] r, p = label.split("_") for react in r.split("+"): s = RMGMolecule(SMILES=react) rmg_reactants.append(s) for prod in p.split("+"): s = RMGMolecule(SMILES=prod) rmg_products.append(s) test_reaction = RMGReaction( reactants=rmg_reactants, products=rmg_products) if rmg_reaction: assert rmg_reaction.isIsomorphic( test_reaction), "The reaction label provided does not match the RMGReaction provided..." for name, family in list(self.rmg_database.kinetics.families.items()): if match: break labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.reactants, test_reaction.products) if not (labeled_r and labeled_p): continue if ((len(labeled_r) > 0) and (len(labeled_p) > 0)): logging.info("Matched reaction to {} family".format(name)) labeled_reactants = deepcopy(labeled_r) labeled_products = deepcopy(labeled_p) test_reaction.reactants = labeled_r[:] test_reaction.products = labeled_p[:] match = True final_name = name break elif rmg_reaction: rmg_reactants = [] rmg_products = [] for react in rmg_reaction.reactants: if isinstance(react, RMGSpecies): rmg_reactants.append(react.molecule) elif isinstance(react, RMGMolecule): rmg_reactants.append([react]) for prod in rmg_reaction.products: if isinstance(prod, RMGSpecies): rmg_products.append(prod.molecule) elif isinstance(prod, RMGMolecule): rmg_products.append([prod]) test_reactants = [] test_products = [] if len(rmg_reactants) == 1: test_reactants = rmg_reactants elif len(rmg_reactants) == 2: l1, l2 = rmg_reactants for i in l1: for j in l2: test_reactants.append([i, j]) if len(rmg_products) == 1: test_reactants = rmg_products elif len(rmg_products) == 2: l1, l2 = rmg_products for i in l1: for j in l2: test_products.append([i, j]) for name, family in list(self.rmg_database.kinetics.families.items()): if match: break for test_reactant in test_reactants: for test_products in test_products: if match: continue test_reaction = RMGReaction( reactants=test_reactant, products=test_products) labeled_r, labeled_p = family.getLabeledReactantsAndProducts( test_reaction.reactants, test_reaction.products) if not (labeled_r and labeled_p): continue if ((len(labeled_r) > 0) and (len(labeled_p) > 0)): logging.info( "Matched reaction to {} family".format(name)) labeled_reactants = deepcopy(labeled_r) labeled_products = deepcopy(labeled_p) test_reaction.reactants = labeled_r[:] test_reaction.products = labeled_p[:] logging.info("\n{}".format(labeled_r)) logging.info("\n{}".format(labeled_p)) match = True final_name = name break assert match, "Could not idetify labeled reactants and products" reaction_list = self.rmg_database.kinetics.generate_reactions_from_families( test_reaction.reactants, test_reaction.products, only_families=[final_name]) assert reaction_list, "Could not match a reaction to a reaction family..." for reaction in reaction_list: if test_reaction.isIsomorphic(reaction): reaction.reactants = labeled_reactants reaction.products = labeled_products break return reaction, name