def __init__(self, reactorType, reactionTime, molFrac, T0=None, P0=None, V0=None): self.reactorType=reactorType self.reactionTime=Quantity(reactionTime) # Normalize initialMolFrac if not already done: if sum(molFrac.values())!=1.00: total=sum(molFrac.values()) for species, value in molFrac.iteritems(): molFrac[species]= value / total self.molFrac=molFrac # Check to see that one of the three attributes T0, P0, and V0 is less unspecified props=[T0,P0,V0] total=0 for prop in props: if prop is None: total+=1 if not total==1: raise Exception("Cantera conditions must leave one of T0, P0, and V0 state variables unspecified") self.T0=Quantity(T0) if T0 else None self.P0=Quantity(P0) if P0 else None self.V0=Quantity(V0) if V0 else None
def options(units='si', saveRestartPeriod=None, generateOutputHTML=False, generatePlots=False, saveSimulationProfiles=False, verboseComments=False, saveEdgeSpecies=False): rmg.units = units rmg.saveRestartPeriod = Quantity( saveRestartPeriod) if saveRestartPeriod else None rmg.generateOutputHTML = generateOutputHTML rmg.generatePlots = generatePlots rmg.saveSimulationProfiles = saveSimulationProfiles rmg.verboseComments = verboseComments rmg.saveEdgeSpecies = saveEdgeSpecies
def simpleReactor(temperature, pressure, initialMoleFractions, terminationConversion=None, terminationTime=None, sensitivity=None, sensitivityThreshold=1e-3): logging.debug('Found SimpleReactor reaction system') 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)) sensitivitySpecies = [] if sensitivity: for spec in sensitivity: sensitivitySpecies.append(speciesDict[spec]) system = SimpleReactor(T, P, initialMoleFractions, termination, sensitivitySpecies, sensitivityThreshold) rmg.reactionSystems.append(system)
def model(toleranceMoveToCore=None, toleranceMoveEdgeReactionToCore=numpy.inf,toleranceKeepInEdge=0.0, toleranceInterruptSimulation=1.0, toleranceMoveEdgeReactionToSurface=numpy.inf, toleranceMoveSurfaceSpeciesToCore=numpy.inf, toleranceMoveSurfaceReactionToCore=numpy.inf, toleranceMoveEdgeReactionToSurfaceInterrupt=None, toleranceMoveEdgeReactionToCoreInterrupt=None, maximumEdgeSpecies=1000000, minCoreSizeForPrune=50, minSpeciesExistIterationsForPrune=2, filterReactions=False, filterThreshold=1e8, ignoreOverallFluxCriterion=False, maxNumSpecies=None,maxNumObjsPerIter=1,terminateAtMaxObjects=False,toleranceThermoKeepSpeciesInEdge=numpy.inf,dynamicsTimeScale=(0.0,'sec'), toleranceBranchReactionToCore=0.0, branchingIndex=0.5, branchingRatioMax=1.0): """ How to generate the model. `toleranceMoveToCore` must be specified. toleranceMoveReactionToCore and toleranceReactionInterruptSimulation refers to an additional criterion for forcing an edge reaction to be included in the core by default this criterion is turned off Other parameters are optional and control the pruning. ignoreOverallFluxCriterion=True will cause the toleranceMoveToCore to be only applied to the pressure dependent network expansion and not movement of species from edge to core """ if toleranceMoveToCore is None: raise InputError("You must provide a toleranceMoveToCore value. It should be less than or equal to toleranceInterruptSimulation which is currently {0}".format(toleranceInterruptSimulation)) if toleranceMoveToCore > toleranceInterruptSimulation: raise InputError("toleranceMoveToCore must be less than or equal to toleranceInterruptSimulation, which is currently {0}".format(toleranceInterruptSimulation)) rmg.modelSettingsList.append( ModelSettings( toleranceMoveToCore=toleranceMoveToCore, toleranceMoveEdgeReactionToCore=toleranceMoveEdgeReactionToCore, toleranceKeepInEdge=toleranceKeepInEdge, toleranceInterruptSimulation=toleranceInterruptSimulation, toleranceMoveEdgeReactionToSurface=toleranceMoveEdgeReactionToSurface, toleranceMoveSurfaceSpeciesToCore=toleranceMoveSurfaceSpeciesToCore, toleranceMoveSurfaceReactionToCore=toleranceMoveSurfaceReactionToCore, toleranceMoveEdgeReactionToSurfaceInterrupt=toleranceMoveEdgeReactionToSurfaceInterrupt, toleranceMoveEdgeReactionToCoreInterrupt=toleranceMoveEdgeReactionToCoreInterrupt, maximumEdgeSpecies=maximumEdgeSpecies, minCoreSizeForPrune=minCoreSizeForPrune, minSpeciesExistIterationsForPrune=minSpeciesExistIterationsForPrune, filterReactions=filterReactions, filterThreshold=filterThreshold, ignoreOverallFluxCriterion=ignoreOverallFluxCriterion, maxNumSpecies=maxNumSpecies, maxNumObjsPerIter=maxNumObjsPerIter, terminateAtMaxObjects=terminateAtMaxObjects, toleranceThermoKeepSpeciesInEdge=toleranceThermoKeepSpeciesInEdge, dynamicsTimeScale=Quantity(dynamicsTimeScale), toleranceBranchReactionToCore=toleranceBranchReactionToCore, branchingIndex=branchingIndex, branchingRatioMax=branchingRatioMax, ) )
def getRateCoefficientUnits(kinetics, user=None): """ For a given `kinetics` model, return the desired rate coefficient units at high and low pressures, the conversion factor from SI to those units (high pressure), and the number of reactant species. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ # Get units from based on the kinetics type if isinstance(kinetics, (Arrhenius, ArrheniusEP, ArrheniusBM, SurfaceArrhenius, SurfaceArrheniusBEP, StickingCoefficient, StickingCoefficientBEP)): units = kinetics.A.units elif isinstance(kinetics, KineticsData): units = kinetics.kdata.units elif isinstance(kinetics, (PDepArrhenius, MultiArrhenius, MultiPDepArrhenius)): return getRateCoefficientUnits(kinetics.arrhenius[0]) elif isinstance(kinetics, Chebyshev): units = kinetics.kunits elif isinstance(kinetics, Troe): units = kinetics.arrheniusHigh.A.units elif isinstance(kinetics, Lindemann): units = kinetics.arrheniusHigh.A.units elif isinstance(kinetics, ThirdBody): units = kinetics.arrheniusLow.A.units else: raise NotImplementedError('Cannot get units for {0} class.'.format(kinetics.__class__.__name__)) if user and user.is_authenticated: # If user is logged in, get their desired units user_profile = UserProfile.objects.get(user=user) desired_units = user_profile.rate_coefficient_units else: # Default base units desired_units = 'm^3,mol,s' if units == '': # Dimensionless return '', '', 1 else: # Reconstruct the rate units using the desired base units kunits = reconstruct_rate_units(units, desired_units) kunits_low = reconstruct_rate_units(units, desired_units, add_conc_dim=True) kfactor = Quantity(1, kunits).get_conversion_factor_from_si() return kunits, kunits_low, kfactor
def options(name='Seed', generateSeedEachIteration=False, saveSeedToDatabase=False, units='si', saveRestartPeriod=None, generateOutputHTML=False, generatePlots=False, saveSimulationProfiles=False, verboseComments=False, saveEdgeSpecies=False, keepIrreversible=False, wallTime='00:00:00:00'): rmg.name = name rmg.generateSeedEachIteration=generateSeedEachIteration rmg.saveSeedToDatabase=saveSeedToDatabase rmg.units = units rmg.saveRestartPeriod = Quantity(saveRestartPeriod) if saveRestartPeriod else None if generateOutputHTML: logging.warning('Generate Output HTML option was turned on. Note that this will slow down model generation.') rmg.generateOutputHTML = generateOutputHTML rmg.generatePlots = generatePlots rmg.saveSimulationProfiles = saveSimulationProfiles rmg.verboseComments = verboseComments if saveEdgeSpecies: logging.warning('Edge species saving was turned on. This will slow down model generation for large simulations.') rmg.saveEdgeSpecies = saveEdgeSpecies rmg.keepIrreversible = keepIrreversible rmg.wallTime = wallTime
def runIgnitionThermoSensitivity(runChemkinJob, inputFile, dictionaryFile): """ Supply a runChemkinJob python function which returns the ignition delay with a chemkin file input. This will run finite difference sensitivities to enthalpies and save them to a csv file. """ from rmgpy.chemkin import loadChemkinFile, saveChemkinFile, getSpeciesIdentifier from rmgpy.quantity import Quantity speciesList, reactionList = loadChemkinFile(inputFile, dictionaryPath = dictionaryFile, readComments = False) num_species = len(speciesList) deltaH = Quantity(0.5, 'kcal/mol').value_si worksheet = csv.writer(file('ignition_thermo_sensitivity.csv', 'w')) worksheet.writerow(['Species', 'd[del H] (kcal/mol)', 'tau_high', 'tau_low', 'd[ln tau]/d[del H]']) logging.info('Running thermo sensitivity analysis using finite differences...') for index, species in enumerate(speciesList): species_index = index + 1 species_string = getSpeciesIdentifier(species) logging.info('At species {0} of {1}. {2}'.format(species_index, num_species, species_string)) species.thermo.changeBaseEnthalpy(deltaH) saveChemkinFile('chem_temp.inp', speciesList, reactionList, verbose = False) tau_high = runChemkinJob('chem_temp.inp') species.thermo.changeBaseEnthalpy(-deltaH) # reset the thermo species.thermo.changeBaseEnthalpy(-deltaH) saveChemkinFile('chem_temp.inp', speciesList, reactionList, verbose = False) tau_low = runChemkinJob('chem_temp.inp') species.thermo.changeBaseEnthalpy(deltaH) # reset the kinetics if tau_high != 0 and tau_low != 0: sens = numpy.log(tau_high / tau_low) / (2 * deltaH) else: sens = 0 worksheet.writerow([species_string, '1', tau_high, tau_low, sens])
def explorer(source, explore_tol=(0.01,'s^-1'), energy_tol=np.inf, flux_tol=0.0, bathGas=None, maximumRadicalElectrons=np.inf): global jobList,speciesDict for job in jobList: if isinstance(job, PressureDependenceJob): pdepjob = job break else: raise InputError('the explorer block must occur after the pressureDependence block') source = [speciesDict[name] for name in source] explore_tol = Quantity(explore_tol) if bathGas: bathGas0 = bathGas or {}; bathGas = {} for spec, fraction in bathGas0.items(): bathGas[speciesDict[spec]] = fraction job = ExplorerJob(source=source,pdepjob=pdepjob,explore_tol=explore_tol.value_si, energy_tol=energy_tol,flux_tol=flux_tol,bathGas=bathGas, maximumRadicalElectrons=maximumRadicalElectrons) jobList.append(job)
def __init__(self, reactor_type, reaction_time, mol_frac, T0=None, P0=None, V0=None): self.reactor_type = reactor_type self.reaction_time = Quantity(reaction_time) # Normalize initialMolFrac if not already done: if sum(mol_frac.values()) != 1.00: total = sum(mol_frac.values()) for species, value in mol_frac.items(): mol_frac[species] = value / total self.mol_frac = mol_frac # Check to see that one of the three attributes T0, P0, and V0 is less unspecified props = [T0, P0, V0] total = 0 for prop in props: if prop is None: total += 1 if not total == 1: raise Exception("Cantera conditions must leave one of T0, P0, and V0 state variables unspecified") self.T0 = Quantity(T0) if T0 else None self.P0 = Quantity(P0) if P0 else None self.V0 = Quantity(V0) if V0 else None
class CanteraCondition: """ This class organizes the inputs needed for a cantera simulation ======================= ==================================================== Attribute Description ======================= ==================================================== `reactorType` A string of the cantera reactor type. List of supported types below: IdealGasReactor: A constant volume, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureReactor: A homogeneous, constant pressure, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureTemperatureReactor: A homogenous, constant pressure and constant temperature, zero-dimensional reactor for ideal gas mixtures (the same as RMG's SimpleReactor) `reactionTime` A tuple object giving the (reaction time, units) `molFrac` A dictionary giving the initial mol Fractions. Keys are species objects and the values are floats To specify the system for an ideal gas, you must define 2 of the following 3 parameters: `T0` A tuple giving the (initial temperature, units) which reconstructs a Quantity object 'P0' A tuple giving the (initial pressure, units) which reconstructs a Quantity object 'V0' A tuple giving the (initial specific volume, units) which reconstructs a Quantity object ======================= ==================================================== """ def __init__(self, reactorType, reactionTime, molFrac, T0=None, P0=None, V0=None): self.reactorType=reactorType self.reactionTime=Quantity(reactionTime) # Normalize initialMolFrac if not already done: if sum(molFrac.values())!=1.00: total=sum(molFrac.values()) for species, value in molFrac.iteritems(): molFrac[species]= value / total self.molFrac=molFrac # Check to see that one of the three attributes T0, P0, and V0 is less unspecified props=[T0,P0,V0] total=0 for prop in props: if prop is None: total+=1 if not total==1: raise Exception("Cantera conditions must leave one of T0, P0, and V0 state variables unspecified") self.T0=Quantity(T0) if T0 else None self.P0=Quantity(P0) if P0 else None self.V0=Quantity(V0) if V0 else None def __repr__(self): """ Return a string representation that can be used to reconstruct the object. """ string="CanteraCondition(" string += 'reactorType="{0}", '.format(self.reactorType) string += 'reactionTime={}, '.format(self.reactionTime.__repr__()) string += 'molFrac={0}, '.format(self.molFrac.__repr__()) if self.T0: string += 'T0={}, '.format(self.T0.__repr__()) if self.P0: string += 'P0={}, '.format(self.P0.__repr__()) if self.V0: string += 'V0={}, '.format(self.V0__repr__()) string = string[:-2] + ')' return string def __str__(self): """ Return a string representation of the condition. """ string="" string += 'Reactor Type: {0}\n'.format(self.reactorType) string += 'Reaction Time: {}\n'.format(self.reactionTime) if self.T0: string += 'T0: {}\n'.format(self.T0) if self.P0: string += 'P0: {}\n'.format(self.P0) if self.V0: string += 'V0: {}\n'.format(self.V0) #ConvertMolFrac to SMILES for keys for display prettyMolFrac={} for key, value in self.molFrac.iteritems(): prettyMolFrac[key.molecule[0].toSMILES()]=value string += 'Initial Mole Fractions: {0}'.format(prettyMolFrac.__repr__()) return string
def loadChemkinOutput(outputFile, reactionModel): """ Load the species concentrations from a Chemkin Output file in a simulation and generate the reaction rates at each time point. """ import rmgpy.constants as constants from rmgpy.quantity import Quantity coreReactions = reactionModel.core.reactions edgeReactions = reactionModel.edge.reactions speciesList = reactionModel.core.species time = [] coreSpeciesConcentrations = [] coreReactionRates = [] edgeReactionRates = [] with open(outputFile, 'r') as f: line = f.readline() while line != '' and 'SPECIFIED END' not in line: line.strip() tokens = line.split() if ' TIME ' in line: # Time is in seconds time.append(float(tokens[-2])) elif ' PRESSURE ' in line: # Pressure from Chemkin is in atm P = Quantity(float(tokens[-2]), 'atm') elif ' TEMPERATURE ' in line: # Temperature from Chemkin in in K T = Quantity(float(tokens[-2]), 'K') elif ' MOLE FRACTIONS ' in line: # Species always come in the same order as listed in chem.inp molefractions = [] line = f.readline( ) # This one reads the blank line which follows line = f.readline() while line.strip() != '': tokens = line.split() for value in tokens[2::3]: # Make all concentrations positive if value.find('-') == 0: value = value.replace('-', '', 1) # Sometimes chemkin removes the `E` in scientific notation due to lack of space, # rendering invalid float values. If this is the case, add it in. if value.find('-') != -1: if value.find('E') == -1: value = value.replace('-', 'E-') molefractions.append(float(value)) line = f.readline() totalConcentration = P.value_si / constants.R / T.value_si coreSpeciesConcentrations.append([ molefrac * totalConcentration for molefrac in molefractions ]) coreRates = [] edgeRates = [] for reaction in coreReactions: rate = reaction.getRateCoefficient(T.value_si, P.value_si) for reactant in reaction.reactants: rate *= molefractions[speciesList.index( reactant)] * totalConcentration coreRates.append(rate) for reaction in edgeReactions: edgeRates.append( reaction.getRateCoefficient(T.value_si, P.value_si)) if coreRates: coreReactionRates.append(coreRates) if edgeRates: edgeReactionRates.append(edgeRates) line = f.readline() time = numpy.array(time) coreSpeciesConcentrations = numpy.array(coreSpeciesConcentrations) coreReactionRates = numpy.array(coreReactionRates) edgeReactionRates = numpy.array(edgeReactionRates) return time, coreSpeciesConcentrations, coreReactionRates, edgeReactionRates
def sensitivity_analysis(self, initial_mole_fractions, sensitive_species, T, P, termination_time, sensitivity_threshold=1e-3, number=10, fileformat='.png'): """ Run sensitivity analysis using the RMG solver in a single ReactionSystem object initial_mole_fractions is a dictionary with Species objects as keys and mole fraction initial conditions sensitive_species is a list of sensitive Species objects number is the number of top species thermo or reaction kinetics desired to be plotted """ from rmgpy.solver import SimpleReactor, TerminationTime from rmgpy.quantity import Quantity from rmgpy.rmg.listener import SimulationProfileWriter, SimulationProfilePlotter from rmgpy.rmg.settings import ModelSettings, SimulatorSettings T = Quantity(T) P = Quantity(P) termination = [TerminationTime(Quantity(termination_time))] reaction_system = SimpleReactor( T=T, P=P, initial_mole_fractions=initial_mole_fractions, termination=termination, sensitive_species=sensitive_species, sensitivity_threshold=sensitivity_threshold) # Create the csv worksheets for logging sensitivity util.make_output_subdirectory(self.output_directory, 'solver') sens_worksheet = [] reaction_system_index = 0 for spec in reaction_system.sensitive_species: csvfile_path = os.path.join( self.output_directory, 'solver', 'sensitivity_{0}_SPC_{1}.csv'.format(reaction_system_index + 1, spec.index)) sens_worksheet.append(csvfile_path) reaction_system.attach( SimulationProfileWriter(self.output_directory, reaction_system_index, self.species_list)) reaction_system.attach( SimulationProfilePlotter(self.output_directory, reaction_system_index, self.species_list)) simulator_settings = SimulatorSettings() # defaults model_settings = ModelSettings() # defaults model_settings.tol_move_to_core = 0.1 model_settings.tol_interrupt_simulation = 1.0 model_settings.tol_keep_in_edge = 0.0 reaction_system.simulate( core_species=self.species_list, core_reactions=self.reaction_list, edge_species=[], edge_reactions=[], surface_species=[], surface_reactions=[], model_settings=model_settings, simulator_settings=simulator_settings, sensitivity=True, sens_worksheet=sens_worksheet, ) plot_sensitivity(self.output_directory, reaction_system_index, reaction_system.sensitive_species, number=number, fileformat=fileformat)
def processOldLibraryEntry(self, data): """ Process a list of parameters `data` as read from an old-style RMG thermo database, returning the corresponding kinetics object. """ # This is hardcoding of reaction families! label = os.path.split(self.label)[-2] if label in BIMOLECULAR_KINETICS_FAMILIES: Aunits = 'cm^3/(mol*s)' elif label in UNIMOLECULAR_KINETICS_FAMILIES: Aunits = 's^-1' else: raise Exception( 'Unable to determine preexponential units for old reaction family "{0}".' .format(self.label)) try: Tmin, Tmax = data[0].split('-') Tmin = (float(Tmin), "K") Tmax = (float(Tmax), "K") except ValueError: Tmin = (float(data[0]), "K") Tmax = None A, n, alpha, E0, dA, dn, dalpha, dE0 = data[1:9] A = float(A) if dA[0] == '*': A = Quantity(A, Aunits, '*|/', float(dA[1:])) else: dA = float(dA) if dA != 0: A = Quantity(A, Aunits, '+|-', dA) else: A = Quantity(A, Aunits) n = float(n) dn = float(dn) if dn != 0: n = Quantity(n, '', '+|-', dn) else: n = Quantity(n, '') alpha = float(alpha) dalpha = float(dalpha) if dalpha != 0: alpha = Quantity(alpha, '', '+|-', dalpha) else: alpha = Quantity(alpha, '') E0 = float(E0) dE0 = float(dE0) if dE0 != 0: E0 = Quantity(E0, 'kcal/mol', '+|-', dE0) else: E0 = Quantity(E0, 'kcal/mol') rank = int(data[9]) return ArrheniusEP(A=A, n=n, alpha=alpha, E0=E0, Tmin=Tmin, Tmax=Tmax), rank
def __init__(self,toleranceMoveToCore=None, toleranceMoveEdgeReactionToCore=numpy.inf,toleranceKeepInEdge=0.0, toleranceInterruptSimulation=1.0, toleranceMoveEdgeReactionToSurface=numpy.inf, toleranceMoveSurfaceSpeciesToCore=numpy.inf, toleranceMoveSurfaceReactionToCore=numpy.inf, toleranceMoveEdgeReactionToSurfaceInterrupt=None,toleranceMoveEdgeReactionToCoreInterrupt=None, maximumEdgeSpecies=1000000, minCoreSizeForPrune=50, minSpeciesExistIterationsForPrune=2, filterReactions=False, ignoreOverallFluxCriterion=False, maxNumSpecies=None, maxNumObjsPerIter=1, terminateAtMaxObjects=False,toleranceThermoKeepSpeciesInEdge=numpy.inf,dynamicsTimeScale = Quantity((0.0,'sec'))): self.fluxToleranceKeepInEdge = toleranceKeepInEdge self.fluxToleranceMoveToCore = toleranceMoveToCore self.toleranceMoveEdgeReactionToCore = toleranceMoveEdgeReactionToCore self.fluxToleranceInterrupt = toleranceInterruptSimulation self.maximumEdgeSpecies = maximumEdgeSpecies self.minCoreSizeForPrune = minCoreSizeForPrune self.minSpeciesExistIterationsForPrune = minSpeciesExistIterationsForPrune self.filterReactions = filterReactions self.ignoreOverallFluxCriterion=ignoreOverallFluxCriterion self.toleranceMoveEdgeReactionToSurface = toleranceMoveEdgeReactionToSurface self.toleranceMoveSurfaceSpeciesToCore = toleranceMoveSurfaceSpeciesToCore self.toleranceMoveSurfaceReactionToCore = toleranceMoveSurfaceReactionToCore self.toleranceThermoKeepSpeciesInEdge = toleranceThermoKeepSpeciesInEdge self.terminateAtMaxObjects = terminateAtMaxObjects self.dynamicsTimeScale = dynamicsTimeScale.value_si if toleranceInterruptSimulation: self.fluxToleranceInterrupt = toleranceInterruptSimulation else: self.fluxToleranceInterrupt = toleranceMoveToCore if toleranceMoveEdgeReactionToSurfaceInterrupt: self.toleranceMoveEdgeReactionToSurfaceInterrupt = toleranceMoveEdgeReactionToSurfaceInterrupt else: self.toleranceMoveEdgeReactionToSurfaceInterrupt = toleranceMoveEdgeReactionToSurface if toleranceMoveEdgeReactionToCoreInterrupt: self.toleranceMoveEdgeReactionToCoreInterrupt = toleranceMoveEdgeReactionToCoreInterrupt else: self.toleranceMoveEdgeReactionToCoreInterrupt = toleranceMoveEdgeReactionToCore if maxNumSpecies: self.maxNumSpecies = maxNumSpecies else: self.maxNumSpecies = numpy.inf if maxNumObjsPerIter <= 0: self.maxNumObjsPerIter = numpy.inf else: self.maxNumObjsPerIter = maxNumObjsPerIter
def render_thermo_math(thermo, user=None): """ Return a math representation of the given `thermo` using jsMath. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ # Define other units and conversion factors to use if user and user.is_authenticated(): user_profile = UserProfile.objects.get(user=user) Tunits = str(user_profile.temperatureUnits) Punits = str(user_profile.pressureUnits) Cpunits = str(user_profile.heatCapacityUnits) Hunits = str(user_profile.energyUnits) Sunits = str(user_profile.heatCapacityUnits) Gunits = str(user_profile.energyUnits) else: Tunits = 'K' Punits = 'bar' Cpunits = 'cal/(mol*K)' Hunits = 'kcal/mol' Sunits = 'cal/(mol*K)' Gunits = 'kcal/mol' Tfactor = Quantity(1, Tunits).getConversionFactorFromSI() Pfactor = Quantity(1, Punits).getConversionFactorFromSI() Cpfactor = Quantity(1, Cpunits).getConversionFactorFromSI() Hfactor = Quantity(1, Hunits).getConversionFactorFromSI() Sfactor = Quantity(1, Sunits).getConversionFactorFromSI() Gfactor = Quantity(1, Gunits).getConversionFactorFromSI() # The string that will be returned to the template result = '' if isinstance(thermo, ThermoData): # The thermo is in ThermoData format result += '<table class="thermoEntryData">\n' if thermo.H298 is not None: result += '<tr>' result += r' <td class="key"><span class="math">\Delta H_\mathrm{f}^\circ(298 \ \mathrm{K})</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.H298.value_si * Hfactor, Hunits) result += '</tr>\n' if thermo.S298 is not None: result += '<tr>' result += r' <td class="key"><span class="math">\Delta S_\mathrm{f}^\circ(298 \ \mathrm{K})</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.S298.value_si * Sfactor, Sunits) result += '</tr>\n' if thermo.Tdata is not None and thermo.Cpdata is not None: for T, Cp in zip(thermo.Tdata.value_si, thermo.Cpdata.value_si): result += '<tr>' result += r' <td class="key"><span class="math">C_\mathrm{{p}}^\circ({0:g} \ \mathrm{{ {1!s} }})</span></td>'.format(T * Tfactor, Tunits) result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(Cp * Cpfactor, Cpunits) result += '</tr>\n' result += '</table>\n' elif isinstance(thermo, Wilhoit): # The thermo is in Wilhoit format result += '<div class="math">\n' result += r'\begin{split}' result += r'C_\mathrm{p}(T) &= C_\mathrm{p}(0) + \left[ C_\mathrm{p}(\infty) -' result += r' C_\mathrm{p}(0) \right] y^2 \left[ 1 + (y - 1) \sum_{i=0}^3 a_i y^i \right] \\' result += r'H^\circ(T) &= H_0 + \int_0^\infty C_\mathrm{p}(T) \ dT \\' result += r'S^\circ(T) &= S_0 + \int_0^\infty \frac{C_\mathrm{p}(T)}{T} \ dT\\' result += r'y &\equiv \frac{T}{T + B}' result += r'\end{split}' result += '</div>\n' result += '<table class="thermoEntryData">\n' result += '<tr>' result += r' <td class="key"><span class="math">C_\mathrm{p}(0)</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.cp0.value_si * Cpfactor, Cpunits) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">C_\mathrm{p}(\infty)</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.cpInf.value_si * Cpfactor, Cpunits) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_0</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(thermo.a0)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_1</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(thermo.a1)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_2</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(thermo.a2)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_3</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(thermo.a3)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">H_0</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.H0.value_si * Hfactor, Hunits) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">S_0</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.S0.value_si * Sfactor, Sunits) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">B</span></td>' result += r' <td class="equals">=</td>' result += r' <td class="value"><span class="math">{0:.2f} \ \mathrm{{ {1!s} }}</span></td>'.format(thermo.B.value_si * Tfactor, Tunits) result += '</tr>\n' result += '</table>\n' elif isinstance(thermo, NASA): # The thermo is in NASA format result += '<div class="math">\n' result += r'\frac{C_\mathrm{p}^\circ(T)}{R} = a_{-2} T^{-2} + a_{-1} T^{-1} + a_0 + a_1 T + a_2 T^2 + a_3 T^3 + a_4 T^4' result += '</div>\n' result += '<div class="math">\n' result += r'\frac{H^\circ(T)}{RT} = -a_{-2} T^{-2} + a_{-1} \frac{\ln T}{T} + a_0 + \frac{1}{2} a_1 T + \frac{1}{3} a_2 T^2 + \frac{1}{4} a_3 T^3 + \frac{1}{5} a_4 T^4 + \frac{a_5}{T}' result += '</div>\n' result += '<div class="math">\n' result += r'\frac{S^\circ(T)}{R} = -\frac{1}{2} a_{-2} T^{-2} - a_{-1} T^{-1} + a_0 \ln T + a_1 T + \frac{1}{2} a_2 T^2 + \frac{1}{3} a_3 T^3 + \frac{1}{4} a_4 T^4 + a_6' result += '</div>\n' result += '<table class="thermoEntryData">\n' result += '<tr>' result += r' <td class="key">Temperature range</td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value">{0:g} to {1:g} {2!s}</td>'.format(polynomial.Tmin.value_si * Tfactor, polynomial.Tmax.value_si * Tfactor, Tunits) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_{-2}</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.cm2)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_{-1}</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.cm1)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_0</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c0)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_1</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c1)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_2</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c2)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_3</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c3)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_4</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c4)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_5</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c5)) result += '</tr>\n' result += '<tr>' result += r' <td class="key"><span class="math">a_6</span></td>' result += r' <td class="equals">=</td>' for polynomial in thermo.polynomials: result += r' <td class="value"><span class="math">{0!s}</span></td>'.format(getLaTeXScientificNotation(polynomial.c6)) result += '</tr>\n' result += '</table>\n' elif isinstance(thermo, list): # The thermo is a link index = thermo[1] url = reverse('database.views.thermoEntry', {'section': section, 'subsection': subsection, 'index': index}) result += '<table class="thermoEntryData">\n' result += '<tr>' result += r' <td class="key">Link:</td>' result += r' <td class="value"><a href="{0!s}">{1}</a></td>'.format(url, index) result += '</tr>\n' result += '<\table>\n' # Temperature range if isinstance(thermo, (ThermoData, Wilhoit, NASA)): result += '<table class="thermoEntryData">' if thermo.Tmin is not None and thermo.Tmax is not None: result += '<tr><td class="key">Temperature range</td><td class="equals">=</td><td class="value">{0:g} to {1:g} {2!s}</td></tr>'.format(thermo.Tmin.value_si, thermo.Tmax.value_si, Tunits) result += '</table>' return mark_safe(result)
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # # DEALINGS IN THE SOFTWARE. # # # ############################################################################### """ This module contains information related to kinetic uncertainties """ from rmgpy.quantity import Quantity rank_accuracy_map ={1:(0.0,'kcal/mol'), 2:(0.5,'kcal/mol'), 3:(1.0,'kcal/mol'), 4:(1.5,'kcal/mol'), 5:(2.5,'kcal/mol'), 6:(3.5,'kcal/mol'), 7:(4.0,'kcal/mol'), 8:(5.0,'kcal/mol'), 9:(14.0,'kcal/mol'), 10:(14.0,'kcal/mol'), None:(14.0,'kcal/mol'), 0:(14.0,'kcal/mol'), 11:(14.0,'kcal/mol'), } rank_accuracy_map = {key:Quantity(value) for key,value in rank_accuracy_map.iteritems()}
def generateCanteraConditions(reactorTypeList, reactionTimeList, molFracList, Tlist=None, Plist=None, Vlist=None): """ Creates a list of cantera conditions from from the arguments provided. ======================= ==================================================== Argument Description ======================= ==================================================== `reactorTypeList` A list of strings of the cantera reactor type. List of supported types below: IdealGasReactor: A constant volume, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureReactor: A homogeneous, constant pressure, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureTemperatureReactor: A homogenous, constant pressure and constant temperature, zero-dimensional reactor for ideal gas mixtures (the same as RMG's SimpleReactor) `reactionTimeList` A tuple object giving the ([list of reaction times], units) `molFracList` A list of molfrac dictionaries with species object keys and mole fraction values To specify the system for an ideal gas, you must define 2 of the following 3 parameters: `T0List` A tuple giving the ([list of initial temperatures], units) 'P0List' A tuple giving the ([list of initial pressures], units) 'V0List' A tuple giving the ([list of initial specific volumes], units) This saves all the reaction conditions into the Cantera class. """ # Create individual ScalarQuantity objects for Tlist, Plist, Vlist, and reactionTimeList if Tlist: Tlist = Quantity( Tlist) # Be able to create a Quantity object from it first Tlist = [(Tlist.value[i], Tlist.units) for i in range(len(Tlist.value))] if Plist: Plist = Quantity(Plist) Plist = [(Plist.value[i], Plist.units) for i in range(len(Plist.value))] if Vlist: Vlist = Quantity(Vlist) Vlist = [(Vlist.value[i], Vlist.units) for i in range(len(Vlist.value))] if reactionTimeList: reactionTimeList = Quantity(reactionTimeList) reactionTimeList = [(reactionTimeList.value[i], reactionTimeList.units) for i in range(len(reactionTimeList.value))] conditions = [] if Tlist is None: for reactorType in reactorTypeList: for reactionTime in reactionTimeList: for molFrac in molFracList: for P in Plist: for V in Vlist: conditions.append( CanteraCondition(reactorType, reactionTime, molFrac, P0=P, V0=V)) elif Plist is None: for reactorType in reactorTypeList: for reactionTime in reactionTimeList: for molFrac in molFracList: for T in Tlist: for V in Vlist: conditions.append( CanteraCondition(reactorType, reactionTime, molFrac, T0=T, V0=V)) elif Vlist is None: for reactorType in reactorTypeList: for reactionTime in reactionTimeList: for molFrac in molFracList: for T in Tlist: for P in Plist: conditions.append( CanteraCondition(reactorType, reactionTime, molFrac, T0=T, P0=P)) else: raise Exception( "Cantera conditions must leave one of T0, P0, and V0 state variables unspecified" ) return conditions
def __init__(self, tol_move_to_core=None, tol_move_edge_rxn_to_core=np.inf, tol_keep_in_edge=0.0, tol_interrupt_simulation=1.0, tol_move_edge_rxn_to_surface=np.inf, tol_move_surface_spc_to_core=np.inf, tol_move_surface_rxn_to_core=np.inf, tol_move_edge_rxn_to_surface_interrupt=None, tol_move_edge_rxn_to_core_interrupt=None, maximum_edge_species=1000000, min_core_size_for_prune=50, min_species_exist_iterations_for_prune=2, filter_reactions=False, filter_threshold=1e8, ignore_overall_flux_criterion=False, max_num_species=None, max_num_objects_per_iter=1, terminate_at_max_objects=False, thermo_tol_keep_spc_in_edge=np.inf, dynamics_time_scale=Quantity((0.0, 'sec')), tol_branch_rxn_to_core=0.0, branching_index=0.5, branching_ratio_max=1.0): self.tol_keep_in_edge = tol_keep_in_edge self.tol_move_to_core = tol_move_to_core self.tol_move_edge_rxn_to_core = tol_move_edge_rxn_to_core self.tol_interrupt_simulation = tol_interrupt_simulation self.maximum_edge_species = maximum_edge_species self.min_core_size_for_prune = min_core_size_for_prune self.min_species_exist_iterations_for_prune = min_species_exist_iterations_for_prune self.filter_reactions = filter_reactions self.filter_threshold = filter_threshold self.ignore_overall_flux_criterion = ignore_overall_flux_criterion self.tol_move_edge_rxn_to_surface = tol_move_edge_rxn_to_surface self.tol_move_surface_spc_to_core = tol_move_surface_spc_to_core self.tol_move_surface_rxn_to_core = tol_move_surface_rxn_to_core self.thermo_tol_keep_spc_in_edge = thermo_tol_keep_spc_in_edge self.terminate_at_max_objects = terminate_at_max_objects self.dynamics_time_scale = dynamics_time_scale.value_si self.tol_branch_rxn_to_core = tol_branch_rxn_to_core self.branching_index = branching_index self.branching_ratio_max = branching_ratio_max if tol_interrupt_simulation: self.tol_interrupt_simulation = tol_interrupt_simulation else: self.tol_interrupt_simulation = tol_move_to_core if tol_move_edge_rxn_to_surface_interrupt: self.tol_move_edge_rxn_to_surface_interrupt = tol_move_edge_rxn_to_surface_interrupt else: self.tol_move_edge_rxn_to_surface_interrupt = tol_move_edge_rxn_to_surface if tol_move_edge_rxn_to_core_interrupt: self.tol_move_edge_rxn_to_core_interrupt = tol_move_edge_rxn_to_core_interrupt else: self.tol_move_edge_rxn_to_core_interrupt = tol_move_edge_rxn_to_core if max_num_species: self.max_num_species = max_num_species else: self.max_num_species = np.inf if max_num_objects_per_iter <= 0: self.max_num_objects_per_iter = np.inf else: self.max_num_objects_per_iter = max_num_objects_per_iter
def render_states_math(states, user=None): """ Return a math representation of the given `states` using jsMath. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ # Define other units and conversion factors to use if user and user.is_authenticated(): user_profile = UserProfile.objects.get(user=user) Tunits = str(user_profile.temperatureUnits) Eunits = str(user_profile.energyUnits) else: Tunits = 'K' Eunits = 'kcal/mol' Tfactor = Quantity(1, Tunits).getConversionFactorFromSI() Efactor = Quantity(1, Eunits).getConversionFactorFromSI() # The string that will be returned to the template result = '' result += '<table class="reference">\n' hindIndex = 0 for mode in states.modes: if isinstance(mode, Translation): result += '<tr>' result += r' <td colspan="2" class="section">External translation</td>' result += '</tr>\n' result += '<tr>' result += r' <td class="label">Mass (g/mol):</td>' result += r' <td>{0:g}</td>'.format(mode.mass.value * 1000.) result += '</tr>\n' elif isinstance(mode, RigidRotor): result += '<tr>' result += r' <td colspan="2" class="section">External rotation</td>' result += '</tr>\n' result += '<tr>' result += r' <td class="label">Linearity:</td>' result += r' <td>{0}</td>'.format(mode.linear) result += '</tr>\n' result += '<tr>' result += r' <td class="label">Moments of inertia (amu×Å^2):</td>' if mode.inertia.isArray(): inertia = ', '.join([ '{0:.1f}'.format(I * constants.Na * 1e23) for I in mode.inertia.values ]) else: inertia = '{0:.1f}'.format(mode.inertia.value * constants.Na * 1e23) result += r' <td>{0!s}</td>'.format(inertia) result += '</tr>\n' result += '<tr>' result += r' <td class="label">Symmetry number:</td>' result += r' <td>{0:d}</td>'.format(mode.symmetry) result += '</tr>\n' elif isinstance(mode, HarmonicOscillator): result += '<tr>' result += r' <td colspan="2" class="section">Vibrations</td>' result += '</tr>\n' result += '<tr>' frequencies = ', '.join( ['{0:.1f}'.format(freq) for freq in mode.frequencies.values]) result += r' <td class="label" class="section">Frequencies (cm^-1):</td>' result += r' <td>{0!s}</td>'.format(frequencies) result += '</tr>\n' elif isinstance(mode, HinderedRotor): hindIndex += 1 result += '<tr>' result += r' <td colspan="2" class="section">Hindered rotor #{0:d}:</td>'.format( hindIndex) result += '</tr>\n' if mode.fourier: fourierA = ', '.join( ['{0:g}'.format(a_k) for a_k in mode.fourier.values[0, :]]) fourierB = ', '.join( ['{0:g}'.format(b_k) for b_k in mode.fourier.values[1, :]]) result += '<tr>' result += r' <td colspan="2"><span class="math">V(\phi) = A + \sum_k \left( a_k \cos k \phi + b_k \sin k \phi \right)</span></td>' result += '</tr>\n' result += '<tr>' result += r' <td class="label"><span class="math">a_k</span></td>' result += r' <td>{0}</td>'.format(fourierA) result += '</tr>\n' result += '<tr>' result += r' <td class="label"><span class="math">b_k</span></td>' result += r' <td>{0}</td>'.format(fourierB) result += '</tr>\n' else: result += '<tr>' result += r' <td colspan="2"><span class="math">V(\phi) = \frac{1}{2} V_0 \left[1 - \cos \left( \sigma \phi \right) \right]</span></td>' result += '</tr>\n' result += '<tr>' result += r' <td class="label">Barrier height ({0!s}):</td>'.format( Eunits) result += r' <td>{0:.2f}</td>'.format(mode.barrier.value * Efactor) result += '</tr>\n' result += '<tr>' result += r' <td class="label">Moment of inertia (amu×Å^2):</td>' result += r' <td>{0:.1f}</td>'.format(mode.inertia.value * constants.Na * 1e23) result += '</tr>\n' result += '<tr>' result += r' <td class="label">Symmetry number:</td>' result += r' <td>{0:d}</td>'.format(mode.symmetry) result += '</tr>\n' result += '<tr>' result += r' <td colspan="2" class="section">Electronic</td>' result += '</tr>\n' result += '<tr>' result += r' <td class="label">Spin multiplicity:</td>' result += r' <td>{0:d}</td>'.format(states.spinMultiplicity) result += '</tr>\n' result += '</table>\n' return mark_safe(result)
def get_states_data(states, user=None): """ Generate and return a set of :math:`k(T,P)` data suitable for plotting using Highcharts. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ # Define other units and conversion factors to use if user and user.is_authenticated(): user_profile = UserProfile.objects.get(user=user) Tunits = str(user_profile.temperatureUnits) Eunits = str(user_profile.energyUnits) else: Tunits = 'K' Eunits = 'kcal/mol' Tfactor = Quantity(1, Tunits).getConversionFactorFromSI() Efactor = Quantity(1, Eunits).getConversionFactorFromSI() Qunits = '' Qfactor = 1.0 rhounits = 'per cm^-1' rhofactor = constants.h * constants.c * 100 * constants.Na phiunits = 'rad' phifactor = 1.0 Vunits = Eunits Vfactor = Efactor # Generate data to use for plots Tdata = [] Qdata = [] for T in numpy.arange(10, 2001, 10): Tdata.append(T * Tfactor) Qdata.append(states.getPartitionFunction(T) * Qfactor) Edata = numpy.arange(0, 400001, 1000, numpy.float) rhodata = states.getDensityOfStates(Edata) Edata = list(Edata * Efactor) rhodata = list(rhodata * rhofactor) phidata = numpy.arange(0, 2 * math.pi, math.pi / 200) Vdata = [] for mode in states.modes: if isinstance(mode, HinderedRotor): Vdata.append(list(mode.getPotential(phidata) * Vfactor)) phidata = list(phidata * phifactor) return mark_safe(""" Tlist = {0}; Qlist = {1}; Elist = {2}; rholist = {3}; philist = {4}; Vlist = {5}; Tunits = "{6}"; Qunits = "{7}"; Eunits = "{8}"; rhounits = "{9}"; phiunits = "{10}"; Vunits = "{11}"; """.format( Tdata, Qdata, Edata, rhodata, phidata, Vdata, Tunits, Qunits, Eunits, rhounits, phiunits, Vunits, ))
def getRateCoefficientUnits(kinetics, user=None): """ For a given `kinetics` model, return the desired rate coefficient units at high and low pressures, the conversion factor from SI to those units (high pressure), and the number of reactant species. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ # Determine the number of reactants based on the units of one of the # kinetic parameters (which to use depends on the model) numReactants = 0 if isinstance(kinetics, Arrhenius): numReactants = getNumberOfReactantsFromUnits(kinetics.A.units) elif isinstance(kinetics, ArrheniusEP): numReactants = getNumberOfReactantsFromUnits(kinetics.A.units) elif isinstance(kinetics, KineticsData): numReactants = getNumberOfReactantsFromUnits(kinetics.kdata.units) elif isinstance(kinetics, PDepArrhenius): numReactants = getNumberOfReactantsFromUnits( kinetics.arrhenius[0].A.units) elif isinstance(kinetics, Chebyshev): numReactants = getNumberOfReactantsFromUnits(kinetics.kunits) elif isinstance(kinetics, Troe): numReactants = getNumberOfReactantsFromUnits( kinetics.arrheniusHigh.A.units) elif isinstance(kinetics, Lindemann): numReactants = getNumberOfReactantsFromUnits( kinetics.arrheniusHigh.A.units) elif isinstance(kinetics, ThirdBody): numReactants = getNumberOfReactantsFromUnits( kinetics.arrheniusLow.A.units) elif isinstance(kinetics, MultiArrhenius): return getRateCoefficientUnits(kinetics.arrhenius[0]) elif isinstance(kinetics, MultiPDepArrhenius): return getRateCoefficientUnits(kinetics.arrhenius[0]) # Use the number of reactants to get the rate coefficient units and conversion factor kunitsDict = { 1: 's^-1', 2: 'm^3/(mol*s)', 3: 'm^6/(mol^2*s)', 4: 'm^9/(mol^3*s)', } if user and user.is_authenticated(): user_profile = UserProfile.objects.get(user=user) if user_profile.rateCoefficientUnits == 'm^3,mol,s': kunitsDict = { 1: 's^-1', 2: 'm^3/(mol*s)', 3: 'm^6/(mol^2*s)', 4: 'm^9/(mol^3*s)', } elif user_profile.rateCoefficientUnits == 'cm^3,mol,s': kunitsDict = { 1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)', 4: 'cm^9/(mol^3*s)', } elif user_profile.rateCoefficientUnits == 'm^3,molecule,s': kunitsDict = { 1: 's^-1', 2: 'm^3/(molecule*s)', 3: 'm^6/(molecule^2*s)', 4: 'm^9/(molecule^3*s)', } elif user_profile.rateCoefficientUnits == 'cm^3,molecule,s': kunitsDict = { 1: 's^-1', 2: 'cm^3/(molecule*s)', 3: 'cm^6/(molecule^2*s)', 4: 'cm^9/(molecule^3*s)', } kunits = kunitsDict[numReactants] kunits_low = kunitsDict[numReactants + 1] kfactor = Quantity(1, kunits).getConversionFactorFromSI() return kunits, kunits_low, kfactor, numReactants
if network is None: return # Set title and description of network network.title = local_context['title'] network.description = local_context['description'].strip() # Log title and description logging.info('') logging.info('Network title: {0}'.format(network.title)) logging.info('Network description: ') logging.info(network.description) measure.network = network # Determine temperature grid if not yet known if measure.Tlist is None and measure.Tmin is not None and measure.Tmax is not None and measure.Tcount is not None: measure.Tlist = Quantity(getTemperaturesForModel(measure.model, measure.Tmin.value_si, measure.Tmax.value_si, measure.Tcount),"K") elif measure.Tmin is not None and measure.Tmax is not None and measure.Tcount is not None: pass else: raise InputError('No temperature() block found.') # Determine pressure grid if not yet known if measure.Plist is None and measure.Pmin is not None and measure.Pmax is not None and measure.Pcount is not None: measure.Plist = Quantity(getPressuresForModel(measure.model, measure.Pmin.value_si, measure.Pmax.value_si, measure.Pcount),"Pa") elif measure.Pmin is not None and measure.Pmax is not None and measure.Pcount is not None: pass else: raise InputError('No pressure() block found.') # Check that we have energy grain information if measure.grainSize is None and measure.grainCount is None:
('C', 'O', 2): (799.0, 'kJ/mol'), ('C', 'O', 3): (1072.0, 'kJ/mol'), ('C', 'P', 1): (264.0, 'kJ/mol'), ('C', 'S', 1): (272.0, 'kJ/mol'), ('C', 'S', 2): (573.0, 'kJ/mol'), ('C', 'F', 1): (485.0, 'kJ/mol'), ('C', 'Cl', 1): (327.0, 'kJ/mol'), ('C', 'Br', 1): (285.0, 'kJ/mol'), ('C', 'I', 1): (213.0, 'kJ/mol'), ('Si', 'Si', 1): (222.0, 'kJ/mol'), ('Si', 'N', 1): (355.0, 'kJ/mol'), ('Si', 'O', 1): (452.0, 'kJ/mol'), ('Si', 'S', 1): (293.0, 'kJ/mol'), ('Si', 'F', 1): (565.0, 'kJ/mol'), ('Si', 'Cl', 1): (381.0, 'kJ/mol'), ('Si', 'Br', 1): (310.0, 'kJ/mol'), ('Si', 'I', 1): (234.0, 'kJ/mol'), ('N', 'N', 1): (167.0, 'kJ/mol'), ('N', 'N', 2): (418.0, 'kJ/mol'), ('N', 'N', 3): (942.0, 'kJ/mol'), ('N', 'O', 1): (201.0, 'kJ/mol'), ('N', 'O', 2): (607.0, 'kJ/mol'), ('N', 'F', 1): (283.0, 'kJ/mol'), ('N', 'Cl', 1): (313.0, 'kJ/mol'), ('O', 'O', 1): (142.0, 'kJ/mol'), ('O', 'O', 2): (494.0, 'kJ/mol'), ('O', 'P', 1): (335.0, 'kJ/mol'), ('O', 'P', 2): (544.0, 'kJ/mol'), ('O', 'S', 1): (265.0, 'kJ/mol'), ('O', 'S', 2): (522.0, 'kJ/mol'), ('P', 'P', 1): (201.0, 'kJ/mol'), ('P', 'P', 2): (351.0, 'kJ/mol'), ('P', 'P', 3): (489.0, 'kJ/mol'), ('P', 'S', 2): (335.0, 'kJ/mol'), ('P', 'F', 1): (490.0, 'kJ/mol'), ('P', 'Cl', 1): (326.0, 'kJ/mol'), ('P', 'Br', 1): (264.0, 'kJ/mol'), ('P', 'I', 2): (184.0, 'kJ/mol'), ('S', 'S', 1): (226.0, 'kJ/mol'), ('S', 'S', 2): (425.0, 'kJ/mol'), ('S', 'Cl', 1): (255.0, 'kJ/mol'), ('F', 'F', 1): (155.0, 'kJ/mol'), ('Cl', 'Cl', 1): (240.0, 'kJ/mol'), ('Br', 'Br', 1): (190.0, 'kJ/mol'), ('I', 'I', 1): (148.0, 'kJ/mol')} bdes = {} for key, value in bde_dict.items(): q = Quantity(value).value_si bdes[(key[0], key[1], key[2])] = q bdes[(key[1], key[0], key[2])] = q
def processOldLibraryEntry(self, data): """ Process a list of parameters `data` as read from an old-style RMG thermo database, returning the corresponding kinetics object. """ # The names of all of the RMG reaction families that are bimolecular BIMOLECULAR_KINETICS_FAMILIES = [ 'H_Abstraction', 'R_Addition_MultipleBond', 'R_Recombination', 'Disproportionation', '1+2_Cycloaddition', '2+2_cycloaddition_Cd', '2+2_cycloaddition_CO', '2+2_cycloaddition_CCO', 'Diels_alder_addition', '1,2_Insertion', '1,3_Insertion_CO2', '1,3_Insertion_ROR', 'R_Addition_COm', 'Oa_R_Recombination', 'Substitution_O', 'SubstitutionS', 'R_Addition_CSm', '1,3_Insertion_RSR', 'lone_electron_pair_bond', ] # The names of all of the RMG reaction families that are unimolecular UNIMOLECULAR_KINETICS_FAMILIES = [ 'intra_H_migration', 'Birad_recombination', 'intra_OH_migration', 'HO2_Elimination_from_PeroxyRadical', 'H_shift_cyclopentadiene', 'Cyclic_Ether_Formation', 'Intra_R_Add_Exocyclic', 'Intra_R_Add_Endocyclic', '1,2-Birad_to_alkene', 'Intra_Disproportionation', 'Korcek_step1', 'Korcek_step2', '1,2_shiftS', 'intra_substitutionCS_cyclization', 'intra_substitutionCS_isomerization', 'intra_substitutionS_cyclization', 'intra_substitutionS_isomerization', 'intra_NO2_ONO_conversion', '1,4_Cyclic_birad_scission', '1,4_Linear_birad_scission', 'Intra_Diels_alder', 'ketoenol', 'Retroen' ] # This is hardcoding of reaction families! label = os.path.split(self.label)[-2] if label in BIMOLECULAR_KINETICS_FAMILIES: Aunits = 'cm^3/(mol*s)' elif label in UNIMOLECULAR_KINETICS_FAMILIES: Aunits = 's^-1' else: raise Exception( 'Unable to determine preexponential units for old reaction family "{0}".' .format(self.label)) try: Tmin, Tmax = data[0].split('-') Tmin = (float(Tmin), "K") Tmax = (float(Tmax), "K") except ValueError: Tmin = (float(data[0]), "K") Tmax = None A, n, alpha, E0, dA, dn, dalpha, dE0 = data[1:9] A = float(A) if dA[0] == '*': A = Quantity(A, Aunits, '*|/', float(dA[1:])) else: dA = float(dA) if dA != 0: A = Quantity(A, Aunits, '+|-', dA) else: A = Quantity(A, Aunits) n = float(n) dn = float(dn) if dn != 0: n = Quantity(n, '', '+|-', dn) else: n = Quantity(n, '') alpha = float(alpha) dalpha = float(dalpha) if dalpha != 0: alpha = Quantity(alpha, '', '+|-', dalpha) else: alpha = Quantity(alpha, '') E0 = float(E0) dE0 = float(dE0) if dE0 != 0: E0 = Quantity(E0, 'kcal/mol', '+|-', dE0) else: E0 = Quantity(E0, 'kcal/mol') rank = int(data[9]) return ArrheniusEP(A=A, n=n, alpha=alpha, E0=E0, Tmin=Tmin, Tmax=Tmax), rank
class CanteraCondition: """ This class organizes the inputs needed for a cantera simulation ======================= ==================================================== Attribute Description ======================= ==================================================== `reactorType` A string of the cantera reactor type. List of supported types below: IdealGasReactor: A constant volume, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureReactor: A homogeneous, constant pressure, zero-dimensional reactor for ideal gas mixtures IdealGasConstPressureTemperatureReactor: A homogenous, constant pressure and constant temperature, zero-dimensional reactor for ideal gas mixtures (the same as RMG's SimpleReactor) `reactionTime` A tuple object giving the (reaction time, units) `molFrac` A dictionary giving the initial mol Fractions. Keys are species objects and the values are floats To specify the system for an ideal gas, you must define 2 of the following 3 parameters: `T0` A tuple giving the (initial temperature, units) which reconstructs a Quantity object 'P0' A tuple giving the (initial pressure, units) which reconstructs a Quantity object 'V0' A tuple giving the (initial specific volume, units) which reconstructs a Quantity object ======================= ==================================================== """ def __init__(self, reactorType, reactionTime, molFrac, T0=None, P0=None, V0=None): self.reactorType = reactorType self.reactionTime = Quantity(reactionTime) # Normalize initialMolFrac if not already done: if sum(molFrac.values()) != 1.00: total = sum(molFrac.values()) for species, value in molFrac.iteritems(): molFrac[species] = value / total self.molFrac = molFrac # Check to see that one of the three attributes T0, P0, and V0 is less unspecified props = [T0, P0, V0] total = 0 for prop in props: if prop is None: total += 1 if not total == 1: raise Exception( "Cantera conditions must leave one of T0, P0, and V0 state variables unspecified" ) self.T0 = Quantity(T0) if T0 else None self.P0 = Quantity(P0) if P0 else None self.V0 = Quantity(V0) if V0 else None def __repr__(self): """ Return a string representation that can be used to reconstruct the object. """ string = "CanteraCondition(" string += 'reactorType="{0}", '.format(self.reactorType) string += 'reactionTime={}, '.format(self.reactionTime.__repr__()) string += 'molFrac={0}, '.format(self.molFrac.__repr__()) if self.T0: string += 'T0={}, '.format(self.T0.__repr__()) if self.P0: string += 'P0={}, '.format(self.P0.__repr__()) if self.V0: string += 'V0={}, '.format(self.V0__repr__()) string = string[:-2] + ')' return string def __str__(self): """ Return a string representation of the condition. """ string = "" string += 'Reactor Type: {0}\n'.format(self.reactorType) string += 'Reaction Time: {}\n'.format(self.reactionTime) if self.T0: string += 'T0: {}\n'.format(self.T0) if self.P0: string += 'P0: {}\n'.format(self.P0) if self.V0: string += 'V0: {}\n'.format(self.V0) #ConvertMolFrac to SMILES for keys for display prettyMolFrac = {} for key, value in self.molFrac.iteritems(): prettyMolFrac[key.molecule[0].toSMILES()] = value string += 'Initial Mole Fractions: {0}'.format( prettyMolFrac.__repr__()) return string
def render_kinetics_math(kinetics, user=None): """ Return a math representation of the given `kinetics` using MathJax. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ if kinetics is None: return mark_safe("<p>There are no kinetics for this entry.</p>") # Define other units and conversion factors to use if user and user.is_authenticated: user_profile = UserProfile.objects.get(user=user) Tunits = user_profile.temperature_units Punits = user_profile.pressure_units Eunits = user_profile.energy_units else: Tunits = 'K' Punits = 'Pa' Eunits = 'J/mol' kunits, kunits_low, kfactor = getRateCoefficientUnits(kinetics, user=user) Tfactor = Quantity(1, Tunits).get_conversion_factor_from_si() Pfactor = Quantity(1, Punits).get_conversion_factor_from_si() Efactor = Quantity(1, Eunits).get_conversion_factor_from_si() if kunits == 's^-1': kunits = 's^{-1}' # The string that will be returned to the template result = '' if isinstance(kinetics, (Arrhenius, SurfaceArrhenius, StickingCoefficient)): # The kinetics is in Arrhenius format result += r'<script type="math/tex; mode=display">k(T) = {0!s}</script>'.format(getArrheniusJSMath( kinetics.A.value_si * kfactor, kunits, kinetics.n.value_si, '', kinetics.Ea.value_si * Efactor, Eunits, kinetics.T0.value_si * Tfactor, Tunits, )) elif isinstance(kinetics, (ArrheniusEP, SurfaceArrheniusBEP, StickingCoefficientBEP)): # The kinetics is in ArrheniusEP format result += r'<script type="math/tex; mode=display">k(T) = {0!s}'.format(getLaTeXScientificNotation(kinetics.A.value_si * kfactor)) if kinetics.n.value_si != 0: result += r' T^{{ {0:.2f} }}'.format(kinetics.n.value_si) result += r' \exp \left( - \, \frac{{ {0:.2f} \ \mathrm{{ {1!s} }} + {2:.2f} \Delta H_\mathrm{{rxn}}^\circ }}{{ R T }} \right)'.format(kinetics.E0.value_si * Efactor, Eunits, kinetics.alpha.value_si) result += r' \ \mathrm{{ {0!s} }}</script>'.format(kunits) elif isinstance(kinetics, ArrheniusBM): # The kinetics is in ArrheniusBM format result += r'<script type="math/tex; mode=display">\begin{{split}}k(T) &= {0!s}'.format(getLaTeXScientificNotation(kinetics.A.value_si * kfactor)) if kinetics.n.value_si != 0: result += r' T^{{ {0:.2f} }}' .format(kinetics.n.value_si) result += r' \exp \left(- \, \frac{{ E_\mathrm{{a}} }}{{RT}} \right) \ \mathrm{{ {0!s} }} \\'.format(kunits) result += r''' E_\mathrm{{a}} &= \frac{{ \left( w_{{0}} + 0.5 \Delta H_\mathrm{{rxn}} \right) \left( V_\mathrm{{p}} - 2 w_{{0}} + \Delta H_\mathrm{{rxn}} \right) ^ {{2}} }} {{ V_\mathrm{{p}} ^ {{2}} - \left( 2 w_{{0}} \right) ^ {{2}} + \Delta H_\mathrm{{rxn}} ^ {{2}} }} \\ V_\mathrm{{p}} &= 2 w_{{0}} \left( \frac{{ w_{{0}} + E_{{0}} }} {{ w_{{0}} - E_{{0}} }} \right) \\ w_{{0}} &= {0:.2f}\ \mathrm{{ {1!s} }} \\ E_{{0}} &= {2:.2f}\ \mathrm{{ {1!s} }} \end{{split}}</script> '''.format(kinetics.w0.value_si * Efactor, Eunits, kinetics.E0.value_si * Efactor) elif isinstance(kinetics, KineticsData): # The kinetics is in KineticsData format result += r'<table class="KineticsData">' result += r'<tr><th>Temperature</th><th>Rate coefficient</th></tr>' for T, k in zip(kinetics.Tdata.value_si, kinetics.kdata.value_si): result += r'<tr><td><script type="math/tex">{0:g} \ \mathrm{{ {1!s} }}</script></td><td><script type="math/tex">{2!s} \ \mathrm{{ {3!s} }}</script></td></tr>'.format(T * Tfactor, Tunits, getLaTeXScientificNotation(k * kfactor), kunits) result += r'</table>' # fit to an arrhenius arr = kinetics.to_arrhenius() result += "Fitted to an Arrhenius:" result += r'<script type="math/tex; mode=display">k(T) = {0!s}</script>'.format(getArrheniusJSMath( arr.A.value_si * kfactor, kunits, arr.n.value_si, '', arr.Ea.value_si * Efactor, Eunits, arr.T0.value_si * Tfactor, Tunits, )) elif isinstance(kinetics, PDepArrhenius): # The kinetics is in PDepArrhenius format for P, arrh in zip(kinetics.pressures.value_si, kinetics.arrhenius): if isinstance(arrh, Arrhenius): result += r'<script type="math/tex; mode=display">k(T, {0} \mathrm{{ {1!s} }}) = {2}</script>'.format( getLaTeXScientificNotation(P * Pfactor), Punits, getArrheniusJSMath( arrh.A.value_si * kfactor, kunits, arrh.n.value_si, '', arrh.Ea.value_si * Efactor, Eunits, arrh.T0.value_si * Tfactor, Tunits, ), ) elif isinstance(arrh, MultiArrhenius): start = (r'<script type="math/tex; mode=display">' r'k(T, {0} \mathrm{{ {1!s} }}) = '.format(getLaTeXScientificNotation(P * Pfactor), Punits)) res = '' for i, k in enumerate(arrh.arrhenius): start += 'k_{{ {0:d} }}(T, {1} \mathrm{{ {2!s} }}) + '.format(i + 1, getLaTeXScientificNotation(P * Pfactor), Punits) res += r'<script type="math/tex; mode=display">k_{{ {0:d} }}(T, {1} \mathrm{{ {2!s} }}) = {3}</script>'.format( i + 1, getLaTeXScientificNotation(P * Pfactor), Punits, getArrheniusJSMath( k.A.value_si * kfactor, kunits, k.n.value_si, '', k.Ea.value_si * Efactor, Eunits, k.T0.value_si * Tfactor, Tunits, ), ) result += start[:-3] + '</script>\n' + res + '<br/>' elif isinstance(kinetics, Chebyshev): # The kinetics is in Chebyshev format result += r"""<script type="math/tex; mode=display"> \begin{split} \log k(T,P) &= \sum_{t=1}^{N_T} \sum_{p=1}^{N_P} C_{tp} \phi_t(\tilde{T}) \phi_p(\tilde{P}) [\mathrm{""" + kinetics.kunits + r""" }] \\ \tilde{T} &\equiv \frac{2T^{-1} - T_\mathrm{min}^{-1} - T_\mathrm{max}^{-1}}{T_\mathrm{max}^{-1} - T_\mathrm{min}^{-1}} \\ \tilde{P} &\equiv \frac{2 \log P - \log P_\mathrm{min} - \log P_\mathrm{max}}{\log P_\mathrm{max} - \log P_\mathrm{min}} \end{split}</script><br/> <script type="math/tex; mode=display">\mathbf{C} = \begin{bmatrix} """ for t in range(kinetics.degreeT): for p in range(kinetics.degreeP): if p > 0: result += ' & ' result += '{0:g}'.format(kinetics.coeffs.value_si[t, p]) result += '\\\\ \n' result += '\end{bmatrix}</script>' elif isinstance(kinetics, Troe): # The kinetics is in Troe format Fcent = r'(1 - \alpha) \exp \left( -T/T_3 \right) + \alpha \exp \left( -T/T_1 \right) + \exp \left( -T_2/T \right)' if kinetics.T2 is not None: Fcent += r' + \exp \left( -T_2/T \right)' result += r"""<script type="math/tex; mode=display"> \begin{{split}} k(T,P) &= k_\infty(T) \left[ \frac{{P_\mathrm{{r}}}}{{1 + P_\mathrm{{r}}}} \right] F \\ P_\mathrm{{r}} &= \frac{{k_0(T)}}{{k_\infty(T)}} [\mathrm{{M}}] \\ \log F &= \left\{{1 + \left[ \frac{{\log P_\mathrm{{r}} + c}}{{n - d (\log P_\mathrm{{r}} + c)}} \right]^2 \right\}}^{{-1}} \log F_\mathrm{{cent}} \\ c &= -0.4 - 0.67 \log F_\mathrm{{cent}} \\ n &= 0.75 - 1.27 \log F_\mathrm{{cent}} \\ d &= 0.14 \\ F_\mathrm{{cent}} &= {0} \end{{split}} </script><script type="math/tex; mode=display">\begin{{split}} """.format(Fcent) result += r'k_\infty(T) &= {0!s} \\'.format(getArrheniusJSMath( kinetics.arrheniusHigh.A.value_si * kfactor, kunits, kinetics.arrheniusHigh.n.value_si, '', kinetics.arrheniusHigh.Ea.value_si * Efactor, Eunits, kinetics.arrheniusHigh.T0.value_si * Tfactor, Tunits, )) result += r'k_0(T) &= {0!s} \\'.format(getArrheniusJSMath( kinetics.arrheniusLow.A.value_si * kfactor * kfactor, kunits_low, kinetics.arrheniusLow.n.value_si, '', kinetics.arrheniusLow.Ea.value_si * Efactor, Eunits, kinetics.arrheniusLow.T0.value_si * Tfactor, Tunits, )) result += r'\alpha &= {0:g} \\'.format(kinetics.alpha) result += r'T_3 &= {0:g} \ \mathrm{{ {1!s} }} \\'.format(kinetics.T3.value_si * Tfactor, Tunits) result += r'T_1 &= {0:g} \ \mathrm{{ {1!s} }} \\'.format(kinetics.T1.value_si * Tfactor, Tunits) if kinetics.T2 is not None: result += r'T_2 &= {0:g} \ \mathrm{{ {1!s} }} \\'.format(kinetics.T2.value_si * Tfactor, Tunits) result += r'\end{split}</script>' elif isinstance(kinetics, Lindemann): # The kinetics is in Lindemann format result += r"""<script type="math/tex; mode=display"> \begin{{split}} k(T,P) &= k_\infty(T) \left[ \frac{{P_\mathrm{{r}}}}{{1 + P_\mathrm{{r}}}} \right] \\ P_\mathrm{{r}} &= \frac{{k_0(T)}}{{k_\infty(T)}} [\mathrm{{M}}] \\ \end{{split}} </script><script type="math/tex; mode=display">\begin{{split}} """.format() result += r'k_\infty(T) &= {0!s} \\'.format(getArrheniusJSMath( kinetics.arrheniusHigh.A.value_si * kfactor, kunits, kinetics.arrheniusHigh.n.value_si, '', kinetics.arrheniusHigh.Ea.value_si * Efactor, Eunits, kinetics.arrheniusHigh.T0.value_si * Tfactor, Tunits, )) result += r'k_0(T) &= {0!s} \\'.format(getArrheniusJSMath( kinetics.arrheniusLow.A.value_si * kfactor * kfactor, kunits_low, kinetics.arrheniusLow.n.value_si, '', kinetics.arrheniusLow.Ea.value_si * Efactor, Eunits, kinetics.arrheniusLow.T0.value_si * Tfactor, Tunits, )) result += r'\end{split}</script>' elif isinstance(kinetics, ThirdBody): # The kinetics is in ThirdBody format result += r"""<script type="math/tex; mode=display"> k(T,P) = k_0(T) [\mathrm{{M}}] </script><script type="math/tex; mode=display"> """.format() result += r'k_0(T) = {0!s}'.format(getArrheniusJSMath( kinetics.arrheniusLow.A.value_si * kfactor * kfactor, kunits_low, kinetics.arrheniusLow.n.value_si, '', kinetics.arrheniusLow.Ea.value_si * Efactor, Eunits, kinetics.arrheniusLow.T0.value_si * Tfactor, Tunits, )) result += '</script>' elif isinstance(kinetics, (MultiArrhenius, MultiPDepArrhenius)): # The kinetics is in MultiArrhenius or MultiPDepArrhenius format result = '' start = r'<script type="math/tex; mode=display">k(T, P) = ' for i, k in enumerate(kinetics.arrhenius): res = render_kinetics_math(k, user=user) start += 'k_{{ {0:d} }}(T, P) + '.format(i+1) result += res.replace('k(T', 'k_{{ {0:d} }}(T'.format(i+1)) + '<br/>' result = start[:-3] + '</script><br/>' + result # Collision efficiencies if hasattr(kinetics, 'efficiencies') and kinetics.efficiencies: result += '<table>\n' result += '<tr><th colspan="2">Collision efficiencies</th></tr>' for smiles, eff in kinetics.efficiencies.items(): result += '<tr><td>{0}</td><td>{1:g}</td></tr>\n'.format(getStructureMarkup(smiles), eff) result += '</table><br/>\n' # Temperature and pressure ranges result += '<table class="kineticsEntryData">' if kinetics.Tmin is not None and kinetics.Tmax is not None: result += '<tr><td class="key">Temperature range</td><td class="equals">=</td><td class="value">{0:g} to {1:g} {2!s}</td></tr>'.format(kinetics.Tmin.value_si * Tfactor, kinetics.Tmax.value_si * Tfactor, Tunits) if kinetics.Pmin is not None and kinetics.Pmax is not None: result += '<tr><td class="key">Pressure range</td><td class="equals">=</td><td class="value">{0:g} to {1:g} {2!s}</td></tr>'.format(kinetics.Pmin.value_si * Pfactor, kinetics.Pmax.value_si * Pfactor, Punits) result += '</table>' return mark_safe(result)
def get_thermo_data(thermo, user=None): """ Generate and return a set of thermodynamics data suitable for plotting using Highcharts. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. """ if not isinstance(thermo, (ThermoData, Wilhoit, NASA)): return '' # Define other units and conversion factors to use if user and user.is_authenticated(): user_profile = UserProfile.objects.get(user=user) Tunits = str(user_profile.temperatureUnits) Punits = str(user_profile.pressureUnits) Cpunits = str(user_profile.heatCapacityUnits) Hunits = str(user_profile.energyUnits) Sunits = str(user_profile.heatCapacityUnits) Gunits = str(user_profile.energyUnits) else: Tunits = 'K' Punits = 'bar' Cpunits = 'cal/(mol*K)' Hunits = 'kcal/mol' Sunits = 'cal/(mol*K)' Gunits = 'kcal/mol' Tfactor = Quantity(1, Tunits).getConversionFactorFromSI() Pfactor = Quantity(1, Punits).getConversionFactorFromSI() Cpfactor = Quantity(1, Cpunits).getConversionFactorFromSI() Hfactor = Quantity(1, Hunits).getConversionFactorFromSI() Sfactor = Quantity(1, Sunits).getConversionFactorFromSI() Gfactor = Quantity(1, Gunits).getConversionFactorFromSI() if thermo.Tmin is not None and thermo.Tmax is not None: Tmin = thermo.Tmin.value_si Tmax = thermo.Tmax.value_si elif isinstance(thermo, ThermoData) and (thermo.Cp0 is None or thermo.CpInf is None): Tmin = 300 Tmax = 1500 else: Tmin = 300 Tmax = 2000 Tdata = []; Cpdata = []; Hdata = []; Sdata = []; Gdata = [] try: for T in numpy.arange(Tmin, Tmax+1, 10): Tdata.append(T * Tfactor) Cpdata.append(thermo.getHeatCapacity(T) * Cpfactor) Hdata.append(thermo.getEnthalpy(T) * Hfactor) Sdata.append(thermo.getEntropy(T) * Sfactor) Gdata.append(thermo.getFreeEnergy(T) * Gfactor) return mark_safe(""" Tlist = {0}; Cplist = {1}; Hlist = {2}; Slist = {3}; Glist = {4}; Tunits = "{5!s}"; Cpunits = "{6!s}"; Hunits = "{7!s}"; Sunits = "{8!s}"; Gunits = "{9!s}"; """.format( Tdata, Cpdata, Hdata, Sdata, Gdata, Tunits, Cpunits, Hunits, Sunits, Gunits, )) except: # don't fail completely if thermo data is incomplete return ''
def get_rate_coefficients(kinetics, user=None): """ Generate and return a set of :math:`k(T,P)` data suitable for plotting using Highcharts. If a `user` is specified, the user's preferred units will be used; otherwise default units will be used. If `user=='A_n_Ea'` then it fits an Arrhenius expression and returns the parameters (and their units). """ if kinetics is None: return "// There are no kinetics for this entry." if user == "A_n_Ea": # Not a user, but a request to just return the Arrhenius coefficients return_A_n_Ea = True user = None else: return_A_n_Ea = False # Define other units and conversion factors to use if user and user.is_authenticated: user_profile = UserProfile.objects.get(user=user) Tunits = user_profile.temperature_units Punits = user_profile.pressure_units Eunits = user_profile.energy_units else: Tunits = 'K' Punits = 'Pa' Eunits = 'J/mol' kunits, kunits_low, kfactor = getRateCoefficientUnits(kinetics, user=user) Tfactor = Quantity(1, Tunits).get_conversion_factor_from_si() Pfactor = Quantity(1, Punits).get_conversion_factor_from_si() Efactor = Quantity(1, Eunits).get_conversion_factor_from_si() # Generate data to use for plots Tdata = [] Pdata = [] kdata = [] if kinetics.Tmin is not None and kinetics.Tmax is not None: if kinetics.Tmin.value_si == kinetics.Tmax.value_si: Tmin = kinetics.Tmin.value_si - 5 Tmax = kinetics.Tmax.value_si + 5 else: Tmin = kinetics.Tmin.value_si Tmax = kinetics.Tmax.value_si else: Tmin = 300 Tmax = 2000 if kinetics.Pmin is not None and kinetics.Pmax is not None: Pmin = kinetics.Pmin.value_si Pmax = kinetics.Pmax.value_si else: Pmin = 1e3 Pmax = 1e7 # Number of points in Tlist (ten times that in Pdep's Tlist2) points = 50 for Tinv in np.linspace(1.0 / Tmax, 1.0 / Tmin, points): Tdata.append(1.0 / Tinv) if kinetics.is_pressure_dependent(): for logP in np.arange(math.log10(Pmin), math.log10(Pmax)+0.001, 1): Pdata.append(10**logP) for P in Pdata: klist = [] for T in Tdata: klist.append(kinetics.get_rate_coefficient(T, P) * kfactor) kdata.append(klist) elif isinstance(kinetics, (ArrheniusEP, ArrheniusBM)): for T in Tdata: kdata.append(kinetics.get_rate_coefficient(T, dHrxn=0) * kfactor) elif isinstance(kinetics, (StickingCoefficient, StickingCoefficientBEP)): for T in Tdata: kdata.append(kinetics.get_sticking_coefficient(T) * kfactor) else: for T in Tdata: kdata.append(kinetics.get_rate_coefficient(T) * kfactor) Tdata2 = [] Pdata2 = [] kdata2 = [] for Tinv in np.linspace(1.0 / Tmax, 1.0 / Tmin, points // 10): Tdata2.append(1.0 / Tinv) if kinetics.is_pressure_dependent(): for logP in np.arange(math.log10(Pmin), math.log10(Pmax)+0.001, 0.1): Pdata2.append(10**logP) for P in Pdata2: klist = [] for T in Tdata2: klist.append(kinetics.get_rate_coefficient(T, P) * kfactor) kdata2.append(klist) elif isinstance(kinetics, (ArrheniusEP, ArrheniusBM)): for T in Tdata2: kdata2.append(kinetics.get_rate_coefficient(T, dHrxn=0) * kfactor) elif isinstance(kinetics, (StickingCoefficient, StickingCoefficientBEP)): for T in Tdata: kdata2.append(kinetics.get_sticking_coefficient(T) * kfactor) else: for T in Tdata2: kdata2.append(kinetics.get_rate_coefficient(T) * kfactor) if return_A_n_Ea: "We are only interested in the (fitted) Arrhenius parameters (and their units)" Tlist = np.array([T * Tfactor for T in Tdata], np.float64) if kinetics.is_pressure_dependent(): # Use the highest pressure we have available klist = np.array(kdata[-1], np.float64) pressure_note = " (At {0} {1})".format(Pdata[-1], Punits) k_model = Arrhenius().fit_to_data(Tlist, klist, kunits) elif isinstance(kinetics, (StickingCoefficient, StickingCoefficientBEP)): klist = np.array(kdata, np.float64) pressure_note = "" k_model = StickingCoefficient().fit_to_data(Tlist, klist, kunits) elif isinstance(kinetics, (SurfaceArrhenius, SurfaceArrheniusBEP)): klist = np.array(kdata, np.float64) pressure_note = "" k_model = SurfaceArrhenius().fit_to_data(Tlist, klist, kunits) else: klist = np.array(kdata, np.float64) pressure_note = "" k_model = Arrhenius().fit_to_data(Tlist, klist, kunits) return mark_safe("""A = {0}; n = {1}; Ea = {2}; Aunits = "{3}"; Eunits = "{4}"; Pnote = "{5}";""".format( k_model.A.value_si * kfactor, k_model.n.value_si, k_model.Ea.value_si * Efactor, kunits, Eunits, pressure_note )) return mark_safe("""Tlist = {0};Plist = {1};klist = {2}; Tlist2 = {3};Plist2 = {4}; klist2 = {5}; Tunits = "{6}";Punits = "{7}";kunits = "{8}";""".format( [T * Tfactor for T in Tdata], [P * Pfactor for P in Pdata], kdata, [T * Tfactor for T in Tdata2], [P * Pfactor for P in Pdata2], kdata2, Tunits, Punits, kunits, ))
def sensitivityAnalysis(self, initialMoleFractions, sensitiveSpecies, T, P, terminationTime, sensitivityThreshold=1e-3, number=10, fileformat='.png'): """ Run sensitivity analysis using the RMG solver in a single ReactionSystem object initialMoleFractions is a dictionary with Species objects as keys and mole fraction initial conditions sensitiveSpecies is a list of sensitive Species objects number is the number of top species thermo or reaction kinetics desired to be plotted """ from rmgpy.solver import SimpleReactor, TerminationTime from rmgpy.quantity import Quantity from rmgpy.tools.simulate import plot_sensitivity from rmgpy.rmg.listener import SimulationProfileWriter, SimulationProfilePlotter from rmgpy.rmg.settings import ModelSettings, SimulatorSettings T = Quantity(T) P = Quantity(P) termination = [TerminationTime(Quantity(terminationTime))] reactionSystem = SimpleReactor(T, P, initialMoleFractions, termination, sensitiveSpecies, sensitivityThreshold) # Create the csv worksheets for logging sensitivity util.makeOutputSubdirectory(self.outputDirectory, 'solver') sensWorksheet = [] reactionSystemIndex = 0 for spec in reactionSystem.sensitiveSpecies: csvfilePath = os.path.join( self.outputDirectory, 'solver', 'sensitivity_{0}_SPC_{1}.csv'.format(reactionSystemIndex + 1, spec.index)) sensWorksheet.append(csvfilePath) reactionSystem.attach( SimulationProfileWriter(self.outputDirectory, reactionSystemIndex, self.speciesList)) reactionSystem.attach( SimulationProfilePlotter(self.outputDirectory, reactionSystemIndex, self.speciesList)) simulatorSettings = SimulatorSettings() #defaults modelSettings = ModelSettings() #defaults modelSettings.fluxToleranceMoveToCore = 0.1 modelSettings.fluxToleranceInterrupt = 1.0 modelSettings.fluxToleranceKeepInEdge = 0.0 reactionSystem.simulate( coreSpecies=self.speciesList, coreReactions=self.reactionList, edgeSpecies=[], edgeReactions=[], surfaceSpecies=[], surfaceReactions=[], modelSettings=modelSettings, simulatorSettings=simulatorSettings, sensitivity=True, sensWorksheet=sensWorksheet, ) plot_sensitivity(self.outputDirectory, reactionSystemIndex, reactionSystem.sensitiveSpecies, number=number, fileformat=fileformat)
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 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 liquidReactor(temperature, initialConcentrations, terminationConversion=None, nSimsTerm = 4, terminationTime=None, terminationRateRatio=None, sensitivity=None, sensitivityThreshold=1e-3, sensitivityTemperature=None, sensitivityConcentrations=None, constantSpecies=None): logging.debug('Found LiquidReactor reaction system') 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] for spec,conc in initialConcentrations.iteritems(): if not isinstance(conc,list): concentration = Quantity(conc) # check the dimensions are ok # convert to mol/m^3 (or something numerically nice? or must it be SI) initialConcentrations[spec] = concentration.value_si else: if len(conc) != 2: raise InputError("Concentration values must either be in the form of (number,units) or a list with 2 entries of the same format") initialConcentrations[spec] = [Quantity(conc[0]),Quantity(conc[1])] if not isinstance(temperature,list) and all([not isinstance(x,list) for x in initialConcentrations.itervalues()]): 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: for spec in sensitivity: sensitiveSpecies.append(speciesDict[spec]) ##chatelak: check the constant species exist if constantSpecies is not None: logging.debug(' Generation with constant species:') for constantSpecie in constantSpecies: logging.debug(" {0}".format(constantSpecie)) if not speciesDict.has_key(constantSpecie): raise InputError('Species {0} not found in the input file'.format(constantSpecie)) if not isinstance(T,list): sensitivityTemperature = T if not any([isinstance(x,list) for x in initialConcentrations.itervalues()]): sensitivityConcentrations = initialConcentrations if sensitivityConcentrations is None or sensitivityTemperature is None: sensConditions = None else: sensConditions = sensitivityConcentrations sensConditions['T'] = Quantity(sensitivityTemperature).value_si system = LiquidReactor(T, initialConcentrations, nSimsTerm, termination, sensitiveSpecies, sensitivityThreshold, sensConditions, constantSpecies) rmg.reactionSystems.append(system)