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 liquidReactor(temperature, initialConcentrations, terminationConversion=None, terminationTime=None, sensitivity=None, sensitivityThreshold=1e-3): logging.debug('Found LiquidReactor reaction system') T = Quantity(temperature) for spec, conc in initialConcentrations.iteritems(): 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 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 = LiquidReactor(T, initialConcentrations, termination, sensitiveSpecies, sensitivityThreshold) rmg.reactionSystems.append(system)
def mlEstimator(thermo=True, name='main', minHeavyAtoms=1, maxHeavyAtoms=None, H298UncertaintyCutoff=(3.0, 'kcal/mol'), S298UncertaintyCutoff=(2.0, 'cal/(mol*K)'), CpUncertaintyCutoff=(2.0, 'cal/(mol*K)')): from rmgpy.ml.estimator import MLEstimator # Currently only support thermo if thermo: models_path = os.path.join(settings['database.directory'], 'thermo', 'ml', name) if not os.path.exists(models_path): raise InputError( 'Cannot find ML models folder {}'.format(models_path)) H298_path = os.path.join(models_path, 'H298') S298_path = os.path.join(models_path, 'S298') Cp_path = os.path.join(models_path, 'Cp') rmg.ml_estimator = MLEstimator(H298_path, S298_path, Cp_path) uncertainty_cutoffs = dict(H298=Quantity(*H298UncertaintyCutoff), S298=Quantity(*S298UncertaintyCutoff), Cp=Quantity(*CpUncertaintyCutoff)) rmg.ml_settings = dict( min_heavy_atoms=minHeavyAtoms, max_heavy_atoms=maxHeavyAtoms, uncertainty_cutoffs=uncertainty_cutoffs, )
def renderMW(MW): """ Renders molecular weight from SI units to the regular g/mol units we are used to. """ mass = Quantity(MW, 'kg/mol').value multfactor = Quantity(1, 'g/mol').getConversionFactorFromSI() return mark_safe("{0:.2f}".format(mass * multfactor))
def reactorSetups(reactorTypes, temperatures, pressures, initialMoleFractionsList, terminationTimes): global setups terminationTimes = Quantity(terminationTimes) temperatures = Quantity(temperatures) pressures = Quantity(pressures) setups = [reactorTypes, temperatures, pressures, initialMoleFractionsList, terminationTimes]
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 energies(Emin=None, Emax=None, dE=None, count=None): global measure if dE is not None or count is not None: if dE is not None: measure.grainSize = Quantity(dE) if count is not None: measure.grainCount = count if Emin is not None and Emax is not None: measure.Emin = Quantity(Emin) measure.Emax = Quantity(Emax) else: raise InputError('Must specify either dE or count in energies() block.')
def pressureDependence( method, temperatures, pressures, maximumGrainSize=0.0, minimumNumberOfGrains=0, interpolation=None, maximumAtoms=None, ): from rmgpy.cantherm.pdep import PressureDependenceJob # Setting the pressureDependence attribute to non-None enables pressure dependence rmg.pressureDependence = PressureDependenceJob(network=None) # Process method rmg.pressureDependence.method = method # Process interpolation model if isinstance(interpolation, str): interpolation = (interpolation, ) if interpolation[0].lower() not in ("chebyshev", "pdeparrhenius"): raise InputError( "Interpolation model must be set to either 'Chebyshev' or 'PDepArrhenius'." ) rmg.pressureDependence.interpolationModel = interpolation # Process temperatures Tmin, Tmax, Tunits, Tcount = temperatures rmg.pressureDependence.Tmin = Quantity(Tmin, Tunits) rmg.pressureDependence.Tmax = Quantity(Tmax, Tunits) rmg.pressureDependence.Tcount = Tcount rmg.pressureDependence.generateTemperatureList() # Process pressures Pmin, Pmax, Punits, Pcount = pressures rmg.pressureDependence.Pmin = Quantity(Pmin, Punits) rmg.pressureDependence.Pmax = Quantity(Pmax, Punits) rmg.pressureDependence.Pcount = Pcount rmg.pressureDependence.generatePressureList() # Process grain size and count rmg.pressureDependence.maximumGrainSize = Quantity(maximumGrainSize) rmg.pressureDependence.minimumGrainCount = minimumNumberOfGrains # Process maximum atoms rmg.pressureDependence.maximumAtoms = maximumAtoms rmg.pressureDependence.activeJRotor = True rmg.pressureDependence.activeKRotor = True rmg.pressureDependence.rmgmode = True
def fitArrhenius(kineticsList, weights, Tlist, Tmin, Tmax): """ Fit a modified Arrhenius expression to the set of loaded kinetics `kineticsList` using the given array of temperatures `Tlist` in K. The `Tmin` and `Tmax` parameters specify the limits in K at which the fitted kinetics should be said to be valid. Returns the best-fit kinetics and the confidence interval (on a log scale). """ import scipy.stats Tdata = [] kdata = [] wdata = [] print 'Fitting modified Arrhenius kinetics...' for kinetics, weight in zip(kineticsList, weights): for n in range(len(Tlist)): if kinetics.isTemperatureValid(Tlist[n]): Tdata.append(Tlist[n]) kdata.append(kinetics.getRateCoefficient(Tlist[n])) wdata.append(weight) Tdata = numpy.array(Tdata, numpy.float) kdata = numpy.array(kdata, numpy.float) wdata = numpy.array(wdata, numpy.float) arrhenius = Arrhenius().fitToData(Tdata, kdata, kunits='m^3/(mol*s)', T0=300, weights=wdata) # Compute RMS error and confidence interval count = len(kdata) rmsError = 0 for T, k in zip(Tdata, kdata): rmsError += (math.log10(k) - math.log10(arrhenius.getRateCoefficient(T)))**2 rmsError = math.sqrt(rmsError / (count - 3)) ci = scipy.stats.t.ppf(0.975, count - 3) * rmsError # Adjust units of best-fit Arrhenius expression arrhenius.A.units = 'cm^3/(mol*s)' if len( forwardReaction.reactants) == 2 else 's^-1' arrhenius.Ea.units = 'kJ/mol' # Set Tmin and Tmax of best-fit Arrhenius expression arrhenius.Tmin = Quantity(Tmin, "K") arrhenius.Tmax = Quantity(Tmax, "K") return arrhenius, ci
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.sensitivity import plotSensitivity from rmgpy.rmg.listener import SimulationProfileWriter, SimulationProfilePlotter 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)) reactionSystem.simulate( coreSpecies = self.speciesList, coreReactions = self.reactionList, edgeSpecies = [], edgeReactions = [], toleranceKeepInEdge = 0, toleranceMoveToCore = 1, toleranceInterruptSimulation = 1, sensitivity = True, sensWorksheet = sensWorksheet, ) plotSensitivity(self.outputDirectory, reactionSystemIndex, reactionSystem.sensitiveSpecies, number=number, fileformat=fileformat)
def temperatures(Tlist=None, Tmin=None, Tmax=None, count=None): global measure if Tlist is not None: # We've been provided a list of specific temperatures to use measure.Tlist = Quantity(Tlist) measure.Tmin = Quantity(numpy.min(measure.Tlist.value_si),"K") measure.Tmax = Quantity(numpy.max(measure.Tlist.value_si),"K") elif Tmin is not None and Tmax is not None and count is not None: # We've been provided a temperature range and number of temperatures to use # We defer choosing the actual temperatures because they depend on the # choice of interpolation model measure.Tmin = Quantity(Tmin) measure.Tmax = Quantity(Tmax) measure.Tcount = count else: raise SyntaxError('Must specify either a list of temperatures or Tmin, Tmax, and count.')
def options(name='Seed', generateSeedEachIteration=True, 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 pressures(Plist=None, Pmin=None, Pmax=None, count=None): global measure if Plist is not None: # We've been provided a list of specific pressures to use measure.Plist = Quantity(Plist) measure.Pmin = Quantity(numpy.min(measure.Plist.value_si),"Pa") measure.Pmax = Quantity(numpy.max(measure.Plist.value_si),"Pa") elif Pmin is not None and Pmax is not None and count is not None: # We've been provided a pressures range and number of pressures to use # We defer choosing the actual pressures because they depend on the # choice of interpolation model measure.Pmin = Quantity(Pmin) measure.Pmax = Quantity(Pmax) measure.Pcount = count else: raise SyntaxError('Must specify either a list of pressures or Pmin, Pmax, and count.')
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 plotKinetics(request): """ Allows user to upload chemkin files to generate a plot of reaction kinetics. """ from rmgpy.quantity import Quantity from rmgweb.database.forms import RateEvaluationForm if request.method == 'POST': chemkin = Chemkin() chemkin.createDir() form = UploadChemkinForm(request.POST, request.FILES, instance=chemkin) rateForm = RateEvaluationForm(request.POST) eval = [] if rateForm.is_valid(): temperature = Quantity( rateForm.cleaned_data['temperature'], str(rateForm.cleaned_data['temperature_units'])).value_si pressure = Quantity( rateForm.cleaned_data['pressure'], str(rateForm.cleaned_data['pressure_units'])).value_si eval = [temperature, pressure] kineticsDataList = chemkin.getKinetics() if form.is_valid(): form.save() kineticsDataList = chemkin.getKinetics() return render_to_response( 'plotKineticsData.html', { 'kineticsDataList': kineticsDataList, 'plotWidth': 500, 'plotHeight': 400 + 15 * len(kineticsDataList), 'form': rateForm, 'eval': eval }, context_instance=RequestContext(request)) # Otherwise create the form else: chemkin = Chemkin() chemkin.deleteDir() form = UploadChemkinForm(instance=chemkin) return render_to_response('plotKinetics.html', {'form': form}, context_instance=RequestContext(request))
def pressureDependence( method, temperatures, pressures, maximumGrainSize=0.0, minimumNumberOfGrains=0, interpolation=None, maximumAtoms=None, ): from rmgpy.cantherm.pdep import PressureDependenceJob # Setting the pressureDependence attribute to non-None enables pressure dependence rmg.pressureDependence = PressureDependenceJob(network=None) # Process method rmg.pressureDependence.method = method # Process interpolation model rmg.pressureDependence.interpolationModel = interpolation # Process temperatures Tmin, Tmax, Tunits, Tcount = temperatures rmg.pressureDependence.Tmin = Quantity(Tmin, Tunits) rmg.pressureDependence.Tmax = Quantity(Tmax, Tunits) rmg.pressureDependence.Tcount = Tcount rmg.pressureDependence.generateTemperatureList() # Process pressures Pmin, Pmax, Punits, Pcount = pressures rmg.pressureDependence.Pmin = Quantity(Pmin, Punits) rmg.pressureDependence.Pmax = Quantity(Pmax, Punits) rmg.pressureDependence.Pcount = Pcount rmg.pressureDependence.generatePressureList() # Process grain size and count rmg.pressureDependence.maximumGrainSize = Quantity(maximumGrainSize) rmg.pressureDependence.minimumGrainCount = minimumNumberOfGrains # Process maximum atoms rmg.pressureDependence.maximumAtoms = maximumAtoms rmg.pressureDependence.activeJRotor = True rmg.pressureDependence.activeKRotor = True rmg.pressureDependence.rmgmode = True
def copy(self): """ Return a copy of the current MEASURE job. """ measure = MEASURE() measure.inputFile = self.inputFile measure.logFile = self.logFile measure.outputFile = self.outputFile measure.drawFile = self.drawFile if self.Tmin is not None: measure.Tmin = Quantity(self.Tmin) if self.Tmax is not None: measure.Tmax = Quantity(self.Tmax) measure.Tcount = self.Tcount if self.Pmin is not None: measure.Pmin = Quantity(self.Pmin) if self.Pmax is not None: measure.Pmax = Quantity(self.Pmax) measure.Pcount = self.Pcount if self.Emin is not None: measure.Emin = Quantity(self.Emin) if self.Emax is not None: measure.Emax = Quantity(self.Emax) if self.grainSize is not None: measure.grainSize = Quantity(self.grainSize) measure.grainCount = self.grainCount measure.method = self.method measure.model = self.model measure.network = self.network measure.Tlist = self.Tlist measure.Plist = self.Plist measure.Elist = self.Elist return measure
def test_repr(self): """ Test that the repr function for a CanteraCondition object can reconstitute the same object """ reactor_type = 'IdealGasReactor' mol_frac = {'CC': 0.05, '[Ar]': 0.95} P = (3, 'atm') T = (1500, 'K') termination_time = (5e-5, 's') condition = CanteraCondition(reactor_type, termination_time, mol_frac, T0=T, P0=P) repr_condition = eval(condition.__repr__()) self.assertEqual(repr_condition.T0.value_si, Quantity(T).value_si) self.assertEqual(repr_condition.P0.value_si, Quantity(P).value_si) self.assertEqual(repr_condition.V0, None) self.assertEqual(repr_condition.mol_frac, mol_frac)
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]' ]) print 'Running thermo sensitivity analysis using finite differences...' for index, species in enumerate(speciesList): species_index = index + 1 species_string = getSpeciesIdentifier(species) print '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 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 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, 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.rateCoefficientUnits 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).getConversionFactorFromSI() return kunits, kunits_low, kfactor
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, ignoreOverallFluxCriterion=False, maxNumSpecies=None, maxNumObjsPerIter=1, terminateAtMaxObjects=False, toleranceThermoKeepSpeciesInEdge=numpy.inf, dynamicsTimeScale=(0.0, 'sec')): """ 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, toleranceMoveEdgeReactionToCore, toleranceKeepInEdge, toleranceInterruptSimulation, toleranceMoveEdgeReactionToSurface, toleranceMoveSurfaceSpeciesToCore, toleranceMoveSurfaceReactionToCore, toleranceMoveEdgeReactionToSurfaceInterrupt, toleranceMoveEdgeReactionToCoreInterrupt, maximumEdgeSpecies, minCoreSizeForPrune, minSpeciesExistIterationsForPrune, filterReactions, ignoreOverallFluxCriterion, maxNumSpecies, maxNumObjsPerIter, terminateAtMaxObjects, toleranceThermoKeepSpeciesInEdge, Quantity(dynamicsTimeScale)))
def species(label='', E0=None, states=None, thermo=None, transportData=None, molecularWeight=0.0, collisionModel=None, SMILES='', InChI=''): global speciesDict if label == '': raise InputError('Missing "label" attribute in species() block.') spec = Species(label=label, states=states, thermo=thermo, E0=E0, molecularWeight=molecularWeight, transportData=transportData, collisionModel=collisionModel) if InChI != '': spec.molecule = [Molecule(InChI=InChI)] elif SMILES != '': spec.molecule = [Molecule(SMILES=SMILES)] speciesDict[label] = spec logging.debug('Found species "{0}"'.format(spec)) # If the molecular weight was not specified but the structure was, then # get the molecular weight from the structure if spec.molecularWeight.value_si == 0.0 and spec.molecule is not None and len(spec.molecule) > 0: spec.molecularWeight = Quantity(spec.molecule[0].getMolecularWeight(),"kg/mol")
def options(units='si', saveRestartPeriod=None, drawMolecules=False, generatePlots=False, saveSimulationProfiles=False, verboseComments=False, saveEdgeSpecies=False): rmg.units = units rmg.saveRestartPeriod = Quantity( saveRestartPeriod) if saveRestartPeriod else None rmg.drawMolecules = drawMolecules rmg.generatePlots = generatePlots rmg.saveSimulationProfiles = saveSimulationProfiles rmg.verboseComments = verboseComments rmg.saveEdgeSpecies = saveEdgeSpecies
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 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
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)
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 ''
# 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