""" The statelist module. """fromeon.configimportconfigimportlogginglogger=logging.getLogger('statelist')importmathimportshutilfromeonimportatomsfromeonimportakmcstatefromeonimportstatelist
[docs]classAKMCStateList(statelist.StateList):""" The StateList class. Serves as an interface to State objects and StateList metadata. """def__init__(self,kT,thermal_window,max_thermal_window,initial_state=None,filter_hole=False):statelist.StateList.__init__(self,akmcstate.AKMCState,initial_state)# aKMC data.self.kT=kTself.thermal_window=thermal_windowself.max_thermal_window=max_thermal_windowself.filter_hole=filter_hole
[docs]defregister_process(self,reactant_number,product_number,process_id):# Get the reactant and product state objects.reactant=self.get_state(reactant_number)product=self.get_state(product_number)reactant.load_process_table()# Forward process (reac->prod)# Make the reactant process point to the product state number.reactant.procs[process_id]['product']=product_numberreactant.save_process_table()# If the process is of type reac->reac no reverse process needs to be added and we can return.# This can be the case if for example a water molecule rotates to mirrored conf.ifreactant_number==product_number:return# Loads 'reference' energy for the reactant state as defined in meta-data.reactant_energy=reactant.get_energy()saddle_energy=reactant.procs[process_id]['saddle_energy']# Reverse process (prod->reac).# Have any processes been determined for the product state.ifproduct.get_num_procs()!=0:print("register_process: found process in product state")product.load_process_table()reverse_procs=product.get_process_table()candidates=[]# An alike reverse process might already existforidinlist(reverse_procs.keys()):proc=reverse_procs[id]if(abs(proc['saddle_energy']-saddle_energy)<self.epsilon_e)and(proc['product']==-1):candidates.append(id)iflen(candidates):print("register_process: some candidate reverse processes found")reactant_conf=reactant.get_reactant()foridincandidates:conf=product.get_process_product(id)# The process is known but has not been accepted yet.ifatoms.match(reactant_conf,conf,config.comp_eps_r,config.comp_neighbor_cutoff,False):# Reverse process table should be updated to ensure that the two processes (reac->prod & proc->reac) are symmetric.reactant.load_process_table()# Set maximum rate, if defined# cur_rate = reactant.procs[process_id]['product_prefactor'] * math.exp( - ( saddle_energy - product.get_energy() ) /self.kT)# if config.akmc_max_rate > 0 and cur_rate > config.akmc_max_rate:# # print "max rate exceeded: ", cur_rate# cur_rate = config.akmc_max_rate# Set equilibrium rate, if definedprint("register_process: into eq rate test")reverse_rate=reactant.procs[process_id]['product_prefactor']*math.exp(-(saddle_energy-product.get_energy())/self.kT)forward_barrier=saddle_energy-reactant.get_energy()forward_rate=reactant.procs[process_id]['prefactor']*math.exp(-forward_barrier/self.kT)eq_rate_flag=Falseifconfig.akmc_eq_rate>0andforward_rate>config.akmc_eq_rateandreverse_rate>config.akmc_eq_rate:eq_rate_flag=Trueprint("eq_rate exceeded, forward:",forward_rate," reverse: ",reverse_rate)ifforward_rate<reverse_rate:forward_eq_rate=config.akmc_eq_ratereverse_eq_rate=config.akmc_eq_rate*(reverse_rate/forward_rate)else:forward_eq_rate=config.akmc_eq_rate*(forward_rate/reverse_rate)reverse_eq_rate=config.akmc_eq_rateprint("new eq forward rate:",forward_eq_rate," reverse: ",reverse_eq_rate)# Remember we are now looking at the reverse processesreverse_procs[id]['product']=reactant_numberreverse_procs[id]['saddle_energy']=saddle_energyreverse_procs[id]['prefactor']=reactant.procs[process_id]['product_prefactor']reverse_procs[id]['product_energy']=reactant.get_energy()reverse_procs[id]['product_prefactor']=reactant.procs[process_id]['prefactor']reverse_procs[id]['barrier']=saddle_energy-product.get_energy()reverse_procs[id]['rate']=reverse_rateproduct.save_process_table()# If equilibrium rate, change the forward and reverse rateifeq_rate_flag:print("register_process: setting eq rates")reactant.procs[process_id]['rate']=forward_eq_ratereverse_procs[id]['rate']=reverse_eq_ratereactant.save_process_table()product.save_process_table()# We are done.return# The process is not in the list and must be added as a new process.reverse_process_id=product.get_num_procs()else:# This must be a new state.print("register_process: new product state")product.set_energy(reactant.procs[process_id]['product_energy'])reverse_process_id=0# The product state does not know the reverse process yet.# Reverse id has been determined above. (0 if it is a new state, else the last element in the proc table + 1)shutil.copy(reactant.proc_saddle_path(process_id),product.proc_saddle_path(reverse_process_id))shutil.copy(reactant.proc_reactant_path(process_id),product.proc_product_path(reverse_process_id))shutil.copy(reactant.proc_product_path(process_id),product.proc_reactant_path(reverse_process_id))shutil.copy(reactant.proc_results_path(process_id),product.proc_results_path(reverse_process_id))shutil.copy(reactant.proc_mode_path(process_id),product.proc_mode_path(reverse_process_id))# Add the reverse process in the product statebarrier=saddle_energy-product.get_energy()# Set maximum rate, if defined# print "max rate code"# cur_rate = reactant.procs[process_id]['product_prefactor'] * math.exp(-barrier / self.kT)# if config.akmc_max_rate > 0 and cur_rate > config.akmc_max_rate:# # print "max rate exceeded: ", cur_rate# cur_rate = config.akmc_max_rateproduct.append_process_table(id=reverse_process_id,saddle_energy=saddle_energy,prefactor=reactant.procs[process_id]['product_prefactor'],product=reactant_number,product_energy=reactant_energy,product_prefactor=reactant.procs[process_id]['prefactor'],barrier=barrier,rate=reactant.procs[process_id]['product_prefactor']*math.exp(-barrier/self.kT),# rate = cur_rate,repeats=0)# Set equilibrium rate, if definedprint("register_process: into eq rate test")forward_barrier=saddle_energy-reactant.get_energy()forward_rate=reactant.procs[process_id]['prefactor']*math.exp(-forward_barrier/self.kT)reverse_rate=reactant.procs[process_id]['product_prefactor']*math.exp(-(saddle_energy-product.get_energy())/self.kT)eq_rate_flag=Falseifconfig.akmc_eq_rate>0andforward_rate>config.akmc_eq_rateandreverse_rate>config.akmc_eq_rate:eq_rate_flag=Trueprint("eq_rate exceeded, forward:",forward_rate," reverse: ",reverse_rate)ifforward_rate<reverse_rate:forward_eq_rate=config.akmc_eq_ratereverse_eq_rate=config.akmc_eq_rate*(reverse_rate/forward_rate)else:forward_eq_rate=config.akmc_eq_rate*(forward_rate/reverse_rate)reverse_eq_rate=config.akmc_eq_rateprint("new eq forward rate:",forward_eq_rate," reverse: ",reverse_eq_rate)reactant.procs[process_id]['rate']=forward_eq_rateproduct.procs[reverse_process_id]['rate']=reverse_eq_rate#GH: added this first linereactant.save_process_table()product.save_process_table()# Update the metadata.# If this the forward process was a random proc, increase the repeat count.if(process_idinreactant.get_proc_random_count()):product.inc_proc_random_count(reverse_process_id)product.set_unique_saddle_count(product.get_unique_saddle_count()+1)product.update_lowest_barrier(barrier)# Register the process in the search result file.result_fake={'barrier_reactant_to_product':barrier,'displacement_saddle_distance':0.0,'force_calls_saddle':0,'force_calls_minimization':0,'force_calls_prefactors':0}ifconfig.akmc_server_side_process_search:first_column="search_id"else:first_column="wuid"result={first_column:0,'type':'reverse','results':result_fake}product.append_search_result(result,'reverse from '+str(reactant_number),None)return
[docs]defconnect_states(self,states):''' This function goes through the process tables of all states in the argument and checks if any of the unregistered processes connect these states. It thus tries to connect update the processtables of the states. '''# print "connect_states, states: ",statesforiinstates:proc_tab=i.get_process_table()forjinproc_tab:# print "checking state, process: ",i," ",jifproc_tab[j]['product']!=-1:continueenew=proc_tab[j]['product_energy']energetically_close=[]forstateinstates:ifabs(state.get_energy()-enew)<self.epsilon_e:energetically_close.append(state)# Perform distance checks on the energetically close configurations.iflen(energetically_close)>0:# print "energetically close: ",energetically_closepnew=i.get_process_product(j)forstateinenergetically_close:p=state.get_reactant()# print "atoms.match between state, process, state: ",i," ",j," ",stateifatoms.match(p,pnew,config.comp_eps_r,config.comp_neighbor_cutoff,True):# Update the reactant state to point at the new state id.# print "structures match"self.register_process(i.number,state.number,j)
[docs]defconnect_state_sets(self,states1,states2):''' This function goes through the process tables of all states in states1 checks if any of the unregistered processes connect to a state in state2. It thus tries to connect update the processtables of the states. '''# print "connect_state_sets: ",states1," ",states2foriinstates1:proc_tab=i.get_process_table()forjinproc_tab:# print "checking state, process: ",i," ",jifproc_tab[j]['product']!=-1:continueenew=proc_tab[j]['product_energy']energetically_close=[]forstateinstates2:ifabs(state.get_energy()-enew)<self.epsilon_e:energetically_close.append(state)# Perform distance checks on the energetically close configurations.iflen(energetically_close)>0:# print "energetically close: ",energetically_closepnew=i.get_process_product(j)forstateinenergetically_close:p=state.get_reactant()# print "atoms.match between state, process, state: ",i," ",j," ",stateifatoms.match(p,pnew,config.comp_eps_r,config.comp_neighbor_cutoff,True):# Update the reactant state to point at the new state id.# print "structures match"self.register_process(i.number,state.number,j)foriinstates2:proc_tab=i.get_process_table()forjinproc_tab:# print "checking state, process: ",i," ",jifproc_tab[j]['product']!=-1:continueenew=proc_tab[j]['product_energy']energetically_close=[]forstateinstates1:ifabs(state.get_energy()-enew)<self.epsilon_e:energetically_close.append(state)# Perform distance checks on the energetically close configurations.iflen(energetically_close)>0:# print "energetically close: ",energetically_closepnew=i.get_process_product(j)forstateinenergetically_close:p=state.get_reactant()# print "atoms.match between state, process, state: ",i," ",j," ",stateifatoms.match(p,pnew,config.comp_eps_r,config.comp_neighbor_cutoff,True):# Update the reactant state to point at the new state id.# print "structures match"self.register_process(i.number,state.number,j)