예제 #1
0
    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
예제 #2
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.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
예제 #3
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
예제 #4
0
    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
예제 #5
0
    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