Source code for catmap.scalers.scaler_base

import catmap
from catmap import ReactionModelWrapper
from catmap.model import ReactionModel
np = catmap.np
re = catmap.re
# copy = catmap.copy
string2symbols = catmap.string2symbols


[docs]class ScalerBase(ReactionModelWrapper):
[docs] def __init__(self,reaction_model = None): """Class for `scaling' descriptors to free energies of reaction and activation (or other parameters). This class acts as a base class to be inherited by other scaler classes, but is not functional on its own. This class contains the description of the microkinetic model (adsorbate_names, gas_names, etc.) along with the temperature and gas_pressures. In most cases these will automatically be populated by the parent reaction_model class. The scaler-specific attributes are: gas_energies: defines the energies of the gas-phase species. This sets the references for the system. gas_thermo_mode: the mode for obtaining thermal contributions in the gas phase. Default is to use the ideal gas approxmation. adsorbate_thermo_mode: the mode for obtaining thermal contributions from adsorbed species. Default is to use the harmonic adsorbate approximation. frequency_dict: a dictionary of vibrational frequencies (in eV) for each gas/adsorbate. Should be of the form frequency_dict[ads] = [freq1, freq2,...]. Needed for ideal gas, harmonic adsorbate, or hindered adsorbate approximations. A functional derived scaler class must also contain the methods: get_electronic_energies(descriptors): a function to `scale' the descriptors to electronic energies. Returns a dictionary of the electronic energies of each species in the model. get_energetics(descriptors): a function to obtain the reaction energetics from the descriptors. Should return a list of length N (number of elementary reactions): [[E_rxn1,E_a1],[E_rxn2,E_a2],...[E_rxnN,E_aN]] get_rxn_parameters(descriptors): a function to obtain all necessary reaction parameters from the descriptors. Should return a list of length N (number of elementary reactions): [[param1_rxn1,param2_rxn1...]...[param1_rxnN,param2_rxnN...]]. For a simple model this could be the same as get_energetics, but models accounting for interactions may require more parameters which can be scaled. """ if reaction_model is None: reaction_model = ReactionModel() self._rxm = reaction_model defaults = dict( parameter_mode = 'formation_energy', ) self._rxm.update(defaults,override=False)
[docs] def set_output_attrs(self,descriptors): "Function to set output information." ads = self.gas_names+self.adsorbate_names+self.transition_state_names if 'rxn_parameter' in self.output_variables: params = self.get_rxn_parameters(descriptors) self._rxn_parameter = params self.output_labels['rxn_parameter'] = self.parameter_names if 'frequency' in self.output_variables: self._frequency = [self.frequency_dict.get(a,[]) for a in ads] max_len = 0 for f in self._frequency: if len(f) > max_len: max_len = len(f) nu_labels = ['nu_'+str(i+1) for i in range(max_len)] self.output_labels['frequency'] = [ads,nu_labels] if 'electronic_energy' in self.output_variables: electronic_energy_dict = self.get_electronic_energies(descriptors) self._electronic_energy = [electronic_energy_dict[a] for a in ads] self.output_labels['electronic_energy'] = ads if 'free_energy' in self.output_variables: free_energy_dict = self.get_free_energies(descriptors) self._free_energy = [free_energy_dict[a] for a in ads] self.output_labels['free_energy'] = ads if 'gas_pressure' in self.output_variables: self._gas_pressure = [p for p in self.gas_pressures] self.output_labels['gas_pressure'] = self.gas_names if 'boltzmann_coverage' in self.output_variables: cvgs = self.thermodynamics.boltzmann_coverages( self.get_free_energies(descriptors)) self._boltzmann_coverage = cvgs self.output_labels['boltzmann_coverage'] = self.adsorbate_names if set(['enthalpy','entropy','zero_point_energy']).issubset( set(self.output_variables)): self.thermodynamics.get_thermodynamic_corrections() self._zero_point_energy = [self._zpe_dict[a] for a in ads] self._enthalpy = [self._enthalpy_dict[a] for a in ads] self._entropy = [self._entropy_dict[a] for a in ads] self.output_labels['enthalpy'] = ads self.output_labels['entropy'] = ads self.output_labels['zero_point_energy'] = ads if 'interaction_matrix' in self.output_variables: self._interaction_matrix = getattr( self.thermodynamics.adsorbate_interactions, '_interaction_matrix', None) all_names = self.adsorbate_names + self.transition_state_names self.output_labels['interaction_matrix'] = [all_names,all_names]
[docs] def get_energetics(self,descriptors): raise AttributeError('Scaler class does not contain this method. \ Please ensure that it is defined in order for the scaler \ to be useful.')
[docs] def get_rxn_parameters(self,descriptors): raise AttributeError('Scaler class does not contain this method. \ Please ensure that it is defined in order for the scaler \ to be useful.')
[docs] def get_electronic_energies(self,descriptors): raise AttributeError('Scaler class does not contain this method. \ Please ensure that it is defined in order for the scaler \ to be useful.')
[docs] def get_thermodynamic_energies(self,**kwargs): thermo_dict = self.thermodynamics.get_thermodynamic_corrections( **kwargs) return thermo_dict
[docs] def get_free_energies(self,descriptors,**kwargs): electronic_energy_dict = self.get_electronic_energies(descriptors) self._electronic_energy_dict = electronic_energy_dict thermodynamic_energy_dict = self.get_thermodynamic_energies( descriptors=descriptors,**kwargs) free_energy_dict = {} for key in electronic_energy_dict: if key in thermodynamic_energy_dict: E_DFT = electronic_energy_dict[key] G = thermodynamic_energy_dict[key] if G is None: raise ValueError('No free energy for '+key) elif E_DFT is None: raise ValueError('No formation energy for '+key) free_energy_dict[key] = E_DFT + G self._gas_energies = [free_energy_dict[g] for g in self.gas_names] self._site_energies = [free_energy_dict.get(s,0) for s in self.site_names] return free_energy_dict
[docs] def get_enthalpies(self,descriptors,**kwargs): self.get_free_energies(descriptors,**kwargs) return self._enthalpy_dict.copy()
[docs] def get_total_enthalpies(self,descriptors,**kwargs): self.get_free_energies(descriptors,**kwargs) energy_dict = self._enthalpy_dict.copy() for _ in energy_dict.keys(): energy_dict[_] += self._electronic_energy_dict[_] return energy_dict
[docs] def get_entropies(self,descriptors,**kwargs): self.get_free_energies(descriptors,**kwargs) return self._entropy_dict.copy()
[docs] def summary_text(self): return ''