def simpleReactor(temperature, pressure, initialMoleFractions, terminationConversion=None, terminationTime=None, sensitivity=None, sensitivityThreshold=1e-3): logging.debug('Found SimpleReactor reaction system') for value in initialMoleFractions.values(): if value < 0: raise InputError('Initial mole fractions cannot be negative.') for spec in initialMoleFractions: initialMoleFractions[spec] = float(initialMoleFractions[spec]) totalInitialMoles = sum(initialMoleFractions.values()) if totalInitialMoles != 1: logging.warning( 'Initial mole fractions do not sum to one; normalizing.') logging.info('') logging.info('Original composition:') for spec, molfrac in initialMoleFractions.iteritems(): logging.info("{0} = {1}".format(spec, molfrac)) for spec in initialMoleFractions: initialMoleFractions[spec] /= totalInitialMoles logging.info('') logging.info('Normalized mole fractions:') for spec, molfrac in initialMoleFractions.iteritems(): logging.info("{0} = {1}".format(spec, molfrac)) T = Quantity(temperature) P = Quantity(pressure) termination = [] if terminationConversion is not None: for spec, conv in terminationConversion.iteritems(): termination.append(TerminationConversion(speciesDict[spec], conv)) if terminationTime is not None: termination.append(TerminationTime(Quantity(terminationTime))) if len(termination) == 0: raise InputError( 'No termination conditions specified for reaction system #{0}.'. format(len(rmg.reactionSystems) + 2)) sensitiveSpecies = [] if sensitivity: if isinstance(sensitivity, str): sensitivity = [sensitivity] for spec in sensitivity: sensitiveSpecies.append(speciesDict[spec]) system = SimpleReactor(T, P, initialMoleFractions, termination, sensitiveSpecies, sensitivityThreshold) rmg.reactionSystems.append(system)
def simpleReactor(temperature, pressure, initialMoleFractions, terminationConversion=None, terminationTime=None, sensitivity=None, sensitivityThreshold=1e-3): logging.debug('Found SimpleReactor reaction system') for value in initialMoleFractions.values(): if value < 0: raise InputError('Initial mole fractions cannot be negative.') if sum(initialMoleFractions.values()) != 1: logging.warning( 'Initial mole fractions do not sum to one; renormalizing.') for spec in initialMoleFractions: initialMoleFractions[spec] /= sum(initialMoleFractions.values()) T = Quantity(temperature) P = Quantity(pressure) termination = [] if terminationConversion is not None: for spec, conv in terminationConversion.iteritems(): termination.append(TerminationConversion(speciesDict[spec], conv)) if terminationTime is not None: termination.append(TerminationTime(Quantity(terminationTime))) if len(termination) == 0: raise InputError( 'No termination conditions specified for reaction system #{0}.'. format(len(rmg.reactionSystems) + 2)) sensitiveSpecies = [] if sensitivity: for spec in sensitivity: sensitiveSpecies.append(speciesDict[spec]) system = SimpleReactor(T, P, initialMoleFractions, termination, sensitiveSpecies, sensitivityThreshold) rmg.reactionSystems.append(system)
def saveForm(self, posted, form): """ Save form data into input.py file specified by the path. """ # Clean past history self.rmg = RMG() # Databases #self.rmg.databaseDirectory = settings['database.directory'] self.rmg.thermoLibraries = [] if posted.thermo_libraries.all(): self.rmg.thermoLibraries = [ item.thermolib.encode() for item in posted.thermo_libraries.all() ] self.rmg.reactionLibraries = [] self.rmg.seedMechanisms = [] if posted.reaction_libraries.all(): for item in posted.reaction_libraries.all(): if not item.seedmech and not item.edge: self.rmg.reactionLibraries.append( (item.reactionlib.encode(), False)) elif not item.seedmech: self.rmg.reactionLibraries.append( (item.reactionlib.encode(), True)) else: self.rmg.seedMechanisms.append(item.reactionlib.encode()) self.rmg.statmechLibraries = [] self.rmg.kineticsDepositories = 'default' self.rmg.kineticsFamilies = 'default' self.rmg.kineticsEstimator = 'rate rules' # Species self.rmg.initialSpecies = [] speciesDict = {} initialMoleFractions = {} self.rmg.reactionModel = CoreEdgeReactionModel() for item in posted.reactor_species.all(): structure = Molecule().fromAdjacencyList(item.adjlist.encode()) spec, isNew = self.rmg.reactionModel.makeNewSpecies( structure, label=item.name.encode(), reactive=False if item.inert else True) self.rmg.initialSpecies.append(spec) speciesDict[item.name.encode()] = spec initialMoleFractions[spec] = item.molefrac # Reactor systems self.rmg.reactionSystems = [] for item in posted.reactor_systems.all(): T = Quantity(item.temperature, item.temperature_units.encode()) P = Quantity(item.pressure, item.pressure_units.encode()) termination = [] if item.conversion: termination.append( TerminationConversion(speciesDict[item.species.encode()], item.conversion)) termination.append( TerminationTime( Quantity(item.terminationtime, item.time_units.encode()))) # Sensitivity Analysis sensitiveSpecies = [] if item.sensitivity: if isinstance(item.sensitivity.encode(), str): sensitivity = item.sensitivity.encode().split(',') for spec in sensitivity: sensitiveSpecies.append(speciesDict[spec.strip()]) system = SimpleReactor(T, P, initialMoleFractions, termination, sensitiveSpecies, item.sensitivityThreshold) self.rmg.reactionSystems.append(system) # Simulator tolerances self.rmg.absoluteTolerance = form.cleaned_data['simulator_atol'] self.rmg.relativeTolerance = form.cleaned_data['simulator_rtol'] self.rmg.sensitivityAbsoluteTolerance = form.cleaned_data[ 'simulator_sens_atol'] self.rmg.sensitivityRelativeTolerance = form.cleaned_data[ 'simulator_sens_rtol'] self.rmg.fluxToleranceKeepInEdge = form.cleaned_data[ 'toleranceKeepInEdge'] self.rmg.fluxToleranceMoveToCore = form.cleaned_data[ 'toleranceMoveToCore'] self.rmg.fluxToleranceInterrupt = form.cleaned_data[ 'toleranceInterruptSimulation'] self.rmg.maximumEdgeSpecies = form.cleaned_data['maximumEdgeSpecies'] self.rmg.minCoreSizeForPrune = form.cleaned_data['minCoreSizeForPrune'] self.rmg.minSpeciesExistIterationsForPrune = form.cleaned_data[ 'minSpeciesExistIterationsForPrune'] self.rmg.filterReactions = form.cleaned_data['filterReactions'] # Pressure Dependence pdep = form.cleaned_data['pdep'].encode() if pdep != 'off': self.rmg.pressureDependence = PressureDependenceJob(network=None) self.rmg.pressureDependence.method = pdep # Process interpolation model if form.cleaned_data['interpolation'].encode() == 'chebyshev': self.rmg.pressureDependence.interpolationModel = ( form.cleaned_data['interpolation'].encode(), form.cleaned_data['temp_basis'], form.cleaned_data['p_basis']) else: self.rmg.pressureDependence.interpolationModel = ( form.cleaned_data['interpolation'].encode(), ) # Temperature and pressure range self.rmg.pressureDependence.Tmin = Quantity( form.cleaned_data['temp_low'], form.cleaned_data['temprange_units'].encode()) self.rmg.pressureDependence.Tmax = Quantity( form.cleaned_data['temp_high'], form.cleaned_data['temprange_units'].encode()) self.rmg.pressureDependence.Tcount = form.cleaned_data[ 'temp_interp'] self.rmg.pressureDependence.generateTemperatureList() self.rmg.pressureDependence.Pmin = Quantity( form.cleaned_data['p_low'], form.cleaned_data['prange_units'].encode()) self.rmg.pressureDependence.Pmax = Quantity( form.cleaned_data['p_high'], form.cleaned_data['prange_units'].encode()) self.rmg.pressureDependence.Pcount = form.cleaned_data['p_interp'] self.rmg.pressureDependence.generatePressureList() # Process grain size and count self.rmg.pressureDependence.grainSize = Quantity( form.cleaned_data['maximumGrainSize'], form.cleaned_data['grainsize_units'].encode()) self.rmg.pressureDependence.grainCount = form.cleaned_data[ 'minimumNumberOfGrains'] self.rmg.pressureDependence.maximumAtoms = form.cleaned_data[ 'maximumAtoms'] # Additional Options self.rmg.units = 'si' self.rmg.saveRestartPeriod = Quantity( form.cleaned_data['saveRestartPeriod'], form.cleaned_data['saveRestartPeriodUnits'].encode( )) if form.cleaned_data['saveRestartPeriod'] else None self.rmg.generateOutputHTML = form.cleaned_data['generateOutputHTML'] self.rmg.generatePlots = form.cleaned_data['generatePlots'] self.rmg.saveSimulationProfiles = form.cleaned_data[ 'saveSimulationProfiles'] self.rmg.saveEdgeSpecies = form.cleaned_data['saveEdgeSpecies'] self.rmg.verboseComments = form.cleaned_data['verboseComments'] # Species Constraints speciesConstraints = form.cleaned_data['speciesConstraints'] if speciesConstraints == 'on': allowed = [] if form.cleaned_data['allowed_inputSpecies']: allowed.append('input species') if form.cleaned_data['allowed_seedMechanisms']: allowed.append('seed mechanisms') if form.cleaned_data['allowed_reactionLibraries']: allowed.append('reaction libraries') self.rmg.speciesConstraints['allowed'] = allowed self.rmg.speciesConstraints[ 'maximumCarbonAtoms'] = form.cleaned_data['maximumCarbonAtoms'] self.rmg.speciesConstraints[ 'maximumOxygenAtoms'] = form.cleaned_data['maximumOxygenAtoms'] self.rmg.speciesConstraints[ 'maximumNitrogenAtoms'] = form.cleaned_data[ 'maximumNitrogenAtoms'] self.rmg.speciesConstraints[ 'maximumSiliconAtoms'] = form.cleaned_data[ 'maximumSiliconAtoms'] self.rmg.speciesConstraints[ 'maximumSulfurAtoms'] = form.cleaned_data['maximumSulfurAtoms'] self.rmg.speciesConstraints[ 'maximumHeavyAtoms'] = form.cleaned_data['maximumHeavyAtoms'] self.rmg.speciesConstraints[ 'maximumRadicalElectrons'] = form.cleaned_data[ 'maximumRadicalElectrons'] self.rmg.speciesConstraints['allowSingletO2'] = form.cleaned_data[ 'allowSingletO2'] # Quantum Calculations quantumCalc = form.cleaned_data['quantumCalc'] if quantumCalc == 'on': from rmgpy.qm.main import QMCalculator self.rmg.quantumMechanics = QMCalculator( software=form.cleaned_data['software'].encode(), method=form.cleaned_data['method'].encode(), fileStore=form.cleaned_data['fileStore'].encode(), scratchDirectory=form.cleaned_data['scratchDirectory'].encode( ), onlyCyclics=form.cleaned_data['onlyCyclics'], maxRadicalNumber=form.cleaned_data['maxRadicalNumber'], ) # Save the input.py file self.rmg.saveInput(self.savepath)
def testColliderModel(self): """ Test the solver's ability to simulate a model with collision efficiencies. """ chemFile = os.path.join(os.path.dirname(__file__), 'files', 'collider_model', 'chem.inp') dictionaryFile = os.path.join(os.path.dirname(__file__), 'files', 'collider_model', 'species_dictionary.txt') speciesList, reactionList = loadChemkinFile(chemFile, dictionaryFile) smilesDict = { 'H': '[H]', 'HO2': '[O]O', 'O2': '[O][O]', 'Ar': '[Ar]', 'N2': 'N#N', 'CO2': 'O=C=O', 'CH3': '[CH3]', 'CH4': 'C' } speciesDict = {} for name, smiles in smilesDict.iteritems(): mol = Molecule(SMILES=smiles) for species in speciesList: if species.isIsomorphic(mol): speciesDict[name] = species break T = 1000 # K P = 10 # Pa initialMoleFractions = { speciesDict['O2']: 0.5, speciesDict['H']: 0.5, speciesDict['CO2']: 1.0, speciesDict['Ar']: 4.0 } # Initialize the model rxnSystem = SimpleReactor(T, P, initialMoleFractions=initialMoleFractions, termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 0.1 s rxnSystem.advance(0.1) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y / numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([ 0.6666667, 0, 0, 0, 0.1666667, 0, 0.08333333, 0.08333333, 2.466066000000000E-10, 0, 0, 0, 0, 0 ]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i], expectedMoleFracs[i]) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y / numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([ 0.6666667, 0, 0, 0, 0.1666667, 0, 0.08333332, 0.08333332, 1.233033000000000E-08, 0, 0, 0, 0, 0 ]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i], expectedMoleFracs[i]) # Try a new set of conditions T = 850 # K P = 200 # Pa initialMoleFractions = { speciesDict['O2']: 0.5, speciesDict['H']: 1, speciesDict['CO2']: 1, speciesDict['N2']: 4, speciesDict['CH3']: 1 } # Initialize the model rxnSystem = SimpleReactor(T, P, initialMoleFractions=initialMoleFractions, termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y / numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([ 0, 0, 0, 0.5487241, 0.137181, 0, 0.1083234, 0.0685777, 1.280687000000000E-05, 0, 0, 0, 0.1083362, 0.02884481 ]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i], expectedMoleFracs[i])
def testSolve(self): """ Test the simple batch reactor with a simple kinetic model. Here we choose a kinetic model consisting of the hydrogen abstraction reaction CH4 + C2H5 <=> CH3 + C2H6. """ CH4 = Species( molecule=[Molecule().fromSMILES("C")], thermo=ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([8.615, 9.687, 10.963, 12.301, 14.841, 16.976, 20.528], "cal/(mol*K)"), H298=(-17.714, "kcal/mol"), S298=(44.472, "cal/(mol*K)"))) CH3 = Species(molecule=[Molecule().fromSMILES("[CH3]")], thermo=ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([ 9.397, 10.123, 10.856, 11.571, 12.899, 14.055, 16.195 ], "cal/(mol*K)"), H298=(9.357, "kcal/mol"), S298=(45.174, "cal/(mol*K)"))) C2H6 = Species(molecule=[Molecule().fromSMILES("CC")], thermo=ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([ 12.684, 15.506, 18.326, 20.971, 25.500, 29.016, 34.595 ], "cal/(mol*K)"), H298=(-19.521, "kcal/mol"), S298=(54.799, "cal/(mol*K)"))) C2H5 = Species(molecule=[Molecule().fromSMILES("C[CH2]")], thermo=ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([ 11.635, 13.744, 16.085, 18.246, 21.885, 24.676, 29.107 ], "cal/(mol*K)"), H298=(29.496, "kcal/mol"), S298=(56.687, "cal/(mol*K)"))) rxn1 = Reaction(reactants=[C2H6, CH3], products=[C2H5, CH4], kinetics=Arrhenius(A=(686.375 * 6, 'm^3/(mol*s)'), n=4.40721, Ea=(7.82799, 'kcal/mol'), T0=(298.15, 'K'))) coreSpecies = [CH4, CH3, C2H6, C2H5] edgeSpecies = [] coreReactions = [rxn1] edgeReactions = [] T = 1000 P = 1.0e5 rxnSystem = SimpleReactor(T, P, initialMoleFractions={ C2H5: 0.1, CH3: 0.1, CH4: 0.4, C2H6: 0.4 }, termination=[]) 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) # 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.P.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]) self.assertAlmostEqual(reactionRates[i, 0], speciesRates[i, 3], delta=1e-6 * reactionRates[i, 0]) # Check that we've reached equilibrium self.assertAlmostEqual(reactionRates[-1, 0], 0.0, delta=1e-2) ####### # Unit test for the jacobian function: # Solve a reaction system and check if the analytical jacobian matches the finite difference jacobian H2 = Species(molecule=[Molecule().fromSMILES("[H][H]")], thermo=ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([6.89, 6.97, 6.99, 7.01, 7.08, 7.22, 7.72], "cal/(mol*K)"), H298=(0, "kcal/mol"), S298=(31.23, "cal/(mol*K)"))) rxnList = [] rxnList.append( Reaction(reactants=[C2H6], products=[CH3, CH3], kinetics=Arrhenius(A=(686.375 * 6, '1/s'), n=4.40721, Ea=(7.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[CH3, CH3], products=[C2H6], kinetics=Arrhenius(A=(686.375 * 6, 'm^3/(mol*s)'), n=4.40721, Ea=(7.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[C2H6, CH3], products=[C2H5, 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=[C2H5, CH4], products=[C2H6, CH3], 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=[C2H5, CH4], products=[CH3, CH3, CH3], kinetics=Arrhenius(A=(246.375 * 6, 'm^3/(mol*s)'), n=1.40721, Ea=(3.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[CH3, CH3, CH3], products=[C2H5, CH4], kinetics=Arrhenius(A=(246.375 * 6, 'm^6/(mol^2*s)'), n=1.40721, Ea=(3.82799, 'kcal/mol'), T0=(298.15, 'K')))) # rxnList.append( Reaction(reactants=[C2H6, CH3, CH3], products=[C2H5, C2H5, H2], kinetics=Arrhenius(A=(146.375 * 6, 'm^6/(mol^2*s)'), n=2.40721, Ea=(8.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[C2H5, C2H5, H2], products=[C2H6, CH3, CH3], kinetics=Arrhenius(A=(146.375 * 6, 'm^6/(mol^2*s)'), n=2.40721, Ea=(8.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[C2H6, C2H6], products=[CH3, CH4, C2H5], kinetics=Arrhenius(A=(1246.375 * 6, 'm^3/(mol*s)'), n=0.40721, Ea=(8.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[CH3, CH4, C2H5], products=[C2H6, C2H6], kinetics=Arrhenius(A=(46.375 * 6, 'm^6/(mol^2*s)'), n=0.10721, Ea=(8.82799, 'kcal/mol'), T0=(298.15, 'K')))) for rxn in rxnList: coreSpecies = [CH4, CH3, C2H6, C2H5, H2] edgeSpecies = [] coreReactions = [rxn] rxnSystem0 = SimpleReactor(T, P, initialMoleFractions={ CH4: 0.2, CH3: 0.1, C2H6: 0.35, C2H5: 0.15, H2: 0.2 }, termination=[]) rxnSystem0.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions) dydt0 = rxnSystem0.residual(0.0, rxnSystem0.y, numpy.zeros(rxnSystem0.y.shape))[0] numCoreSpecies = len(coreSpecies) dN = .000001 * sum(rxnSystem0.y) dN_array = dN * numpy.eye(numCoreSpecies) dydt = [] for i in range(numCoreSpecies): rxnSystem0.y[i] += dN dydt.append( rxnSystem0.residual(0.0, rxnSystem0.y, numpy.zeros(rxnSystem0.y.shape))[0]) rxnSystem0.y[i] -= dN # reset y to original y0 # Let the solver compute the jacobian solverJacobian = rxnSystem0.jacobian(0.0, rxnSystem0.y, dydt0, 0.0) # Compute the jacobian using finite differences jacobian = numpy.zeros((numCoreSpecies, numCoreSpecies)) for i in range(numCoreSpecies): for j in range(numCoreSpecies): jacobian[i, j] = (dydt[j][i] - dydt0[i]) / dN self.assertAlmostEqual(jacobian[i, j], solverJacobian[i, j], delta=abs(1e-4 * jacobian[i, j])) #print 'Solver jacobian' #print solverJacobian #print 'Numerical jacobian' #print jacobian ### # Unit test for the compute rate derivative rxnList = [] rxnList.append( Reaction(reactants=[C2H6], products=[CH3, CH3], kinetics=Arrhenius(A=(686.375e6, '1/s'), n=4.40721, Ea=(7.82799, 'kcal/mol'), T0=(298.15, 'K')))) rxnList.append( Reaction(reactants=[C2H6, CH3], products=[C2H5, 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=[C2H6, CH3, CH3], products=[C2H5, C2H5, 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 = [CH4, CH3, C2H6, C2H5, H2] edgeSpecies = [] coreReactions = rxnList rxnSystem0 = SimpleReactor(T, P, initialMoleFractions={ CH4: 0.2, CH3: 0.1, C2H6: 0.35, C2H5: 0.15, H2: 0.2 }, 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 rxnSystem0.termination.append(TerminationTime((integrationTime, 's'))) rxnSystem0.simulate(coreSpecies, coreReactions, [], [], 0, 1, 0) y0 = rxnSystem0.y dfdk = numpy.zeros((numCoreSpecies, len(rxnList))) # d(dy/dt)/dk for i in range(len(rxnList)): k0 = rxnList[i].getRateCoefficient(T, P) rxnList[i].kinetics.A.value_si = rxnList[i].kinetics.A.value_si * ( 1 + 1e-3) dk = rxnList[i].getRateCoefficient(T, P) - k0 rxnSystem = SimpleReactor(T, P, initialMoleFractions={ CH4: 0.2, CH3: 0.1, C2H6: 0.35, C2H5: 0.15, H2: 0.2 }, 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'))) rxnSystem.simulate(coreSpecies, coreReactions, [], [], 0, 1, 0) rxnList[i].kinetics.A.value_si = rxnList[i].kinetics.A.value_si / ( 1 + 1e-3) # reset A factor for i in range(numCoreSpecies): for j in range(len(rxnList)): self.assertAlmostEqual(dfdk[i, j], solver_dfdk[i, j], delta=abs(1e-3 * dfdk[i, j]))
def testSolve(self): """ Test the simple batch reactor with a simple kinetic model. Here we choose a kinetic model consisting of the hydrogen abstraction reaction CH4 + C2H5 <=> CH3 + C2H6. """ CH4 = Species( molecule=[Molecule().fromSMILES("C")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 8.615, 9.687,10.963,12.301,14.841,16.976,20.528],"cal/(mol*K)"), H298=(-17.714,"kcal/mol"), S298=(44.472,"cal/(mol*K)")) ) CH3 = Species( molecule=[Molecule().fromSMILES("[CH3]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 9.397,10.123,10.856,11.571,12.899,14.055,16.195],"cal/(mol*K)"), H298=( 9.357,"kcal/mol"), S298=(45.174,"cal/(mol*K)")) ) C2H6 = Species( molecule=[Molecule().fromSMILES("CC")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([12.684,15.506,18.326,20.971,25.500,29.016,34.595],"cal/(mol*K)"), H298=(-19.521,"kcal/mol"), S298=(54.799,"cal/(mol*K)")) ) C2H5 = Species( molecule=[Molecule().fromSMILES("C[CH2]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([11.635,13.744,16.085,18.246,21.885,24.676,29.107],"cal/(mol*K)"), H298=( 29.496,"kcal/mol"), S298=(56.687,"cal/(mol*K)")) ) rxn1 = Reaction(reactants=[C2H6,CH3], products=[C2H5,CH4], kinetics=Arrhenius(A=(686.375*6,'m^3/(mol*s)'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K'))) coreSpecies = [CH4,CH3,C2H6,C2H5] edgeSpecies = [] coreReactions = [rxn1] edgeReactions = [] T = 1000; P = 1.0e5 rxnSystem = SimpleReactor(T, P, initialMoleFractions={C2H5: 0.1, CH3: 0.1, CH4: 0.4, C2H6: 0.4}, termination=[]) 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) # 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.P.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]) self.assertAlmostEqual(reactionRates[i,0], speciesRates[i,3], delta=1e-6*reactionRates[i,0]) # Check that we've reached equilibrium self.assertAlmostEqual(reactionRates[-1,0], 0.0, delta=1e-2) ####### # Unit test for the jacobian function: # Solve a reaction system and check if the analytical jacobian matches the finite difference jacobian H2 = Species( molecule=[Molecule().fromSMILES("[H][H]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([6.89,6.97,6.99,7.01,7.08,7.22,7.72],"cal/(mol*K)"), H298=( 0,"kcal/mol"), S298=(31.23,"cal/(mol*K)")) ) rxnList = [] rxnList.append(Reaction(reactants=[C2H6], products=[CH3,CH3], kinetics=Arrhenius(A=(686.375*6,'1/s'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[CH3,CH3], products=[C2H6], kinetics=Arrhenius(A=(686.375*6,'m^3/(mol*s)'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[C2H6,CH3], products=[C2H5,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=[C2H5,CH4], products=[C2H6,CH3], 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=[C2H5,CH4], products=[CH3,CH3,CH3], kinetics=Arrhenius(A=(246.375*6,'m^3/(mol*s)'), n=1.40721, Ea=(3.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[CH3,CH3,CH3], products=[C2H5,CH4], kinetics=Arrhenius(A=(246.375*6,'m^6/(mol^2*s)'), n=1.40721, Ea=(3.82799,'kcal/mol'), T0=(298.15,'K'))))# rxnList.append(Reaction(reactants=[C2H6,CH3,CH3], products=[C2H5,C2H5,H2], kinetics=Arrhenius(A=(146.375*6,'m^6/(mol^2*s)'), n=2.40721, Ea=(8.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[C2H5,C2H5,H2], products=[C2H6,CH3,CH3], kinetics=Arrhenius(A=(146.375*6,'m^6/(mol^2*s)'), n=2.40721, Ea=(8.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[C2H6,C2H6], products=[CH3,CH4,C2H5], kinetics=Arrhenius(A=(1246.375*6,'m^3/(mol*s)'), n=0.40721, Ea=(8.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[CH3,CH4,C2H5], products=[C2H6,C2H6], kinetics=Arrhenius(A=(46.375*6,'m^6/(mol^2*s)'), n=0.10721, Ea=(8.82799,'kcal/mol'), T0=(298.15,'K')))) for rxn in rxnList: coreSpecies = [CH4,CH3,C2H6,C2H5,H2] edgeSpecies = [] coreReactions = [rxn] rxnSystem0 = SimpleReactor(T,P,initialMoleFractions={CH4:0.2,CH3:0.1,C2H6:0.35,C2H5:0.15, H2:0.2},termination=[]) rxnSystem0.initializeModel(coreSpecies, coreReactions, edgeSpecies, edgeReactions) dydt0 = rxnSystem0.residual(0.0, rxnSystem0.y, numpy.zeros(rxnSystem0.y.shape))[0] numCoreSpecies = len(coreSpecies) dN = .000001*sum(rxnSystem0.y) dN_array = dN*numpy.eye(numCoreSpecies) dydt = [] for i in range(numCoreSpecies): rxnSystem0.y[i] += dN dydt.append(rxnSystem0.residual(0.0, rxnSystem0.y, numpy.zeros(rxnSystem0.y.shape))[0]) rxnSystem0.y[i] -= dN # reset y to original y0 # Let the solver compute the jacobian solverJacobian = rxnSystem0.jacobian(0.0, rxnSystem0.y, dydt0, 0.0) # Compute the jacobian using finite differences jacobian = numpy.zeros((numCoreSpecies, numCoreSpecies)) for i in range(numCoreSpecies): for j in range(numCoreSpecies): jacobian[i,j] = (dydt[j][i]-dydt0[i])/dN self.assertAlmostEqual(jacobian[i,j], solverJacobian[i,j], delta=abs(1e-4*jacobian[i,j])) #print 'Solver jacobian' #print solverJacobian #print 'Numerical jacobian' #print jacobian ### # Unit test for the compute rate derivative rxnList = [] rxnList.append(Reaction(reactants=[C2H6], products=[CH3,CH3], kinetics=Arrhenius(A=(686.375e6,'1/s'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K')))) rxnList.append(Reaction(reactants=[C2H6,CH3], products=[C2H5,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=[C2H6,CH3,CH3], products=[C2H5,C2H5,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 = [CH4,CH3,C2H6,C2H5,H2] edgeSpecies = [] coreReactions = rxnList rxnSystem0 = SimpleReactor(T,P,initialMoleFractions={CH4:0.2,CH3:0.1,C2H6:0.35,C2H5:0.15, H2:0.2},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 rxnSystem0.termination.append(TerminationTime((integrationTime,'s'))) modelSettings = ModelSettings(toleranceKeepInEdge = 0,toleranceMoveToCore=1,toleranceInterruptSimulation=0) simulatorSettings = SimulatorSettings() rxnSystem0.simulate(coreSpecies, coreReactions, [], [], [],[], modelSettings = modelSettings, simulatorSettings=simulatorSettings) y0 = rxnSystem0.y dfdk = numpy.zeros((numCoreSpecies,len(rxnList))) # d(dy/dt)/dk for i in range(len(rxnList)): k0 = rxnList[i].getRateCoefficient(T,P) rxnList[i].kinetics.A.value_si = rxnList[i].kinetics.A.value_si*(1+1e-3) dk = rxnList[i].getRateCoefficient(T,P) - k0 rxnSystem = SimpleReactor(T,P,initialMoleFractions={CH4:0.2,CH3:0.1,C2H6:0.35,C2H5:0.15, H2:0.2},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 range(numCoreSpecies): for j in range(len(rxnList)): self.assertAlmostEqual(dfdk[i,j], solver_dfdk[i,j], delta=abs(1e-3*dfdk[i,j]))
def testSpecificColliderModel(self): """ Test the solver's ability to simulate a model with specific third body species collision efficiencies. """ chemFile = os.path.join(os.path.dirname(__file__),'files','specific_collider_model','chem.inp') dictionaryFile = os.path.join(os.path.dirname(__file__),'files','specific_collider_model','species_dictionary.txt') speciesList, reactionList = loadChemkinFile(chemFile, dictionaryFile) smilesDict = {'Ar':'[Ar]','N2(1)':'N#N','O2':'[O][O]','H':'[H]','CH3':'[CH3]','CH4':'C'} speciesDict = {} for name, smiles in smilesDict.iteritems(): mol = Molecule(SMILES=smiles) for species in speciesList: if species.isIsomorphic(mol): speciesDict[name] = species break T = 1000 # K P = 10 # Pa initialMoleFractions = {speciesDict['Ar']:2.0, speciesDict['N2(1)']:1.0, speciesDict['O2']:0.5, speciesDict['H']:0.1, speciesDict['CH3']:0.1, speciesDict['CH4']:0.001} # Initialize the model rxnSystem = SimpleReactor(T,P,initialMoleFractions=initialMoleFractions,termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 0.1 s rxnSystem.advance(0.1) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y/numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([0.540394532, 0.270197216, 0.135098608, 0.027019722, 0.027019722, 0.000270202]) # order: Ar, N2, O2, H, CH3, CH4 for i in xrange(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i],6) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN expectedMoleFracs = numpy.array([0.540394573, 0.270197287, 0.135098693, 0.027019519, 0.027019519, 0.00027041]) # order: Ar, N2, O2, H, CH3, CH4 for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i],6) # Try a new set of conditions T = 850 # K P = 200 # Pa initialMoleFractions = {speciesDict['Ar']:1.0, speciesDict['N2(1)']:0.5, speciesDict['O2']:0.5, speciesDict['H']:0.001, speciesDict['CH3']:0.01, speciesDict['CH4']:0.5} # Initialize the model rxnSystem = SimpleReactor(T,P,initialMoleFractions=initialMoleFractions,termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y/numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([0.398247713, 0.199123907, 0.199123907, 0.000398169, 0.003982398, 0.199123907]) # order: Ar, N2, O2, H, CH3, CH4 for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i],6)
def testColliderModel(self): """ Test the solver's ability to simulate a model with collision efficiencies. """ chemFile = os.path.join(os.path.dirname(__file__),'files','collider_model','chem.inp') dictionaryFile = os.path.join(os.path.dirname(__file__),'files','collider_model','species_dictionary.txt') speciesList, reactionList = loadChemkinFile(chemFile, dictionaryFile) smilesDict = {'H':'[H]','HO2':'[O]O','O2':'[O][O]','Ar':'[Ar]','N2':'N#N','CO2':'O=C=O','CH3':'[CH3]','CH4':'C'} speciesDict = {} for name, smiles in smilesDict.iteritems(): mol = Molecule(SMILES=smiles) for species in speciesList: if species.isIsomorphic(mol): speciesDict[name] = species break T = 1000 # K P = 10 # Pa initialMoleFractions = {speciesDict['O2']:0.5, speciesDict['H']:0.5, speciesDict['CO2']:1.0, speciesDict['Ar']:4.0} # Initialize the model rxnSystem = SimpleReactor(T,P,initialMoleFractions=initialMoleFractions,termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 0.1 s rxnSystem.advance(0.1) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y/numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([0.6666667,0,0,0,0.1666667,0, 0.08333333,0.08333333,2.466066000000000E-10,0,0,0,0,0]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i]) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN expectedMoleFracs = numpy.array([0.6666667,0,0,0, 0.1666667,0,0.08333332,0.08333332,1.233033000000000E-08,0,0,0,0,0]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i]) # Try a new set of conditions T = 850 # K P = 200 # Pa initialMoleFractions = {speciesDict['O2']:0.5, speciesDict['H']:1, speciesDict['CO2']:1, speciesDict['N2']:4, speciesDict['CH3']:1} # Initialize the model rxnSystem = SimpleReactor(T,P,initialMoleFractions=initialMoleFractions,termination=None) rxnSystem.initializeModel(speciesList, reactionList, [], []) # Advance to time = 5 s rxnSystem.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulatedMoleFracs = rxnSystem.y/numpy.sum(rxnSystem.y) expectedMoleFracs = numpy.array([0,0,0,0.5487241, 0.137181,0, 0.1083234, 0.0685777, 1.280687000000000E-05, 0,0,0, 0.1083362, 0.02884481]) for i in range(len(simulatedMoleFracs)): self.assertAlmostEqual(simulatedMoleFracs[i],expectedMoleFracs[i])
def simpleReactor(temperature, pressure, initialMoleFractions, nSimsTerm=6, terminationConversion=None, terminationTime=None, terminationRateRatio=None, balanceSpecies=None, sensitivity=None, sensitivityThreshold=1e-3, sensitivityTemperature=None, sensitivityPressure=None, sensitivityMoleFractions=None, ): logging.debug('Found SimpleReactor reaction system') for key,value in initialMoleFractions.iteritems(): if not isinstance(value,list): initialMoleFractions[key] = float(value) if value < 0: raise InputError('Initial mole fractions cannot be negative.') else: if len(value) != 2: raise InputError("Initial mole fraction values must either be a number or a list with 2 entries") initialMoleFractions[key] = [float(value[0]),float(value[1])] if value[0] < 0 or value[1] < 0: raise InputError('Initial mole fractions cannot be negative.') elif value[1] < value[0]: raise InputError('Initial mole fraction range out of order: {0}'.format(key)) if not isinstance(temperature,list): T = Quantity(temperature) else: if len(temperature) != 2: raise InputError('Temperature and pressure ranges can either be in the form of (number,units) or a list with 2 entries of the same format') T = [Quantity(t) for t in temperature] if not isinstance(pressure,list): P = Quantity(pressure) else: if len(pressure) != 2: raise InputError('Temperature and pressure ranges can either be in the form of (number,units) or a list with 2 entries of the same format') P = [Quantity(p) for p in pressure] if not isinstance(temperature,list) and not isinstance(pressure,list) and all([not isinstance(x,list) for x in initialMoleFractions.values()]): nSimsTerm=1 termination = [] if terminationConversion is not None: for spec, conv in terminationConversion.iteritems(): termination.append(TerminationConversion(speciesDict[spec], conv)) if terminationTime is not None: termination.append(TerminationTime(Quantity(terminationTime))) if terminationRateRatio is not None: termination.append(TerminationRateRatio(terminationRateRatio)) if len(termination) == 0: raise InputError('No termination conditions specified for reaction system #{0}.'.format(len(rmg.reactionSystems)+2)) sensitiveSpecies = [] if sensitivity: if isinstance(sensitivity, str): sensitivity = [sensitivity] for spec in sensitivity: sensitiveSpecies.append(speciesDict[spec]) if not isinstance(T,list): sensitivityTemperature = T if not isinstance(P,list): sensitivityPressure = P if not any([isinstance(x,list) for x in initialMoleFractions.itervalues()]): sensitivityMoleFractions = deepcopy(initialMoleFractions) if sensitivityMoleFractions is None or sensitivityTemperature is None or sensitivityPressure is None: sensConditions = None else: sensConditions = sensitivityMoleFractions sensConditions['T'] = Quantity(sensitivityTemperature).value_si sensConditions['P'] = Quantity(sensitivityPressure).value_si system = SimpleReactor(T, P, initialMoleFractions, nSimsTerm, termination, sensitiveSpecies, sensitivityThreshold,sensConditions) rmg.reactionSystems.append(system) assert balanceSpecies is None or isinstance(balanceSpecies,str), 'balanceSpecies should be the string corresponding to a single species' rmg.balanceSpecies = balanceSpecies if balanceSpecies: #check that the balanceSpecies can't be taken to zero total = 0.0 for key,item in initialMoleFractions.iteritems(): if key == balanceSpecies: assert not isinstance(item,list), 'balanceSpecies must not have a defined range' xbspcs = item if isinstance(item,list): total += item[1]-item[0] if total > xbspcs: raise ValueError('The sum of the differences in the ranged mole fractions is greater than the mole fraction of the balance species, this would require the balanceSpecies mole fraction to be negative in some cases which is not allowed, either reduce the maximum mole fractions or dont use balanceSpecies')
def saveForm(self, posted, form): """ Save form data into input.py file specified by the path. """ # Clean past history self.rmg = RMG() # Databases #self.rmg.databaseDirectory = settings['database.directory'] self.rmg.thermoLibraries = [] if posted.thermo_libraries.all(): self.rmg.thermoLibraries = [ item.thermolib.encode() for item in posted.thermo_libraries.all() ] self.rmg.reactionLibraries = [] self.rmg.seedMechanisms = [] if posted.reaction_libraries.all(): for item in posted.reaction_libraries.all(): if not item.seedmech and not item.edge: self.rmg.reactionLibraries.append( (item.reactionlib.encode(), False)) elif not item.seedmech: self.rmg.reactionLibraries.append( (item.reactionlib.encode(), True)) else: self.rmg.seedMechanisms.append(item.reactionlib.encode()) self.rmg.statmechLibraries = [] self.rmg.kineticsDepositories = ['training'] self.rmg.kineticsFamilies = ['!Intra_Disproportionation'] self.rmg.kineticsEstimator = 'rate rules' # Species self.rmg.initialSpecies = [] speciesDict = {} initialMoleFractions = {} self.rmg.reactionModel = CoreEdgeReactionModel() for item in posted.reactor_species.all(): structure = Molecule().fromAdjacencyList(item.adjlist.encode()) spec, isNew = self.rmg.reactionModel.makeNewSpecies( structure, label=item.name.encode(), reactive=False if item.inert else True) self.rmg.initialSpecies.append(spec) speciesDict[item.name.encode()] = spec initialMoleFractions[spec] = item.molefrac # Reactor systems self.rmg.reactionSystems = [] for item in posted.reactor_systems.all(): T = Quantity(item.temperature, item.temperature_units.encode()) P = Quantity(item.pressure, item.pressure_units.encode()) termination = [] if item.conversion: termination.append( TerminationConversion(speciesDict[item.species.encode()], item.conversion)) termination.append( TerminationTime( Quantity(item.terminationtime, item.time_units.encode()))) system = SimpleReactor(T, P, initialMoleFractions, termination) self.rmg.reactionSystems.append(system) # Simulator tolerances self.rmg.absoluteTolerance = form.cleaned_data['simulator_atol'] self.rmg.relativeTolerance = form.cleaned_data['simulator_rtol'] self.rmg.fluxToleranceKeepInEdge = form.cleaned_data[ 'toleranceKeepInEdge'] self.rmg.fluxToleranceMoveToCore = form.cleaned_data[ 'toleranceMoveToCore'] self.rmg.fluxToleranceInterrupt = form.cleaned_data[ 'toleranceInterruptSimulation'] self.rmg.maximumEdgeSpecies = form.cleaned_data['maximumEdgeSpecies'] # Pressure Dependence pdep = form.cleaned_data['pdep'].encode() if pdep != 'off': self.rmg.pressureDependence = MEASURE() self.rmg.pressureDependence.method = pdep # Temperature and pressure range interpolation = (form.cleaned_data['interpolation'].encode(), form.cleaned_data['temp_basis'], form.cleaned_data['p_basis']) self.rmg.pressureDependence.Tmin = Quantity( form.cleaned_data['temp_low'], form.cleaned_data['temprange_units'].encode()) self.rmg.pressureDependence.Tmax = Quantity( form.cleaned_data['temp_high'], form.cleaned_data['temprange_units'].encode()) self.rmg.pressureDependence.Tcount = form.cleaned_data[ 'temp_interp'] Tlist = getTemperaturesForModel( interpolation, self.rmg.pressureDependence.Tmin.value, self.rmg.pressureDependence.Tmax.value, self.rmg.pressureDependence.Tcount) self.rmg.pressureDependence.Tlist = Quantity(Tlist, "K") self.rmg.pressureDependence.Pmin = Quantity( form.cleaned_data['p_low'], form.cleaned_data['prange_units'].encode()) self.rmg.pressureDependence.Pmax = Quantity( form.cleaned_data['p_high'], form.cleaned_data['prange_units'].encode()) self.rmg.pressureDependence.Pcount = form.cleaned_data['p_interp'] Plist = getPressuresForModel( interpolation, self.rmg.pressureDependence.Pmin.value, self.rmg.pressureDependence.Pmax.value, self.rmg.pressureDependence.Pcount) self.rmg.pressureDependence.Plist = Quantity(Plist, "Pa") # Process grain size and count self.rmg.pressureDependence.grainSize = Quantity( form.cleaned_data['maximumGrainSize'], form.cleaned_data['grainsize_units'].encode()) self.rmg.pressureDependence.grainCount = form.cleaned_data[ 'minimumNumberOfGrains'] # Process interpolation model self.rmg.pressureDependence.model = interpolation # Additional Options self.rmg.units = 'si' self.rmg.saveRestartPeriod = Quantity( form.cleaned_data['saveRestartPeriod'], form.cleaned_data['saveRestartPeriodUnits'].encode( )) if form.cleaned_data['saveRestartPeriod'] else None self.rmg.drawMolecules = form.cleaned_data['drawMolecules'] self.rmg.generatePlots = form.cleaned_data['generatePlots'] self.rmg.saveConcentrationProfiles = form.cleaned_data[ 'saveConcentrationProfiles'] # Save the input.py file self.rmg.saveInput(self.savepath)
def test_specific_collider_model(self): """ Test the solver's ability to simulate a model with specific third body species collision efficiencies. """ chem_file = os.path.join(os.path.dirname(__file__), 'files', 'specific_collider_model', 'chem.inp') dictionary_file = os.path.join(os.path.dirname(__file__), 'files', 'specific_collider_model', 'species_dictionary.txt') species_list, reaction_list = load_chemkin_file(chem_file, dictionary_file) # Note that H2O is in the corresponding Chemkin file, but intentionally not defined here to check the solver. smiles_dict = {'Ar': '[Ar]', 'N2(1)': 'N#N', 'O2': '[O][O]', 'H': '[H]', 'CH3': '[CH3]', 'CH4': 'C'} species_dict = {} for name, smiles in smiles_dict.items(): mol = Molecule(smiles=smiles) for species in species_list: if species.is_isomorphic(mol): species_dict[name] = species break T = 1000 # K P = 10 # Pa initial_mole_fractions = {species_dict['Ar']: 2.0, species_dict['N2(1)']: 1.0, species_dict['O2']: 0.5, species_dict['H']: 0.1, species_dict['CH3']: 0.1, species_dict['CH4']: 0.001} # Initialize the model rxn_system = SimpleReactor(T, P, initial_mole_fractions=initial_mole_fractions, n_sims=1, termination=None) rxn_system.initialize_model(species_list, reaction_list, [], []) # Advance to time = 0.1 s rxn_system.advance(0.1) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y) expected_mole_fracs = np.array([0.540394532, 0.270197216, 0.135098608, 0.027019722, 0.027019722, 0.000270202, 0.0]) # order: Ar, N2, O2, H, CH3, CH4 for i in range(len(simulated_mole_fracs)): self.assertAlmostEqual(simulated_mole_fracs[i], expected_mole_fracs[i], 6) # Advance to time = 5 s rxn_system.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN expected_mole_fracs = np.array([0.540394573, 0.270197287, 0.135098693, 0.027019519, 0.027019519, 0.00027041, 0.0]) # order: Ar, N2, O2, H, CH3, CH4 for i in range(len(simulated_mole_fracs)): self.assertAlmostEqual(simulated_mole_fracs[i], expected_mole_fracs[i], 6) # Try a new set of conditions T = 850 # K P = 200 # Pa initial_mole_fractions = {species_dict['Ar']: 1.0, species_dict['N2(1)']: 0.5, species_dict['O2']: 0.5, species_dict['H']: 0.001, species_dict['CH3']: 0.01, species_dict['CH4']: 0.5} # Initialize the model rxn_system = SimpleReactor(T, P, initial_mole_fractions=initial_mole_fractions, n_sims=1, termination=None) rxn_system.initialize_model(species_list, reaction_list, [], []) # Advance to time = 5 s rxn_system.advance(5) # Compare simulated mole fractions with expected mole fractions from CHEMKIN simulated_mole_fracs = rxn_system.y / np.sum(rxn_system.y) expected_mole_fracs = np.array([0.398247713, 0.199123907, 0.199123907, 0.000398169, 0.003982398, 0.199123907, 0.0]) # order: Ar, N2, O2, H, CH3, CH4 for i in range(len(simulated_mole_fracs)): self.assertAlmostEqual(simulated_mole_fracs[i], expected_mole_fracs[i], 6)
def testSolve(self): """ Test the simple batch reactor with a simple kinetic model. Here we choose a kinetic model consisting of the hydrogen abstraction reaction CH4 + C2H5 <=> CH3 + C2H6. """ CH4 = Species( molecule=[Molecule().fromSMILES("C")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 8.615, 9.687,10.963,12.301,14.841,16.976,20.528],"cal/(mol*K)"), H298=(-17.714,"kcal/mol"), S298=(44.472,"cal/(mol*K)")) ) CH3 = Species( molecule=[Molecule().fromSMILES("[CH3]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 9.397,10.123,10.856,11.571,12.899,14.055,16.195],"cal/(mol*K)"), H298=( 9.357,"kcal/mol"), S298=(45.174,"cal/(mol*K)")) ) C2H6 = Species( molecule=[Molecule().fromSMILES("CC")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([12.684,15.506,18.326,20.971,25.500,29.016,34.595],"cal/(mol*K)"), H298=(-19.521,"kcal/mol"), S298=(54.799,"cal/(mol*K)")) ) C2H5 = Species( molecule=[Molecule().fromSMILES("C[CH2]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([11.635,13.744,16.085,18.246,21.885,24.676,29.107],"cal/(mol*K)"), H298=( 29.496,"kcal/mol"), S298=(56.687,"cal/(mol*K)")) ) rxn1 = Reaction(reactants=[C2H6,CH3], products=[C2H5,CH4], kinetics=Arrhenius(A=(686.375*6,'m^3/(mol*s)'), n=4.40721, Ea=(7.82799,'kcal/mol'), T0=(298.15,'K'))) coreSpecies = [CH4,CH3,C2H6,C2H5] edgeSpecies = [] coreReactions = [rxn1] edgeReactions = [] T = 1000; P = 1.0e5 rxnSystem = SimpleReactor(T, P, initialMoleFractions={C2H5: 0.1, CH3: 0.1, CH4: 0.4, C2H6: 0.4}, termination=[]) 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) # 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) # 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]) self.assertAlmostEqual(reactionRates[i,0], speciesRates[i,3], delta=1e-6*reactionRates[i,0]) # Check that we've reached equilibrium self.assertAlmostEqual(reactionRates[-1,0], 0.0, delta=1e-2)
def testSolve(self): """ Test the simple batch reactor with a simple kinetic model. Here we choose a kinetic model consisting of the hydrogen abstraction reaction CH4 + C2H5 <=> CH3 + C2H6. """ CH4 = Species( molecule=[Molecule().fromSMILES("C")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 8.615, 9.687,10.963,12.301,14.841,16.976,20.528],"cal/mol*K"), H298=(-17.714,"kcal/mol"), S298=(44.472,"cal/mol*K")) ) CH3 = Species( molecule=[Molecule().fromSMILES("[CH3]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([ 9.397,10.123,10.856,11.571,12.899,14.055,16.195],"cal/mol*K"), H298=( 9.357,"kcal/mol"), S298=(45.174,"cal/mol*K")) ) C2H6 = Species( molecule=[Molecule().fromSMILES("CC")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([12.684,15.506,18.326,20.971,25.500,29.016,34.595],"cal/mol*K"), H298=(-19.521,"kcal/mol"), S298=(54.799,"cal/mol*K")) ) C2H5 = Species( molecule=[Molecule().fromSMILES("C[CH2]")], thermo=ThermoData(Tdata=([300,400,500,600,800,1000,1500],"K"), Cpdata=([11.635,13.744,16.085,18.246,21.885,24.676,29.107],"cal/mol*K"), H298=( 29.496,"kcal/mol"), S298=(56.687,"cal/mol*K")) ) rxn1 = Reaction(reactants=[C2H6,CH3], products=[C2H5,CH4], kinetics=Arrhenius(A=686.375*6, n=4.40721, Ea=7.82799*4184., T0=298.15)) coreSpecies = [CH4,CH3,C2H6,C2H5] edgeSpecies = [] coreReactions = [rxn1] edgeReactions = [] T = 1000; P = 1.0e5 rxnSystem = SimpleReactor(T, P, initialMoleFractions={C2H5: 0.1, CH3: 0.1, CH4: 0.4, C2H6: 0.4}) 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) # 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) import pylab fig = pylab.figure(figsize=(6,6)) pylab.subplot(2,1,1) pylab.semilogx(t, y) pylab.ylabel('Concentration (mol/m$^\\mathdefault{3}$)') pylab.legend(['CH4', 'CH3', 'C2H6', 'C2H5'], loc=4) pylab.subplot(2,1,2) pylab.semilogx(t, speciesRates) pylab.legend(['CH4', 'CH3', 'C2H6', 'C2H5'], loc=4) pylab.xlabel('Time (s)') pylab.ylabel('Rate (mol/m$^\\mathdefault{3}$*s)') fig.subplots_adjust(left=0.12, bottom=0.10, right=0.95, top=0.95, wspace=0.20, hspace=0.35) pylab.show()