def _stoimat_generate(self): stoimat = np.zeros([self.nrxn, self.nspe], dtype='int8') for i in range(self.nrxn): for react in self.reactionlist[i].reactant: k = get_index_species(str(react[0]), self.specieslist) stoimat[i, k] = -react[1] for prod in self.reactionlist[i].product: k = get_index_species(str(prod[0]), self.specieslist) stoimat[i, k] = prod[1] return stoimat
def init_condition(self, condition): x0 = [0] * (self.nspe - 1) for spe in condition.InitCoverage.keys(): idx = get_index_species(spe, self.specieslist) x0[idx] = condition.InitCoverage[spe] x0.append(1 - sum(x0[self.ngas:])) return x0
def read_species_thermo(species_thermo_file, _dir_): ''' Assign the species thermo calculation result to species list, :param species_thermo_string: json readable string for list of dictionary :param specieslist: list stored all species information ''' with open(species_thermo_file, 'r') as f: datalist = json.load(f) for data in datalist: spe = data['name'] idx = get_index_species(spe, _dir_['specieslist']) _dir_['specieslist'][idx].thermo = data['thermo']
def read_species_vib(species_vib_file, _dir_): ''' Assign the vibrational frequency to species list, :param vib_string: json readable string for list of dictionary :param specieslist: specieslist stored all species information ''' with open(species_vib_file, 'r') as f: datalist = json.load(f) for data in datalist: spe = data['name'] idx = get_index_species(spe, _dir_['specieslist']) _dir_['specieslist'][idx].vibfreq = data['vib']
def read_reaction(reaction_file, _dir_): ''' Read the reaction mechanism given list of reactions :param reaction_string: json readable string ''' with open(reaction_file, 'r') as f: datalist = json.load(f) for data in datalist: rxn = Reaction() rxn.name = data['name'] reactant = data['reactant'] product = data['product'] cons_react = [] for react, stoi in reactant: idx = get_index_species(react, _dir_['specieslist']) cons_react.append((_dir_['specieslist'][idx], stoi)) cons_prod = [] for react, stoi in product: idx = get_index_species(react, _dir_['specieslist']) cons_prod.append((_dir_['specieslist'][idx], stoi)) rxn.reactant = cons_react rxn.product = cons_prod _dir_['reactionlist'].append(rxn)
def eval_likeli(self, dE, conditionlist, evidence_info={}): reltol = evidence_info.get('reltol', 1e-12) abstol = evidence_info.get('abstol', 1e-12) err = evidence_info.get('peak_err', 10) opts = {} opts['abstol'] = abstol opts['reltol'] = reltol opts['disable_internal_warnings'] = True opts['max_num_steps'] = 1e5 # Initialize simulator evidence = 0 for condition in conditionlist: time = condition.TimeGrid T0 = condition.T0 beta = condition.Beta x0 = self.init_condition(condition) P_dae = np.hstack([dE, T0, beta]) Fint = cas.Integrator('Fint', 'cvodes', self._dae_, opts) Fsim = cas.Simulator('Fsim', Fint, time) Fsim.setInput(x0, 'x0') Fsim.setInput(P_dae, 'p') Fsim.evaluate() out = Fsim.getOutput().full() # Find the peak for spe, peak_exp in condition.PeakPosition.items(): idx = get_index_species(spe, self.specieslist) des = out[idx, :] idx_peak = np.argmax(des) peak_sim = condition.TemGrid[idx_peak] dev = peak_sim - peak_exp evidence += (dev * dev) / err**2 return -evidence
def evidence_construct(self, conditionlist, evidence_info, sensitivity=True): # simulation option reltol = evidence_info.get('reltol', 1e-6) abstol = evidence_info.get('abstol', 1e-10) # error value err_type = evidence_info['type'] err = evidence_info['err'] lowSurf = evidence_info.get('lowSurf', 1e4) lowSurf_thres = evidence_info.get('lowSurf_thres', 1e-5) cov_err = evidence_info.get('cov_err', 0.05) # Initialize simulator Pnlp = self._Pnlp if sensitivity: # opts = fwd_sensitivity_option(reltol=reltol, adjtol=adjtol, fwdtol=fwdtol) opts = fwd_sensitivity_option() else: opts = fwd_NoSensitivity_option(reltol=reltol, abstol=abstol) print(opts) Fint = cas.Integrator('Fint', 'cvodes', self._dae_, opts) evidence = 0 for condition in conditionlist: TotalPressure = condition.TotalPressure TotalFlow = condition.TotalFlow Tem = condition.Temperature if condition.InitCoverage == {}: x0 = [0] * (self.nspe - 1) + [1] else: # Construct Coverage x0 = [0] * (self.nspe - 1) + [1] for spe, cov in condition.InitCoverage.items(): idx = get_index_species(spe, self.specieslist) x0[idx - self.ngas] = cov x0[-1] -= cov # construct initial partial pressure Pinlet = np.zeros(self.ngas) for idx, spe in enumerate(self.specieslist): if spe.phase == 'gaseous': Pinlet[idx] = condition.PartialPressure[str(spe)] if str( spe) in condition.PartialPressure.keys() else 0 # run simulation P_dae = cas.vertcat([Pnlp, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) for idx, spe in enumerate(self.specieslist): if spe.phase == 'gaseous': # construct evidence with turnover frequency tor = F_sim['xf'][ idx] - Pinlet[idx] / TotalPressure * TotalFlow if str(spe) in condition.TurnOverFrequency.keys(): exp_tor = condition.TurnOverFrequency[str(spe)] if err_type == 'abs' or abs(exp_tor) <= lowSurf_thres: dev = tor - exp_tor elif err_type == 'rel': dev = 1 - tor / exp_tor elif err_type == 'log': dev = cas.log(tor / exp_tor) else: pass # if abs(exp_tor) <= lowSurf_thres: # evidence += (dev * dev) * lowSurf # else: evidence += (dev * dev) / err**2 # if spe.phase == 'surface': # cov = F_sim['xf'][idx] # if str(spe) in condition.Coverage.keys(): # exp_cov = condition.Coverage[str(spe)] # dev = cas.log(cov / exp_cov) # evidence += (dev * dev) / cov_err**2 self._evidence_ = evidence return evidence
def fwd_simulation(self, dE_start, condition, detail=True, reltol=1e-8, abstol=1e-10, DRX=False, drc_opt={}): TotalPressure = condition.TotalPressure TotalFlow = condition.TotalFlow Tem = condition.Temperature tf = condition.SimulationTime opts = {} opts['tf'] = tf # Simulation time opts['abstol'] = abstol opts['reltol'] = reltol opts['disable_internal_warnings'] = True opts['max_num_steps'] = 1e8 if py == 2: Fint = cas.Integrator('Fint', 'cvodes', self._dae_, opts) elif py == 3: Fint = cas.integrator('Fint', 'cvodes', self._dae_, opts) if condition.InitCoverage == {}: x0 = [0] * (self.nspe - 1) + [1] else: # Construct Coverage x0 = [0] * (self.nspe - 1) + [1] for spe, cov in condition.InitCoverage.items(): idx = get_index_species(spe, self.specieslist) x0[idx - self.ngas] = cov x0[-1] -= cov # Partial Pressure Pinlet = np.zeros(self.ngas) for idx, spe in enumerate(self.specieslist): if spe.phase == 'gaseous': Pinlet[idx] = condition.PartialPressure[str(spe)] if str( spe) in condition.PartialPressure.keys() else 0 P_dae = np.hstack([dE_start, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) tor = {} for idx, spe in enumerate(self.specieslist): if spe.phase == 'gaseous': tor[str(spe)] = float(F_sim['xf'][idx] - Pinlet[idx] / TotalPressure * TotalFlow) # Detailed Reaction network data # Evaluate partial pressure and surface coverage self.pressure_value = list( (F_sim['xf'][:self.ngas] / TotalFlow * TotalPressure).full().T[0]) self.coverage_value = list(F_sim['xf'][self.ngas:].full().T[0]) # Evaluate Reaction Rate automatically save to Rate attribute x = self._x p = self._p if py == 2: rate_fxn = cas.SXFunction('rate_fxn', [x, p], [self._rate, self._rfor, self._rrev]) rate_fxn.setInput(F_sim['xf'], 'i0') rate_fxn.setInput(P_dae, 'i1') rate_fxn.evaluate() self.rate_value = {} self.rate_value['rnet'] = rate_fxn.getOutput( 'o0').full().T[0].tolist() self.rate_value['rfor'] = rate_fxn.getOutput( 'o1').full().T[0].tolist() self.rate_value['rrev'] = rate_fxn.getOutput( 'o2').full().T[0].tolist() # Evaluate Reaction Energy ene_fxn = cas.SXFunction('ene_fxn', [x, p], [ self._reaction_energy_expression['activation'], self._reaction_energy_expression['enthalpy'] ]) ene_fxn.setInput(F_sim['xf'], 'i0') ene_fxn.setInput(P_dae, 'i1') ene_fxn.evaluate() self.energy_value = {} self.energy_value['activation'] = list( ene_fxn.getOutput('o0').full().T[0]) self.energy_value['enthalpy'] = list( ene_fxn.getOutput('o1').full().T[0]) # Evaluate Equilibrium Constant and Rate Constant k_fxn = cas.SXFunction('k_fxn', [x, p], [self._Keq, self._Qeq, self._kf, self._kr]) k_fxn.setInput(F_sim['xf'], 'i0') k_fxn.setInput(P_dae, 'i1') k_fxn.evaluate() self.equil_rate_const_value = {} self.equil_rate_const_value['Keq'] = list( k_fxn.getOutput('o0').full().T[0]) self.equil_rate_const_value['Qeq'] = list( k_fxn.getOutput('o1').full().T[0]) self.equil_rate_const_value['kf'] = list( k_fxn.getOutput('o2').full().T[0]) self.equil_rate_const_value['kr'] = list( k_fxn.getOutput('o3').full().T[0]) elif py == 3: rate_fxn = cas.Function('rate_fxn', [x, p], [self._rate, self._rfor, self._rrev]) outs = rate_fxn(F_sim['xf'], P_dae) self.rate_value = {} self.rate_value['rnet'] = outs[0].full().T[0].tolist() self.rate_value['rfor'] = outs[1].full().T[0].tolist() self.rate_value['rrev'] = outs[2].full().T[0].tolist() # Evaluate Reaction Energy ene_fxn = cas.Function('ene_fxn', [x, p], [ self._reaction_energy_expression['activation'], self._reaction_energy_expression['enthalpy'] ]) outs = ene_fxn(F_sim['xf'], P_dae) self.energy_value = {} self.energy_value['activation'] = list(outs[0].full().T[0]) self.energy_value['enthalpy'] = list(outs[1].full().T[0]) # Evaluate Equilibrium Constant and Rate Constant k_fxn = cas.Function('k_fxn', [x, p], [self._Keq, self._Qeq, self._kf, self._kr]) outs = k_fxn(F_sim['xf'], P_dae) self.equil_rate_const_value = {} self.equil_rate_const_value['Keq'] = list(outs[0].full().T[0]) self.equil_rate_const_value['Qeq'] = list(outs[1].full().T[0]) self.equil_rate_const_value['kf'] = list(outs[2].full().T[0]) self.equil_rate_const_value['kr'] = list(outs[3].full().T[0]) xrc, xtrc = [], [] # TODO: degree of rate control if DRX: delG = drc_opt.get('delG', 1) ref_species = drc_opt.get('ref', 'H2(g)') numer = drc_opt.get('numer', 'fwd') tor0 = tor[ref_species] if numer == 'ad': opts = fwd_sensitivity_option(tf=tf, reltol=1e-8, abstol=1e-16) Fint = cas.Integrator('Fint', 'cvodes', self._dae_, opts) Pnlp = self._Pnlp P_dae = cas.vertcat([Pnlp, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) ii = [ ii for ii, spe in enumerate(self.specieslist) if str(spe) == ref_species ][0] tor_ad = F_sim['xf'][ ii] - Pinlet[ii] / TotalPressure * TotalFlow # define the jacobian and MX function jac = cas.jacobian(tor_ad, Pnlp) # evaluate the jacobian fjac = cas.MXFunction('fjac', [Pnlp], [jac]) xrc = fjac([np.copy(dE_start)])[0] xrc = xrc / tor0 * (_const.Rg * Tem) / (-1000) xrc = xrc.full()[0].tolist()[:len(self.dEa_index)] for idx, j in enumerate(self.dEa_index): dP = np.copy(dE_start) dP[idx] += delG # Partial Pressure P_dae = np.hstack([dP, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) for ii, spe in enumerate(self.specieslist): if str(spe) == ref_species: tor_p = float(F_sim['xf'][ii] - Pinlet[ii] / TotalPressure * TotalFlow) if numer == 'cent': dP = np.copy(dE_start) dP[idx] -= delG # Partial Pressure P_dae = np.hstack([dP, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) for ii, spe in enumerate(self.specieslist): if str(spe) == ref_species: tor_n = float(F_sim['xf'][ii] - Pinlet[ii] / TotalPressure * TotalFlow) if numer == 'fwd': xrc.append((tor_p - tor0) / tor0 / (-delG * 1000 / (_const.Rg * Tem))) # xrc.append((np.log(np.abs(tor_p)) - np.log(np.abs(tor0)))/(-delG * 1000 /(_const.Rg * Tem))) if numer == 'cent': xrc.append((tor_p - tor_n) / tor0 / (-2 * delG * 1000 / (_const.Rg * Tem))) # xrc.append((np.log(np.abs(tor_p)) - np.log(np.abs(tor_n)))/(-2 * delG * 1000 /(_const.Rg * Tem))) # XTRC for idx, j in enumerate(self.dBE_index): spe = self.reactionlist[idx] dP = np.copy(dE_start) deltaE = np.zeros(self.nspe) deltaE[j] += delG # propagate through stoichiomatric deltaEa = self.stoimat.dot(deltaE) # dP[:len(self.dEa_index)] -= deltaEa dP[len(self.dEa_index):] += deltaE[self.dBE_index] # Partial Pressure P_dae = np.hstack([dP, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) for ii, spe in enumerate(self.specieslist): if str(spe) == ref_species: tor_p = float(F_sim['xf'][ii] - Pinlet[ii] / TotalPressure * TotalFlow) if numer == 'fwd': xtrc.append((tor_p - tor0) / tor0 / (-delG * 1000 / (_const.Rg * Tem))) # xrc.append((np.log(np.abs(tor_p)) - np.log(np.abs(tor0)))/(-delG * 1000 /(_const.Rg * Tem))) if numer == 'cent': dP = np.copy(dE_start) deltaE = np.zeros(self.nspe) deltaE[j] -= delG # propagate through stoichiomatric deltaEa = self.stoimat.dot(deltaE) # dP[:len(self.dEa_index)] -= deltaEa dP[len(self.dEa_index):] += deltaE[self.dBE_index] # Partial Pressure P_dae = np.hstack([dP, Pinlet, Tem, TotalFlow]) F_sim = Fint(x0=x0, p=P_dae) for ii, spe in enumerate(self.specieslist): if str(spe) == ref_species: tor_n = float(F_sim['xf'][ii] - Pinlet[ii] / TotalPressure * TotalFlow) xtrc.append((tor_p - tor_n) / tor0 / (-2 * delG * 1000 / (_const.Rg * Tem))) # RESULT result = {} result['pressure'] = self.pressure_value result['coverage'] = self.coverage_value result['rate'] = self.rate_value result['energy'] = self.energy_value result['equil_rate'] = self.equil_rate_const_value result['xrc'] = xrc result['xtrc'] = xtrc self.xrc = xrc return tor, result