Ejemplo n.º 1
0
 def setUp(self):
     """
     A function run before each unit test in this class.
     """
     from rmgpy.chemkin import loadChemkinFile
     folder = os.path.join(os.path.dirname(rmgpy.__file__),'tools/data/various_kinetics')
     
     chemkinPath = os.path.join(folder, 'chem_annotated.inp')
     dictionaryPath = os.path.join(folder, 'species_dictionary.txt')
     transportPath = os.path.join(folder, 'tran.dat')
     
     species, reactions = loadChemkinFile(chemkinPath, dictionaryPath,transportPath) 
     
     self.rmg_ctSpecies = [spec.toCantera(useChemkinIdentifier = True) for spec in species]
     self.rmg_ctReactions = []
     for rxn in reactions:
         convertedReactions = rxn.toCantera(species, useChemkinIdentifier = True)
         if isinstance(convertedReactions,list):
             self.rmg_ctReactions.extend(convertedReactions)
         else:
             self.rmg_ctReactions.append(convertedReactions)
     job = Cantera()
     job.loadChemkinModel(chemkinPath, transportFile=transportPath,quiet=True)
     self.ctSpecies = job.model.species()
     self.ctReactions = job.model.reactions()
Ejemplo n.º 2
0
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        from rmgpy.chemkin import load_chemkin_file
        folder = os.path.join(os.path.dirname(rmgpy.__file__),
                              'tools/data/various_kinetics')

        chemkin_path = os.path.join(folder, 'chem_annotated.inp')
        dictionary_path = os.path.join(folder, 'species_dictionary.txt')
        transport_path = os.path.join(folder, 'tran.dat')

        species, reactions = load_chemkin_file(chemkin_path, dictionary_path,
                                               transport_path)

        self.rmg_ctSpecies = [
            spec.to_cantera(use_chemkin_identifier=True) for spec in species
        ]
        self.rmg_ctReactions = []
        for rxn in reactions:
            converted_reactions = rxn.to_cantera(species,
                                                 use_chemkin_identifier=True)
            if isinstance(converted_reactions, list):
                self.rmg_ctReactions.extend(converted_reactions)
            else:
                self.rmg_ctReactions.append(converted_reactions)
        job = Cantera()
        job.load_chemkin_model(chemkin_path,
                               transport_file=transport_path,
                               quiet=True)
        self.ctSpecies = job.model.species()
        self.ctReactions = job.model.reactions()
Ejemplo n.º 3
0
    def __init__(self,
                 title='',
                 old_dir='',
                 new_dir='',
                 observables=None,
                 expt_data=None,
                 ck2cti=True):
        self.title = title
        self.new_dir = new_dir
        self.old_dir = old_dir
        self.conditions = None
        self.expt_data = expt_data if expt_data else []
        self.observables = observables if observables else {}

        # Detect if the transport file exists
        old_transport_path = None
        if os.path.exists(os.path.join(old_dir, 'tran.dat')):
            old_transport_path = os.path.join(old_dir, 'tran.dat')
        new_transport_path = None
        if os.path.exists(os.path.join(new_dir, 'tran.dat')):
            new_transport_path = os.path.join(new_dir, 'tran.dat')

        # load the species and reactions from each model
        old_species_list, old_reaction_list = load_chemkin_file(
            os.path.join(old_dir, 'chem_annotated.inp'),
            os.path.join(old_dir, 'species_dictionary.txt'),
            old_transport_path)

        new_species_list, new_reaction_list = load_chemkin_file(
            os.path.join(new_dir, 'chem_annotated.inp'),
            os.path.join(new_dir, 'species_dictionary.txt'),
            new_transport_path)

        self.old_sim = Cantera(species_list=old_species_list,
                               reaction_list=old_reaction_list,
                               output_directory=old_dir)
        self.new_sim = Cantera(species_list=new_species_list,
                               reaction_list=new_reaction_list,
                               output_directory=new_dir)

        # load each chemkin file into the cantera model
        if not ck2cti:
            self.old_sim.load_model()
            self.new_sim.load_model()
        else:
            self.old_sim.load_chemkin_model(os.path.join(
                old_dir, 'chem_annotated.inp'),
                                            transport_file=old_transport_path,
                                            quiet=True)
            self.new_sim.load_chemkin_model(os.path.join(
                new_dir, 'chem_annotated.inp'),
                                            transport_file=new_transport_path,
                                            quiet=True)
Ejemplo n.º 4
0
    def __init__(self,
                 title='',
                 oldDir='',
                 newDir='',
                 observables={},
                 exptData=[],
                 ck2cti=True):
        self.title = title
        self.newDir = newDir
        self.oldDir = oldDir
        self.conditions = None
        self.exptData = exptData
        self.observables = observables

        # Detect if the transport file exists
        oldTransportPath = None
        if os.path.exists(os.path.join(oldDir, 'tran.dat')):
            oldTransportPath = os.path.join(oldDir, 'tran.dat')
        newTransportPath = None
        if os.path.exists(os.path.join(newDir, 'tran.dat')):
            newTransportPath = os.path.join(newDir, 'tran.dat')

        # load the species and reactions from each model
        oldSpeciesList, oldReactionList = loadChemkinFile(
            os.path.join(oldDir, 'chem_annotated.inp'),
            os.path.join(oldDir, 'species_dictionary.txt'), oldTransportPath)

        newSpeciesList, newReactionList = loadChemkinFile(
            os.path.join(newDir, 'chem_annotated.inp'),
            os.path.join(newDir, 'species_dictionary.txt'), newTransportPath)

        self.oldSim = Cantera(speciesList=oldSpeciesList,
                              reactionList=oldReactionList,
                              outputDirectory=oldDir)
        self.newSim = Cantera(speciesList=newSpeciesList,
                              reactionList=newReactionList,
                              outputDirectory=newDir)

        # load each chemkin file into the cantera model
        if not ck2cti:
            self.oldSim.loadModel()
            self.newSim.loadModel()
        else:
            self.oldSim.loadChemkinModel(os.path.join(oldDir,
                                                      'chem_annotated.inp'),
                                         transportFile=oldTransportPath,
                                         quiet=True)
            self.newSim.loadChemkinModel(os.path.join(newDir,
                                                      'chem_annotated.inp'),
                                         transportFile=newTransportPath,
                                         quiet=True)
Ejemplo n.º 5
0
    def __init__(self, title='', oldDir='', newDir='', observables = {}, exptData = [], ck2cti=True):
        self.title=title
        self.newDir=newDir
        self.oldDir=oldDir
        self.conditions=None
        self.exptData=exptData
        self.observables=observables

        # Detect if the transport file exists
        oldTransportPath = None
        if os.path.exists(os.path.join(oldDir,'tran.dat')):
            oldTransportPath = os.path.join(oldDir,'tran.dat')
        newTransportPath = None
        if os.path.exists(os.path.join(newDir,'tran.dat')):
            newTransportPath = os.path.join(newDir,'tran.dat')

        # load the species and reactions from each model
        oldSpeciesList, oldReactionList = loadChemkinFile(os.path.join(oldDir,'chem_annotated.inp'),
                                                          os.path.join(oldDir,'species_dictionary.txt'),
                                                          oldTransportPath)

        newSpeciesList, newReactionList = loadChemkinFile(os.path.join(newDir,'chem_annotated.inp'),
                                                          os.path.join(newDir,'species_dictionary.txt'),
                                                          newTransportPath)

        self.oldSim = Cantera(speciesList = oldSpeciesList,
                              reactionList = oldReactionList,
                              outputDirectory = oldDir)
        self.newSim = Cantera(speciesList = newSpeciesList,
                              reactionList = newReactionList,
                              outputDirectory = newDir)
        
        # load each chemkin file into the cantera model
        if not ck2cti:
            self.oldSim.loadModel()
            self.newSim.loadModel()
        else:
            self.oldSim.loadChemkinModel(os.path.join(oldDir,'chem_annotated.inp'), transportFile=oldTransportPath, quiet=True)
            self.newSim.loadChemkinModel(os.path.join(newDir,'chem_annotated.inp'), transportFile=newTransportPath, quiet=True)
Ejemplo n.º 6
0
    def __init__(self, title='', oldDir='', newDir='', observables = {}, exptData = []):
        self.title=title
        self.newDir=newDir
        self.oldDir=oldDir
        self.conditions=None
        self.exptData=exptData
        self.observables=observables

        # load the species and reactions from each model
        oldSpeciesList, oldReactionList = loadChemkinFile(os.path.join(oldDir,'chem_annotated.inp'),
                                                          os.path.join(oldDir,'species_dictionary.txt'))

        newSpeciesList, newReactionList = loadChemkinFile(os.path.join(newDir,'chem_annotated.inp'),
                                                          os.path.join(newDir,'species_dictionary.txt'))
        self.oldSim = Cantera(speciesList = oldSpeciesList,
                              reactionList = oldReactionList,
                              outputDirectory = oldDir)
        self.newSim = Cantera(speciesList = newSpeciesList,
                              reactionList = newReactionList,
                              outputDirectory = newDir)
        
        # load each chemkin file into the cantera model
        self.oldSim.loadChemkinModel(os.path.join(oldDir,'chem_annotated.inp'))
        self.newSim.loadChemkinModel(os.path.join(newDir,'chem_annotated.inp'))
Ejemplo n.º 7
0
class ObservablesTestCase:
    """
    We use this class to run regressive tests

    ======================= ==============================================================================================
    Attribute               Description
    ======================= ==============================================================================================
    `title`                 A string describing the test. For regressive tests, should be same as example's name.
    `oldDir`                A directory path containing the chem_annotated.inp and species_dictionary.txt of the old model
    `newDir`                A directory path containing the chem_annotated.inp and species_dictionary.txt of the new model
    `conditions`            A list of the :class: 'CanteraCondition' objects describing reaction conditions
    `observables`           A dictionary of observables
                            key: 'species', value: a list of the "class" 'Species' that correspond with species mole fraction observables
                            key: 'variable', value: a list of state variable observables, i.e. ['Temperature'] or ['Temperature','Pressure']
                            key: 'ignitionDelay', value: a tuple containing (ignition metric, yVar)
                                                         for example: ('maxDerivative','P')
                                                                      ('maxHalfConcentration', '[OH]')
                                                                      ('maxSpeciesConcentrations',['[CH2]','[O]'])
                                                        see findIgnitionDelay function for more details
    'exptData'              An array of GenericData objects
    'ck2tci'                Indicates whether to convert chemkin to cti mechanism.  If set to False, RMG will convert the species
                            and reaction objects to Cantera objects internally
    ======================= ==============================================================================================


    """
    def __init__(self, title='', oldDir='', newDir='', observables = {}, exptData = [], ck2cti=True):
        self.title=title
        self.newDir=newDir
        self.oldDir=oldDir
        self.conditions=None
        self.exptData=exptData
        self.observables=observables

        # Detect if the transport file exists
        oldTransportPath = None
        if os.path.exists(os.path.join(oldDir,'tran.dat')):
            oldTransportPath = os.path.join(oldDir,'tran.dat')
        newTransportPath = None
        if os.path.exists(os.path.join(newDir,'tran.dat')):
            newTransportPath = os.path.join(newDir,'tran.dat')

        # load the species and reactions from each model
        oldSpeciesList, oldReactionList = loadChemkinFile(os.path.join(oldDir,'chem_annotated.inp'),
                                                          os.path.join(oldDir,'species_dictionary.txt'),
                                                          oldTransportPath)

        newSpeciesList, newReactionList = loadChemkinFile(os.path.join(newDir,'chem_annotated.inp'),
                                                          os.path.join(newDir,'species_dictionary.txt'),
                                                          newTransportPath)

        self.oldSim = Cantera(speciesList = oldSpeciesList,
                              reactionList = oldReactionList,
                              outputDirectory = oldDir)
        self.newSim = Cantera(speciesList = newSpeciesList,
                              reactionList = newReactionList,
                              outputDirectory = newDir)
        
        # load each chemkin file into the cantera model
        if not ck2cti:
            self.oldSim.loadModel()
            self.newSim.loadModel()
        else:
            self.oldSim.loadChemkinModel(os.path.join(oldDir,'chem_annotated.inp'), transportFile=oldTransportPath, quiet=True)
            self.newSim.loadChemkinModel(os.path.join(newDir,'chem_annotated.inp'), transportFile=newTransportPath, quiet=True)

    def __str__(self):
        """
        Return a string representation of this test case, using its title'.
        """
        return 'Observables Test Case: {0}'.format(self.title)

    def generateConditions(self, reactorTypeList, reactionTimeList, molFracList, Tlist=None, Plist=None, Vlist=None):
        """
        Creates a list of conditions from from the lists 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

        `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 both the old and new cantera jobs.
        """
        # Store the conditions in the observables test case, for bookkeeping
        self.conditions = generateCanteraConditions(reactorTypeList, reactionTimeList, molFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)

        # Map the mole fractions dictionaries to species objects from the old and new models
        oldMolFracList = []
        newMolFracList = []

        for molFracCondition in molFracList:
            oldCondition = {}
            newCondition = {} 
            oldSpeciesDict = getRMGSpeciesFromUserSpecies(molFracCondition.keys(), self.oldSim.speciesList)
            newSpeciesDict = getRMGSpeciesFromUserSpecies(molFracCondition.keys(), self.newSim.speciesList)
            for smiles, molfrac in molFracCondition.iteritems():
                if oldSpeciesDict[smiles] is None:
                    raise Exception('SMILES {0} was not found in the old model!'.format(smiles))
                if newSpeciesDict[smiles] is None:
                    raise Exception('SMILES {0} was not found in the new model!'.format(smiles))

                oldCondition[oldSpeciesDict[smiles]] = molfrac
                newCondition[newSpeciesDict[smiles]] = molfrac
            oldMolFracList.append(oldCondition)
            newMolFracList.append(newCondition)
        
        # Generate the conditions in each simulation
        self.oldSim.generateConditions(reactorTypeList, reactionTimeList, oldMolFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)
        self.newSim.generateConditions(reactorTypeList, reactionTimeList, newMolFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)

    def compare(self, tol, plot=False):
        """
        Compare the old and new model
        'tol':  average error acceptable between old and new model for variables
        `plot`: if set to True, it will comparison plots of the two models comparing their species.

        Returns a list of variables failed in a list of tuples in the format:
        
        (CanteraCondition, variable label, variableOld, variableNew)

        """
        # Ignore Inerts
        inertList = ['[Ar]','[He]','[N#N]','[Ne]']

        oldConditionData, newConditionData = self.runSimulations()

        conditionsBroken=[]
        variablesFailed=[]
        
        print ''
        print '{0} Comparison'.format(self)
        print '================'
        # Check the species profile observables
        if 'species' in self.observables:
            oldSpeciesDict = getRMGSpeciesFromUserSpecies(self.observables['species'], self.oldSim.speciesList)
            newSpeciesDict = getRMGSpeciesFromUserSpecies(self.observables['species'], self.newSim.speciesList)
        
        # Check state variable observables 
        implementedVariables = ['temperature','pressure']
        if 'variable' in self.observables:
            for item in self.observables['variable']:
                if item.lower() not in implementedVariables:
                    print 'Observable variable {0} not yet implemented'.format(item)
                    
        failHeader='\nThe following observables did not match:\n'
        failHeaderPrinted=False
        for i in range(len(oldConditionData)):
            timeOld, dataListOld = oldConditionData[i]
            timeNew, dataListNew = newConditionData[i]

            # Compare species observables
            if 'species' in self.observables:
                smilesList=[] #This is to make sure we don't have species with duplicate smiles
                multiplicityList=['','(S)','(D)','(T)','(Q)'] #list ot add multiplcity
                for species in self.observables['species']:

                    smiles=species.molecule[0].toSMILES() #For purpose of naming the plot only
                    if smiles in smilesList: smiles=smiles+multiplicityList[species.molecule[0].multiplicity]
                    smilesList.append(smiles)
                    
                    fail = False
                    oldRmgSpecies = oldSpeciesDict[species]
                    newRmgSpecies = newSpeciesDict[species]
                    
                    if oldRmgSpecies:
                        variableOld = next((data for data in dataListOld if data.species == oldRmgSpecies), None)
                    else:
                        print 'No RMG species found for observable species {0} in old model.'.format(smiles)
                        fail = True
                    if newRmgSpecies:
                        variableNew = next((data for data in dataListNew if data.species == newRmgSpecies), None)
                    else:
                        print 'No RMG species found for observable species {0} in new model.'.format(smiles)
                        fail = True
                    
                    if fail is False:
                        if not curvesSimilar(timeOld.data, variableOld.data, timeNew.data, variableNew.data, tol):
                            fail = True
                            
                        # Try plotting only when species are found in both models
                        if plot:
                            oldSpeciesPlot = SimulationPlot(xVar=timeOld, yVar=variableOld)
                            newSpeciesPlot = SimulationPlot(xVar=timeNew, yVar=variableNew)
                            oldSpeciesPlot.comparePlot(newSpeciesPlot,
                                                       title='Observable Species {0} Comparison'.format(smiles),
                                                       ylabel='Mole Fraction',
                                                       filename='condition_{0}_species_{1}.png'.format(i+1,smiles))
                    
                    # Append to failed variables or conditions if this test failed
                    if fail:
                        if not failHeaderPrinted:
                            print failHeader
                            failHeaderPrinted=True
                        if i not in conditionsBroken: conditionsBroken.append(i)
                        print "Observable species {0} varied by more than {1:.3f} on average between old model {2} and \
new model {3} in condition {4:d}.".format(smiles,
                                          tol,
                                           variableOld.label, 
                                           variableNew.label,
                                           i+1)
                        variablesFailed.append((self.conditions[i], smiles, variableOld, variableNew))
                    
            
            # Compare state variable observables
            if 'variable' in self.observables:
                for varName in self.observables['variable']:
                    variableOld = next((data for data in dataListOld if data.label == varName), None)
                    variableNew = next((data for data in dataListNew if data.label == varName), None)
                    if not curvesSimilar(timeOld.data, variableOld.data, timeNew.data, variableNew.data, 0.05):
                        if i not in conditionsBroken: conditionsBroken.append(i)
                        if not failHeaderPrinted:
                            failHeaderPrinted=True
                            print failHeader

                        print "Observable variable {0} varied by more than {1:.3f} on average between old model and \
new model in condition {2:d}.".format(variableOld.label, i+1)
                        variablesFailed.append((self.conditions[i], tol, varName, variableOld, variableNew))
                    
                    if plot:
                        oldVarPlot = GenericPlot(xVar=timeOld, yVar=variableOld)
                        newVarPlot = GenericPlot(xVar=timeNew, yVar=variableNew)
                        oldVarPlot.comparePlot(newSpeciesPlot,
                                                   title='Observable Variable {0} Comparison'.format(varName),
                                                   filename='condition_{0}_variable_{1}.png'.format(i+1, varName))
                        
            # Compare ignition delay observables
            if 'ignitionDelay' in self.observables:
                print 'Ignition delay observable comparison not implemented yet.'
                
                
        if failHeaderPrinted:
            print ''
            print 'The following reaction conditions were had some discrepancies:'
            print ''
            for index in conditionsBroken:
                print "Condition {0:d}:".format(index+1)
                print str(self.conditions[index])
                print ''

            return variablesFailed
        else:
            print ''
            print 'All Observables varied by less than {0:.3f} on average between old model and \
new model in all conditions!'.format(tol)
            print ''

    def runSimulations(self):
        """
        Run a selection of conditions in Cantera and return
        generic data objects containing the time, pressure, temperature,
        and mole fractions from the simulations.

        Returns (oldConditionData, newConditionData)
        where conditionData is a list of of tuples: (time, dataList) for each condition in the same order as conditions
        time is a GenericData object which gives the time domain for each profile
        dataList is a list of GenericData objects for the temperature, profile, and mole fraction of major species
        """
        oldConditionData = self.oldSim.simulate()
        newConditionData = self.newSim.simulate()
        return (oldConditionData, newConditionData)
Ejemplo n.º 8
0
def run_cantera_job(
    smiles_dictionary,
    specie_initial_mol_frac,
    final_time,
    temp_initial,
    initial_p,
    chemkin_file='',
    species_dictionary_file='',
    transport_file=None,
    reactor_type='IdealGasConstPressureTemperatureReactor',
    time_units='s',
    temp_units='K',
    p_units='atm',
    species_list=None,
    reaction_list=None,
):
    """General function for running Cantera jobs from chemkin files with common defaults

    =========================== =======================================================================
    Input (Required)            Description
    =========================== =======================================================================
    smiles_dictionary           A dictionary with user names as keys and SMILES strings as values
    specie_initial_mol_frac     A dictionary with user specie names as keys and mol fractions as values
    final_time                  Termination time for the simulation
    temp_initial                Initial temperature for the simulation
    initial_p                   Initial pressure for the simulation
    =========================== =======================================================================
    Inputs with Defaults        Description
    =========================== =======================================================================
    chemkin_file                String relative path of the chem.inp or chem_annotated.inp file
    species_dictionary_file     String relative path of species_dictionary file
    reactor_type                String with Cantera reactor type
    time_units                  Default is s (min and h are also supported)
    temp_units                  Default is K (C is also supported)
    p_units                     Default is atm (bar and Pa are also supported)
    =========================== =======================================================================
    Optional Inputs             Description
    =========================== =======================================================================
    transport_file              String relative path of trans.dat file
    species_list                Output from loadChemkinFile for faster simulation (otherwise generated)
    reaction_list               Output from loadChemkinFile for faster simulation (otherwise generated)
    ===================================================================================================


    =========================== =======================================================================
    Output                      Description
    =========================== =======================================================================
    all_data                    Cantera Simulation Data Object [time, [temp, pressure, spc1, spc2,..]]
    ===================================================================================================
    """
    logging.info(
        'Running a cantera job using the chemkin file {}'.format(chemkin_file))

    logging.debug('loading chemkin and species dictionary file')
    cwd = os.getcwd()
    if chemkin_file == '':
        chemkin_file = os.path.join(cwd, 'chem_annotated.inp')

    if species_dictionary_file == '':
        species_dictionary_file = os.path.join(cwd, 'species_dictionary.txt')

    user_species_dictionary = create_species_from_smiles(smiles_dictionary)
    specie_initial_mol_frac = set_species_mol_fractions(
        specie_initial_mol_frac, user_species_dictionary)

    if (not species_list) or (not reaction_list):
        (species_list,
         reaction_list) = loadChemkinFile(chemkin_file,
                                          species_dictionary_file)

    name_dictionary = getRMGSpeciesFromUserSpecies(
        user_species_dictionary.values(), species_list)

    mol_fractions = {}
    for (user_name, chemkin_name) in name_dictionary.iteritems():
        try:
            mol_fractions[chemkin_name] = specie_initial_mol_frac[user_name]
        except KeyError:
            logging.debug(
                '{} initial mol fractions set to 0'.format(user_name))

    if temp_units == 'C':
        temp_initial += 273.0

    temp_initial = ([temp_initial], 'K')
    initial_p = ([initial_p], p_units)

    job = Cantera(speciesList=species_list,
                  reactionList=reaction_list,
                  outputDirectory='')
    job.loadChemkinModel(chemkin_file, transportFile=transport_file)
    job.generateConditions([reactor_type], ([final_time], time_units),
                           [mol_fractions], temp_initial, initial_p)

    logging.debug('Starting Cantera Simulation')
    all_data = job.simulate()
    all_data = all_data[0]
    logging.info('Cantera Simulation Complete')

    logging.debug('Setting labels to user defined species labels')

    species_index = {}
    for i in range(len(species_list)):
        species_index[species_list[i]] = i + 2

    user_index = {}
    for (user_name, specie) in user_species_dictionary.iteritems():
        try:
            user_index[species_index[name_dictionary[specie]]] = user_name
        except KeyError:
            logging.info('{0} is not in the model for {1}'.format(
                user_name, chemkin_file))

    for (indices, user_label) in user_index.iteritems():
        try:
            all_data[1][indices].label = user_label
        except KeyError:
            pass

    return all_data
Ejemplo n.º 9
0
class ObservablesTestCase(object):
    """
    We use this class to run regressive tests

    ======================= ==============================================================================================
    Attribute               Description
    ======================= ==============================================================================================
    `title`                 A string describing the test. For regressive tests, should be same as example's name.
    `old_dir`               A directory path containing the chem_annotated.inp and species_dictionary.txt of the old model
    `new_dir`               A directory path containing the chem_annotated.inp and species_dictionary.txt of the new model
    `conditions`            A list of the :class: 'CanteraCondition' objects describing reaction conditions
    `observables`           A dictionary of observables
                            key: 'species', value: a list of the "class" 'Species' that correspond with species mole fraction observables
                            key: 'variable', value: a list of state variable observables, i.e. ['Temperature'] or ['Temperature','Pressure']
                            key: 'ignitionDelay', value: a tuple containing (ignition metric, y_var)
                                                         for example: ('maxDerivative','P')
                                                                      ('maxHalfConcentration', '[OH]')
                                                                      ('maxSpeciesConcentrations',['[CH2]','[O]'])
                                                        see find_ignition_delay function for more details
    'expt_data'             An array of GenericData objects
    'ck2tci'                Indicates whether to convert chemkin to cti mechanism.  If set to False, RMG will convert the species
                            and reaction objects to Cantera objects internally
    ======================= ==============================================================================================


    """
    def __init__(self,
                 title='',
                 old_dir='',
                 new_dir='',
                 observables=None,
                 expt_data=None,
                 ck2cti=True):
        self.title = title
        self.new_dir = new_dir
        self.old_dir = old_dir
        self.conditions = None
        self.expt_data = expt_data if expt_data else []
        self.observables = observables if observables else {}

        # Detect if the transport file exists
        old_transport_path = None
        if os.path.exists(os.path.join(old_dir, 'tran.dat')):
            old_transport_path = os.path.join(old_dir, 'tran.dat')
        new_transport_path = None
        if os.path.exists(os.path.join(new_dir, 'tran.dat')):
            new_transport_path = os.path.join(new_dir, 'tran.dat')

        # load the species and reactions from each model
        old_species_list, old_reaction_list = load_chemkin_file(
            os.path.join(old_dir, 'chem_annotated.inp'),
            os.path.join(old_dir, 'species_dictionary.txt'),
            old_transport_path)

        new_species_list, new_reaction_list = load_chemkin_file(
            os.path.join(new_dir, 'chem_annotated.inp'),
            os.path.join(new_dir, 'species_dictionary.txt'),
            new_transport_path)

        self.old_sim = Cantera(species_list=old_species_list,
                               reaction_list=old_reaction_list,
                               output_directory=old_dir)
        self.new_sim = Cantera(species_list=new_species_list,
                               reaction_list=new_reaction_list,
                               output_directory=new_dir)

        # load each chemkin file into the cantera model
        if not ck2cti:
            self.old_sim.load_model()
            self.new_sim.load_model()
        else:
            self.old_sim.load_chemkin_model(os.path.join(
                old_dir, 'chem_annotated.inp'),
                                            transport_file=old_transport_path,
                                            quiet=True)
            self.new_sim.load_chemkin_model(os.path.join(
                new_dir, 'chem_annotated.inp'),
                                            transport_file=new_transport_path,
                                            quiet=True)

    def __str__(self):
        """
        Return a string representation of this test case, using its title'.
        """
        return 'Observables Test Case: {0}'.format(self.title)

    def generate_conditions(self,
                            reactor_type_list,
                            reaction_time_list,
                            mol_frac_list,
                            Tlist=None,
                            Plist=None,
                            Vlist=None):
        """
        Creates a list of conditions from from the lists provided. 
        
        ======================= ====================================================
        Argument                Description
        ======================= ====================================================
        `reactor_type_list`     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

        `reaction_time_list`    A tuple object giving the ([list of reaction times], units)
        `mol_frac_list`         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 both the old and new cantera jobs.
        """
        # Store the conditions in the observables test case, for bookkeeping
        self.conditions = generate_cantera_conditions(reactor_type_list,
                                                      reaction_time_list,
                                                      mol_frac_list,
                                                      Tlist=Tlist,
                                                      Plist=Plist,
                                                      Vlist=Vlist)

        # Map the mole fractions dictionaries to species objects from the old and new models
        old_mol_frac_list = []
        new_mol_frac_list = []

        for mol_frac in mol_frac_list:
            old_condition = {}
            new_condition = {}
            old_species_dict = get_rmg_species_from_user_species(
                list(mol_frac.keys()), self.old_sim.species_list)
            new_species_dict = get_rmg_species_from_user_species(
                list(mol_frac.keys()), self.new_sim.species_list)
            for smiles, molfrac in mol_frac.items():
                if old_species_dict[smiles] is None:
                    raise Exception(
                        'SMILES {0} was not found in the old model!'.format(
                            smiles))
                if new_species_dict[smiles] is None:
                    raise Exception(
                        'SMILES {0} was not found in the new model!'.format(
                            smiles))

                old_condition[old_species_dict[smiles]] = molfrac
                new_condition[new_species_dict[smiles]] = molfrac
            old_mol_frac_list.append(old_condition)
            new_mol_frac_list.append(new_condition)

        # Generate the conditions in each simulation
        self.old_sim.generate_conditions(reactor_type_list,
                                         reaction_time_list,
                                         old_mol_frac_list,
                                         Tlist=Tlist,
                                         Plist=Plist,
                                         Vlist=Vlist)
        self.new_sim.generate_conditions(reactor_type_list,
                                         reaction_time_list,
                                         new_mol_frac_list,
                                         Tlist=Tlist,
                                         Plist=Plist,
                                         Vlist=Vlist)

    def compare(self, tol, plot=False):
        """
        Compare the old and new model
        'tol':  average error acceptable between old and new model for variables
        `plot`: if set to True, it will comparison plots of the two models comparing their species.

        Returns a list of variables failed in a list of tuples in the format:
        
        (CanteraCondition, variable label, variable_old, variable_new)

        """
        # Ignore Inerts
        inert_list = ['[Ar]', '[He]', '[N#N]', '[Ne]']

        old_condition_data, new_condition_data = self.run_simulations()

        conditions_broken = []
        variables_failed = []

        print('')
        print('{0} Comparison'.format(self))
        print('================')
        # Check the species profile observables
        if 'species' in self.observables:
            old_species_dict = get_rmg_species_from_user_species(
                self.observables['species'], self.old_sim.species_list)
            new_species_dict = get_rmg_species_from_user_species(
                self.observables['species'], self.new_sim.species_list)

        # Check state variable observables
        implemented_variables = ['temperature', 'pressure']
        if 'variable' in self.observables:
            for item in self.observables['variable']:
                if item.lower() not in implemented_variables:
                    print('Observable variable {0} not yet implemented'.format(
                        item))

        fail_header = '\nThe following observables did not match:\n'
        fail_header_printed = False
        for i in range(len(old_condition_data)):
            time_old, data_list_old, reaction_sensitivity_data_old = old_condition_data[
                i]
            time_new, data_list_new, reaction_sensitivity_data_new = new_condition_data[
                i]

            # Compare species observables
            if 'species' in self.observables:
                smiles_list = [
                ]  # This is to make sure we don't have species with duplicate smiles
                multiplicity_list = ['', '(S)', '(D)', '(T)',
                                     '(Q)']  # list ot add multiplcity
                for species in self.observables['species']:

                    smiles = species.molecule[0].to_smiles(
                    )  # For purpose of naming the plot only
                    if smiles in smiles_list:
                        smiles = smiles + multiplicity_list[
                            species.molecule[0].multiplicity]
                    smiles_list.append(smiles)

                    fail = False
                    old_rmg_species = old_species_dict[species]
                    new_rmg_species = new_species_dict[species]

                    if old_rmg_species:
                        variable_old = next(
                            (data for data in data_list_old
                             if data.species == old_rmg_species), None)
                    else:
                        print(
                            'No RMG species found for observable species {0} in old model.'
                            .format(smiles))
                        fail = True
                    if new_rmg_species:
                        variable_new = next(
                            (data for data in data_list_new
                             if data.species == new_rmg_species), None)
                    else:
                        print(
                            'No RMG species found for observable species {0} in new model.'
                            .format(smiles))
                        fail = True

                    if fail is False:
                        if not curves_similar(time_old.data, variable_old.data,
                                              time_new.data, variable_new.data,
                                              tol):
                            fail = True

                        # Try plotting only when species are found in both models
                        if plot:
                            old_species_plot = SimulationPlot(
                                x_var=time_old, y_var=variable_old)
                            new_species_plot = SimulationPlot(
                                x_var=time_new, y_var=variable_new)
                            old_species_plot.compare_plot(
                                new_species_plot,
                                title='Observable Species {0} Comparison'.
                                format(smiles),
                                ylabel='Mole Fraction',
                                filename='condition_{0}_species_{1}.png'.
                                format(i + 1, smiles))

                    # Append to failed variables or conditions if this test failed
                    if fail:
                        if not fail_header_printed:
                            print(fail_header)
                            fail_header_printed = True
                        if i not in conditions_broken:
                            conditions_broken.append(i)
                        print(
                            "Observable species {0} varied by more than {1:.3f} on average between old model {2} and "
                            "new model {3} in condition {4:d}.".format(
                                smiles, tol, variable_old.label,
                                variable_new.label, i + 1))
                        variables_failed.append((self.conditions[i], smiles,
                                                 variable_old, variable_new))

            # Compare state variable observables
            if 'variable' in self.observables:
                for varName in self.observables['variable']:
                    variable_old = next(
                        (data
                         for data in data_list_old if data.label == varName),
                        None)
                    variable_new = next(
                        (data
                         for data in data_list_new if data.label == varName),
                        None)
                    if not curves_similar(time_old.data, variable_old.data,
                                          time_new.data, variable_new.data,
                                          0.05):
                        if i not in conditions_broken:
                            conditions_broken.append(i)
                        if not fail_header_printed:
                            fail_header_printed = True
                            print(fail_header)

                        print(
                            "Observable variable {0} varied by more than {1:.3f} on average between old model and "
                            "new model in condition {2:d}.".format(
                                variable_old.label, tol, i + 1))
                        variables_failed.append((self.conditions[i], varName,
                                                 variable_old, variable_new))

                    if plot:
                        old_var_plot = GenericPlot(x_var=time_old,
                                                   y_var=variable_old)
                        new_var_plot = GenericPlot(x_var=time_new,
                                                   y_var=variable_new)
                        old_var_plot.compare_plot(
                            new_var_plot,
                            title='Observable Variable {0} Comparison'.format(
                                varName),
                            filename='condition_{0}_variable_{1}.png'.format(
                                i + 1, varName))

            # Compare ignition delay observables
            if 'ignitionDelay' in self.observables:
                print(
                    'Ignition delay observable comparison not implemented yet.'
                )

        if fail_header_printed:
            print('')
            print(
                'The following reaction conditions were had some discrepancies:'
            )
            print('')
            for index in conditions_broken:
                print("Condition {0:d}:".format(index + 1))
                print(str(self.conditions[index]))
                print('')

            return variables_failed
        else:
            print('')
            print(
                'All Observables varied by less than {0:.3f} on average between old model and '
                'new model in all conditions!'.format(tol))
            print('')

    def run_simulations(self):
        """
        Run a selection of conditions in Cantera and return
        generic data objects containing the time, pressure, temperature,
        and mole fractions from the simulations.

        Returns (old_condition_data, new_condition_data)
        where conditionData is a list of of tuples: (time, dataList) for each condition in the same order as conditions
        time is a GenericData object which gives the time domain for each profile
        dataList is a list of GenericData objects for the temperature, profile, and mole fraction of major species
        """
        old_condition_data = self.old_sim.simulate()
        new_condition_data = self.new_sim.simulate()
        return (old_condition_data, new_condition_data)
Ejemplo n.º 10
0
class ObservablesTestCase:
    """
    We use this class to run regressive tests

    ======================= ==============================================================================================
    Attribute               Description
    ======================= ==============================================================================================
    `title`                 A string describing the test. For regressive tests, should be same as example's name.
    `oldDir`                A directory path containing the chem_annotated.inp and species_dictionary.txt of the old model
    `newDir`                A directory path containing the chem_annotated.inp and species_dictionary.txt of the new model
    `conditions`            A list of the :class: 'Condition' objects describing reaction conditions
    `observables`           A dictionary of observables
                            key: 'species', value: a list of smiles that correspond with species mole fraction observables
                            key: 'variable', value: a list of state variable observables, i.e. ['Temperature'] or ['Temperature','Pressure']
                            key: 'ignitionDelay', value: a tuple containing (ignition metric, yVar)
                                                         for example: ('maxDerivative','P')
                                                                      ('maxHalfConcentration', '[OH]')
                                                                      ('maxSpeciesConcentrations',['[CH2]','[O]'])
                                                        see findIgnitionDelay function for more details
    'exptData'              An array of GenericData objects
    ======================= ==============================================================================================


    """
    def __init__(self, title='', oldDir='', newDir='', observables = {}, exptData = []):
        self.title=title
        self.newDir=newDir
        self.oldDir=oldDir
        self.conditions=None
        self.exptData=exptData
        self.observables=observables

        # load the species and reactions from each model
        oldSpeciesList, oldReactionList = loadChemkinFile(os.path.join(oldDir,'chem_annotated.inp'),
                                                          os.path.join(oldDir,'species_dictionary.txt'))

        newSpeciesList, newReactionList = loadChemkinFile(os.path.join(newDir,'chem_annotated.inp'),
                                                          os.path.join(newDir,'species_dictionary.txt'))
        self.oldSim = Cantera(speciesList = oldSpeciesList,
                              reactionList = oldReactionList,
                              outputDirectory = oldDir)
        self.newSim = Cantera(speciesList = newSpeciesList,
                              reactionList = newReactionList,
                              outputDirectory = newDir)
        
        # load each chemkin file into the cantera model
        self.oldSim.loadChemkinModel(os.path.join(oldDir,'chem_annotated.inp'))
        self.newSim.loadChemkinModel(os.path.join(newDir,'chem_annotated.inp'))

    def __str__(self):
        """
        Return a string representation of this test case, using its title'.
        """
        return 'Observables Test Case: {0}'.format(self.title)

    def generateConditions(self, reactorType, reactionTime, molFracList, Tlist=None, Plist=None, Vlist=None):
        """
        Creates a list of conditions from from the lists provided. 
        
        `reactorType`: a string indicating the Cantera reactor type
        `reactionTime`: ScalarQuantity object for time
        `molFracList`: a list of dictionaries containing species smiles and their mole fraction values
        `Tlist`: ArrayQuantity object of temperatures
        `Plist`: ArrayQuantity object of pressures
        `Vlist`: ArrayQuantity object of volumes
        
        This saves all the reaction conditions into both the old and new cantera jobs.
        """
        # Store the conditions in the observables test case, for bookkeeping
        self.conditions = generateCanteraConditions(reactorType, reactionTime, molFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)

        # Map the mole fractions dictionaries to species objects from the old and new models
        oldMolFracList = []
        newMolFracList = []

        for molFracCondition in molFracList:
            oldCondition = {}
            newCondition = {} 
            oldSpeciesDict = getRMGSpeciesFromSMILES(molFracCondition.keys(), self.oldSim.speciesList)
            newSpeciesDict = getRMGSpeciesFromSMILES(molFracCondition.keys(), self.newSim.speciesList)
            for smiles, molfrac in molFracCondition.iteritems():
                if oldSpeciesDict[smiles] is None:
                    raise Exception('SMILES {0} was not found in the old model!'.format(smiles))
                if newSpeciesDict[smiles] is None:
                    raise Exception('SMILES {0} was not found in the new model!'.format(smiles))

                oldCondition[oldSpeciesDict[smiles]] = molfrac
                newCondition[newSpeciesDict[smiles]] = molfrac
            oldMolFracList.append(oldCondition)
            newMolFracList.append(newCondition)
        
        # Generate the conditions in each simulation
        self.oldSim.generateConditions(reactorType, reactionTime, oldMolFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)
        self.newSim.generateConditions(reactorType, reactionTime, newMolFracList, Tlist=Tlist, Plist=Plist, Vlist=Vlist)

    def compare(self, plot=False):
        """
        Compare the old and new model
        `plot`: if set to True, it will comparison plots of the two models comparing their species.

        Returns a list of variables failed in a list of tuples in the format:
        
        (CanteraCondition, variable label, variableOld, variableNew)

        """
        # Ignore Inerts
        inertList = ['[Ar]','[He]','[N#N]','[Ne]']

        oldConditionData, newConditionData = self.runSimulations()

        conditionsBroken=[]
        variablesFailed=[]
        
        print ''
        print '{0} Comparison'.format(self)
        print '================'
        # Check the species profile observables
        if 'species' in self.observables:
            oldSpeciesDict = getRMGSpeciesFromSMILES(self.observables['species'], self.oldSim.speciesList)
            newSpeciesDict = getRMGSpeciesFromSMILES(self.observables['species'], self.newSim.speciesList)
        
        # Check state variable observables 
        implementedVariables = ['temperature','pressure']
        if 'variable' in self.observables:
            for item in self.observables['variable']:
                if item.lower() not in implementedVariables:
                    print 'Observable variable {0} not yet implemented'.format(item)
                    
        print ''
        print 'The following observables did not match:'
        print ''
        for i in range(len(oldConditionData)):
            timeOld, dataListOld = oldConditionData[i]
            timeNew, dataListNew = newConditionData[i]

            # Compare species observables
            if 'species' in self.observables:
                for smiles in self.observables['species']:
                    
                    fail = False
                    oldRmgSpecies = oldSpeciesDict[smiles]
                    newRmgSpecies = newSpeciesDict[smiles]
                    
                    if oldRmgSpecies:
                        variableOld = next((data for data in dataListOld if data.species == oldRmgSpecies), None)
                    else:
                        print 'No RMG species found for observable species {0} in old model.'.format(smiles)
                        fail = True
                    if newRmgSpecies:
                        variableNew = next((data for data in dataListNew if data.species == newRmgSpecies), None)
                    else:
                        print 'No RMG species found for observable species {0} in new model.'.format(smiles)
                        fail = True
                    
                    if fail is False:
                        if not curvesSimilar(timeOld.data, variableOld.data, timeNew.data, variableNew.data, 0.05):
                            fail = True
                            
                        # Try plotting only when species are found in both models
                        if plot:
                            oldSpeciesPlot = SimulationPlot(xVar=timeOld, yVar=variableOld)
                            newSpeciesPlot = SimulationPlot(xVar=timeNew, yVar=variableNew)
                            oldSpeciesPlot.comparePlot(newSpeciesPlot,
                                                       title='Observable Species {0} Comparison'.format(smiles),
                                                       ylabel='Mole Fraction',
                                                       filename='condition_{0}_species_{1}.png'.format(i+1,smiles))
                    
                    # Append to failed variables or conditions if this test failed
                    if fail:
                        if i not in conditionsBroken: conditionsBroken.append(i)
                        print "Observable species {0} does not match between old model {1} and \
new model {2} in condition {3:d}.".format(smiles,
                                           variableOld.label, 
                                           variableNew.label,
                                           i+1)
                        variablesFailed.append((self.conditions[i], smiles, variableOld, variableNew))
                    
            
            # Compare state variable observables
            if 'variable' in self.observables:
                for varName in self.observables['variable']:
                    variableOld = next((data for data in dataListOld if data.label == varName), None)
                    variableNew = next((data for data in dataListNew if data.label == varName), None)
                    if not curvesSimilar(timeOld.data, variableOld.data, timeNew.data, variableNew.data, 0.05):
                        if i not in conditionsBroken: conditionsBroken.append(i)
                        print "Observable variable {0} does not match between old model and \
new model in condition {1:d}.".format(variableOld.label, i+1)
                        variablesFailed.append((self.conditions[i], varName, variableOld, variableNew))
                    
                    if plot:
                        oldVarPlot = GenericPlot(xVar=timeOld, yVar=variableOld)
                        newVarPlot = GenericPlot(xVar=timeNew, yVar=variableNew)
                        oldVarPlot.comparePlot(newSpeciesPlot,
                                                   title='Observable Variable {0} Comparison'.format(varName),
                                                   filename='condition_{0}_variable_{1}.png'.format(i+1, varName))
                        
            # Compare ignition delay observables
            if 'ignitionDelay' in self.observables:
                print 'Ignition delay observable comparison not implemented yet.'
                
                
        
        print ''
        print 'The following reaction conditions were broken:'
        print ''
        for index in conditionsBroken:
            print "Condition {0:d}:".format(index+1)
            print str(self.conditions[index])
            print ''

        return variablesFailed

    def runSimulations(self):
        """
        Run a selection of conditions in Cantera and return
        generic data objects containing the time, pressure, temperature,
        and mole fractions from the simulations.

        Returns (oldConditionData, newConditionData)
        where conditionData is a list of of tuples: (time, dataList) for each condition in the same order as conditions
        time is a GenericData object which gives the time domain for each profile
        dataList is a list of GenericData objects for the temperature, profile, and mole fraction of major species
        """
        oldConditionData = self.oldSim.simulate()
        newConditionData = self.newSim.simulate()
        return (oldConditionData, newConditionData)