Source code for catmap.parsers.parser_base

#Standard imports
import os
import inspect

#Non-standard imports
import catmap
from catmap import ReactionModelWrapper
from catmap.model import ReactionModel

from catmap.functions import get_composition, cartesian_product 

[docs]class ParserBase(ReactionModelWrapper):
[docs] def __init__(self,reaction_model=None): """Class for `parsing' information from raw data (databases, spreadsheets, text files, trajectories, etc.) into a structure which is useful to the microkinetic model. This class acts as a base class to be inherited by other parser classes, but it is not functional on its own. input_file: defines the file path or object to get data from A functional derived parser class must also contain the methods: parse(input_file): a function to parse the input_file file/object and return properly formatted data. The parse function should save all necessary attributes to the Parser class. After parsing the parent microkinetic model class will update itself from the Parser attributes. """ if reaction_model is None: reaction_model = ReactionModel() self._rxm = reaction_model self._required = {} #No user-defined attributes are required.
[docs] def _baseparse(self): #Make dictionary of useful information about species in model if not self.species_definitions: self.species_definitions = {} for species in (self.gas_names+self.adsorbate_names+ self.transition_state_names+self.site_names+tuple(self._gas_sites)): site_names = self.site_names + tuple(self._gas_sites) ads_info = {} if '_' in species: name,site = species.rsplit('_',1) else: name = species site = self._default_site ads_info['name'] = name ads_info['site'] = site if species in self.gas_names: ads_info['type'] = 'gas' ads_info['n_sites'] = 0 elif species in self.adsorbate_names: ads_info['type'] = 'adsorbate' ads_info['n_sites'] = 1 elif species in self.transition_state_names: ads_info['type'] = 'transition_state' ads_info['n_sites'] = 1 elif species in site_names: ads_info['type'] = 'site' ads_info['site'] = species ads_info['formation_energy'] = 0 if species not in self._gas_sites: ads_info['n_sites'] = 1 else: ads_info['n_sites'] = 0 ads_info['site_names'] = ['gas'] ads_info['total'] = 0 ads_info['composition'] = {} else: ads_info['type'] = 'unknown' if species not in site_names: composition = get_composition(name) ads_info['composition'] = composition if species in self.species_definitions: ads_info.update(self.species_definitions[species]) if ads_info['composition'] is None and species not in site_names: raise ValueError('Could not determine composition for '+species) if species not in site_names: self.species_definitions[species] = ads_info else: self.species_definitions[species] = \ self.species_definitions['*_'+species] = ads_info for species in self.species_definitions.keys(): #set site definitions ##This entire block can probably be deleted since sites are now #handled in the above section. Wait for a version or 2 to let #the clauses deprecate... site = self.species_definitions[species].get('site',None) if site and site not in self.species_definitions: ads_info = {} ads_info['type'] = 'site' ads_info['site'] = site ads_info['formation_energy'] = 0 if site not in self._gas_sites: ads_info['n_sites'] = 1 else: ads_info['n_sites'] = 0 ads_info['site_names'] = ['gas'] ads_info['total'] = 0 ads_info['composition'] = {} if self.site_definitions: #Deprecate later... warnings.warn('Deprecation Warning: site_definitions will not be' ' supported in future versions. Please use new ' 'species_definitions syntax.') site_names = self.site_definitions[site] if isinstance(site_names,basestring): site_names = [site_names] ads_info['site_names'] = site_names if self.site_totals: #Deprecate later... warnings.warn('Deprecation Warning: site_totals will not be' ' supported in future versions. Please use new ' 'species_definitions syntax.') ads_info['total'] = self.site_totals[site] if site in self.species_definitions: ads_info.update(self.species_definitions[site]) self.species_definitions[site] = self.species_definitions['*_'+site] \ = ads_info if not self.atomic_reservoir_list: #Make list of valid reference sets for e.g. boltzmann coverages cart_product = [] all_atoms = [] composition_dict = {} dummy_dict = {} for sp in self.gas_names: composition_dict[sp] = self.species_definitions[sp]['composition'] dummy_dict[sp] = 0 #dummy dict of energies for key in composition_dict[sp].keys(): if key not in all_atoms: all_atoms.append(key) for key in all_atoms: possibles = [] for sp in self.gas_names: if composition_dict[sp].get(key,None): possibles.append(sp) cart_product.append(possibles) ref_sets = [] for prod in cartesian_product(*cart_product): refdict = {} for ai,pi in zip(all_atoms,prod): refdict[ai] = pi if (sorted(list(refdict.values())) == sorted(list(set(refdict.values()))) and sorted(list(refdict.values())) not in [sorted(list(rs.values())) for rs in ref_sets]): if refdict and dummy_dict and composition_dict: try: self.convert_formation_energies(dummy_dict, refdict,composition_dict) ref_sets.append(refdict) except ValueError: pass if ref_sets: self.atomic_reservoir_list = ref_sets else: raise AttributeError('No valid reference sets from gas-phase species ' + \ 'in the system. Add gasses or specify atomic_reservoir_list')