def test_pmutt_list_to_dict(self): sum_obj1 = self.sum_class(num1=1, num2=2) sum_obj2 = self.sum_class(num1=2, num2=3) self.assertDictEqual( pmutt.pmutt_list_to_dict([sum_obj1, sum_obj2], key='num1'), { 1: sum_obj1, 2: sum_obj2 })
def organize_phases(phases_data, species=None, reactions=None, interactions=None): """Helper method to organize phase data for OpenMKM Parameters ---------- phases_data : list of dict Each element of the list corresponds to the data to initialize the phase. Each dictionary are keyword arguments. species : list of :class:`~pmutt.empirical.nasa.Nasa`, :class:`~pmutt.empirical.nasa.Nasa9` and/or :class:`~pmutt.empirical.shomate.Shomate` objects, optional Species with phases to include. Default is None. reactions : list of :class:`~pmutt.omkm.reaction.SurfaceReaction` objects, optional Reactions occuring on phases to include. Default is None. interactions : list of :class:`~pmutt.mixture.cov.PiecewiseCovEffect` objects, optional Lateral interactions to include. Default is None Returns ------- phases : list of :class:`~pmutt.cantera.phase.Phase` objects Phases organized using parameters. """ species_phases = get_species_phases(species) reactions_phases = get_reactions_phases(reactions) interactions_phases = \ get_interactions_phases(interactions=interactions, species=pmutt_list_to_dict(species)) phases = [] phase_kwargs = { 'species': species_phases, 'reactions': reactions_phases, 'interactions': interactions_phases } for phase_data in phases_data: # Pre-processing relevant data phase_name = phase_data['name'] phase_type = phase_data.pop('phase_type') # Add relevant data about species, reactions and interactions if present for attr_name, attr_values in phase_kwargs.items(): # Skip if no data has been provided for this attribute if attr_values is None: continue try: attr_value = attr_values[phase_name] except KeyError: # Skip if the phase is not present continue # Skip if the phase has no values assigned (occurs if attr_value is # a defaultdict(list)) if len(attr_value) == 0: continue # Assign the kwargs phase_data[attr_name] = attr_value phase_class = getattr(omkm_phases, phase_type) phase = phase_class(**phase_data) phases.append(phase) return phases
# - [thermdat](thermdat) Thermdat file used to initialize ``Nasa`` species # ## Initialize Species Used For Reaction # First, we need to describe our species as pMuTT objects. For this example, we will be importing the thermdat from the [combustion database by Berkeley](http://combustion.berkeley.edu/gri_mech/version30/files30/thermo30.dat). We will store the species in a dictionary for code clarity later on. # In[1]: from pprint import pprint from pmutt.io.thermdat import read_thermdat from pmutt import pmutt_list_to_dict # The output will be a list species_list = read_thermdat(filename='thermdat') # This function converts the list to a dict for easier usage downstream species_dict = pmutt_list_to_dict(pmutt_list=species_list, key='name') # (Optional) Print the species_dict to see what's in it pprint(species_dict) # To calculate transition state properties, we will need to represent the transition state species as a pMuTT object. For this example, we will create a new ``Nasa`` object based on the H2O entry but modify the a6 parameter arbitrarily to give it a higher enthalpy. # In[2]: from copy import deepcopy # Make a copy so we don't edit the original H2O H2O_TS = deepcopy(species_dict['H2O']) # Change name to differentiate it H2O_TS.name = 'H2O_TS'
# [0]: https://vlachosgroup.github.io/pmutt/io.html#pmutt.io.thermdat.read_thermdat # ## Reactions # You can also evaluate reactions properties. The most straightforward way to do this is to initialize using strings. # In[15]: from pmutt.io.thermdat import read_thermdat from pmutt import pmutt_list_to_dict from pmutt.reaction import Reaction # Get a dictionary of species thermdat_H2O_path = os.path.join(notebook_folder, 'thermdat_H2O') species_list = read_thermdat(thermdat_H2O_path) species_dict = pmutt_list_to_dict(species_list) # Initialize the reaction rxn_H2O = Reaction.from_string('H2 + 0.5O2 = H2O', species=species_dict) # Calculate reaction properties H_rxn = rxn_H2O.get_delta_H(T=298., units='kJ/mol') S_rxn = rxn_H2O.get_delta_S(T=298., units='J/mol/K') print('H_rxn(T=298) = {:.1f} kJ/mol'.format(H_rxn)) print('S_rxn(T=298) = {:.2f} J/mol/K'.format(S_rxn)) # ## Exercise # Write a script to calculate the Enthalpy of adsorption (in kcal/mol) of H2O on Cu(111) at T = 298 K. Some important details are given below. # # ### Information Required
def read_thermdat(filename, format='list', key='name'): """Directly read thermdat file that is in the Chemkin format Parameters ---------- filename : str Input filename format : str, optional Format to output NASA polynomials. Supported options are: 'list', 'tuple', 'dict'. Default is 'list' key : str, optional If `format` is 'dict', uses this attribute as the key for the output dictionary. Default is 'name' Returns ------- Nasas : list, tuple or dict of :class:`~pmutt.empirical.nasa.Nasa` Raises ------ FileNotFoundError If the file isn't found. IOError Invalid line number found. """ species = [] with open(filename, 'r') as f_ptr: for line in f_ptr: ''' Lines to skip ''' # Skip the header line if 'THERMO' in line: continue # Skip the end line if 'END' in line: continue # Skip blank lines if line == '\n': continue # Skip comment lines if line[0] == '!': continue # Skip header temperatures if _is_temperature_header(line): continue ''' Parse lines ''' line_num = _read_line_num(line) if line_num == 1: nasa_data = _read_line1(line) elif line_num == 2: nasa_data = _read_line2(line, nasa_data) elif line_num == 3: nasa_data = _read_line3(line, nasa_data) elif line_num == 4: nasa_data = _read_line4(line, nasa_data) species.append(Nasa(**nasa_data)) else: err_msg = ('Invalid line number, {}, in thermdat file: {}' ''.format(line_num, filename)) raise IOError(err_msg) # Format the NASA polynomials in the required format if format == 'list': pass elif format == 'tuple': species = tuple(species) elif format == 'dict': species = pmutt_list_to_dict(species, key=key) else: err_msg = ( 'Unsupported format: {}. See pmutt.io.thermdat.read_thermdat' ' docstring for supported formats.'.format(format)) raise ValueError(err_msg) return species
beps = [] for bep_data in beps_data: beps.append(BEP(**bep_data)) # Combine species and BEPs to make reactions species_with_beps = species + beps # ### Read reactions # In[6]: from pmutt import pmutt_list_to_dict from pmutt.omkm.reaction import SurfaceReaction # Convert species to dictionary for easier reaction assignment species_with_beps_dict = pmutt_list_to_dict(species_with_beps) reactions_data = read_excel(io=input_path, sheet_name='reactions') reactions = [] # Store information about phases for later retrieval reaction_phases = {} for reaction_data in reactions_data: reaction = SurfaceReaction.from_string(species=species_with_beps_dict, **reaction_data) reactions.append(reaction) # Assign phase information reaction_species = reaction.get_species(include_TS=True) for ind_species in reaction_species: try: phase = species_with_beps_dict[ind_species].phase except AttributeError: pass
def read_reactions(filename, species=None): """Directly read reactions from Chemkin gas.inp or surf.inp files Parameters ---------- filename : str Input filename for Chemkin surf or gas .inp file species : list of :class:`~pmutt.empirical.nasa.Nasa` objects List of NASA objects containing thermodynamic properties for all Reactants and Products in Reactions default = None. Will not return React_obj and Prod_obj Returns ------- Reactions : list of reactions Reactants : list of reactants found in reactions React_obj : list of NASA polynomials for each Reactant If species object list is supplied React_stoic : list of reaction stoichiometries for Reactants Products : list of products found in reactions Prod_obj : list of NASA polynomials for each Product If species object list is supplied Prod_stoic : list of reaction stoichiometries for Products Raises ------ FileNotFoundError If the surf.inp or gas.inp file isn't found. NameError If the species file does not exist AttributeError If the species list is incorrect format """ if species is not None: species_dict = pmutt_list_to_dict(species) rxns = [] with open(filename, 'r') as lines: for line in lines: if re.findall(r'(^[^\!].+)( *<*(?<![0-9][eE])[=\-]>* *)', line): rxns.append(line.strip()) RHS = [] LHS = [] for rxn in rxns: LHS.append(re.split(r' *<*(?<![0-9][eE])[=\-]>* *', rxn)[0]) RHS.append(re.split(r' *<*(?<![0-9][eE])[=\-]>* *', rxn)[1]) Reactants = [] Products = [] React_obj = [] Prod_obj = [] React_stoic = [] Prod_stoic = [] for Reacs, Prods in zip(LHS, RHS): Reactants.append(re.split(r' *\+ *| +', Reacs)) Products.append(re.split(r' *\+ *| +', Prods)[0:-3]) R = [] RS = [] Rx = [] for RR in Reactants[-1]: stoic = re.findall(r'^[0-9]*', RR)[0] if stoic == '': stoic = 1 else: RR = RR.replace(stoic, "") stoic = int(stoic) Rx.append(RR) RS.append(stoic) if species is not None: R.append(species_dict[RR]) Reactants[-1] = Rx React_stoic.append(RS) P = [] PS = [] Px = [] for PP in Products[-1]: stoic = re.findall(r'^[0-9]*', PP)[0] if stoic == '': stoic = 1 else: PP = PP.replace(stoic, "") stoic = int(stoic) Px.append(PP) PS.append(stoic) if species is not None: P.append(species_dict[PP]) Products[-1] = Px Prod_stoic.append(PS) React_obj.append(R) Prod_obj.append(P) Reactions = [] for rxn, Prods in zip(rxns, Products): Reactions.append(rxn[0:rxn.rindex(Prods[-1]) + len(Prods[-1])]) if species is not None: return (Reactions, Reactants, React_obj, React_stoic, Products, Prod_obj, Prod_stoic) else: return (Reactions, Reactants, React_stoic, Products, Prod_stoic)