def connect_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," ",states2 for i in states1: proc_tab = i.get_process_table() for j in proc_tab: # print "checking state, process: ",i," ",j if proc_tab[j]['product'] != -1: continue enew = proc_tab[j]['product_energy'] energetically_close = [] for state in states2: if abs(state.get_energy() - enew) < self.epsilon_e: energetically_close.append(state) # Perform distance checks on the energetically close configurations. if len(energetically_close) > 0: # print "energetically close: ",energetically_close pnew = i.get_process_product(j) for state in energetically_close: p = state.get_reactant() # print "atoms.match between state, process, state: ",i," ",j," ",state if atoms.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) for i in states2: proc_tab = i.get_process_table() for j in proc_tab: # print "checking state, process: ",i," ",j if proc_tab[j]['product'] != -1: continue enew = proc_tab[j]['product_energy'] energetically_close = [] for state in states1: if abs(state.get_energy() - enew) < self.epsilon_e: energetically_close.append(state) # Perform distance checks on the energetically close configurations. if len(energetically_close) > 0: # print "energetically close: ",energetically_close pnew = i.get_process_product(j) for state in energetically_close: p = state.get_reactant() # print "atoms.match between state, process, state: ",i," ",j," ",state if atoms.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)
def get_product_state(self, state_number, process_id): ''' Returns a State object referenced by state_number and process_id. ''' #TODO: Compare configuration of product with existing states. # If the number of states in state_table is zero #we need to add the zero state and energy to the state table. if self.get_num_states() == 0: zst = self.get_state(0) self.append_state_table(zst.get_energy()) # Load the state object containing the process we want the product for. st = self.get_state(state_number) st.load_process_table() # Get the state number for the product. newstnr = st.procs[process_id]['product'] # If the product id is not initialized, make sure it is not a copy of an existing state. # Otherwise, create it, connect it to st, and return it. if newstnr == -1: # Make a list of states for which we need to compare configurations. enew = st.procs[process_id]['product_energy'] energetically_close = [] for id in range(self.get_num_states()): if abs(self.get_state(id).get_energy() - enew) < self.epsilon_e: energetically_close.append(id) # Perform distance checks on the energetically close configurations. if len(energetically_close) > 0: pnew = st.get_process_product(process_id) for id in energetically_close: p = self.get_state(id).get_reactant() if atoms.match(p, pnew, config.comp_eps_r, config.comp_neighbor_cutoff, True): if id == state_number: logging.warning("State %i process %i leads back to initial state", state_number, process_id) self.register_process(st.number, id, process_id) return self.get_state(id) # The id for the new state is the number of states. newstnr = self.get_num_states() # Create the new state object. newst = self.StateClass(statepath = self.state_path(newstnr), statenumber = newstnr, statelist = self, previous_state_num = state_number, reactant_path = st.proc_product_path(process_id)) self.register_process(st.number, newstnr, process_id) # Append the new state to the state table. self.append_state_table(st.procs[process_id]['product_energy']) # The product state already exists, so get it. else: newst = self.get_state(newstnr) # Return the product state. return newst
def finish_minimization(self, result): result1 = self.load_result(self.finished_min1_name) result2 = result atoms1 = io.loadcon(result1['min.con']) atoms2 = io.loadcon(result2['min.con']) results_dat1 = io.parse_results(result1['results.dat']) results_dat2 = io.parse_results(result2['results.dat']) self.data['force_calls_minimization'] += results_dat1['total_force_calls'] self.data['force_calls_minimization'] += results_dat2['total_force_calls'] is_reactant = lambda a: atoms.match(a, self.reactant, config.comp_eps_r, config.comp_neighbor_cutoff, False) tc1 = io.parse_results(result1['results.dat'])['termination_reason'] tc2 = io.parse_results(result2['results.dat'])['termination_reason'] termination_reason1 = self.job_termination_reasons['minimization'][tc1] termination_reason2 = self.job_termination_reasons['minimization'][tc2] if termination_reason1 == 'max_iterations' or termination_reason2 == 'max_iterations': self.data['termination_reason'] = 9 self.data['potential_energy_saddle'] = 0.0 self.data['potential_energy_reactant'] = 0.0 self.data['potential_energy_product'] = 0.0 self.data['barrier_reactant_to_product'] = 0.0 self.data['barrier_product_to_reactant'] = 0.0 return # Check the connectivity of the process if (not is_reactant(atoms1) and not is_reactant(atoms2)) or \ (is_reactant(atoms1) and is_reactant(atoms2)): # Not connected self.data['termination_reason'] = 6 self.data['potential_energy_saddle'] = 0.0 self.data['potential_energy_reactant'] = 0.0 self.data['potential_energy_product'] = 0.0 self.data['barrier_reactant_to_product'] = 0.0 self.data['barrier_product_to_reactant'] = 0.0 return elif is_reactant(atoms1): reactant_results_dat = results_dat1 product_results_dat = results_dat2 self.finished_reactant_name = self.finished_min1_name self.finished_product_name = self.finished_min2_name elif is_reactant(atoms2): reactant_results_dat = results_dat2 product_results_dat = results_dat1 self.finished_reactant_name = self.finished_min2_name self.finished_product_name = self.finished_min1_name self.data['potential_energy_reactant'] = reactant_results_dat['potential_energy'] self.data['potential_energy_product'] = product_results_dat['potential_energy'] self.data['barrier_reactant_to_product'] = self.data['potential_energy_saddle'] - \ self.data['potential_energy_reactant'] self.data['barrier_product_to_reactant'] = self.data['potential_energy_saddle'] - \ self.data['potential_energy_product']
def add_state(self, result_files, result_info): energy = result_info['minimum_energy'] energetically_close = [] added = True if len(self.energy_table) != 0: for row in self.energy_table: if abs(energy - row['energy']) < config.comp_eps_e: energetically_close.append(row['state']) if len(energetically_close) != 0: a1 = io.loadcon(result_files['min.con']) for state_number in energetically_close: state_con_path = os.path.join(config.path_states, str(state_number), 'minimum.con') a2 = io.loadcon(state_con_path) if atoms.match(a1, a2, config.comp_eps_r, config.comp_neighbor_cutoff, True): logger.info("Found a repeat of state %i", state_number) added = False for row in self.energy_table.rows: if row['state'] == state_number: row['repeats'] += 1 self.energy_table.write() break if added: state_number = len(self.energy_table) row = {'state': state_number, 'energy': energy, 'repeats': 0} self.energy_table.add_row(row) self.energy_table.rows.sort(key=lambda r: -r['energy']) self.energy_table.write() state_path = os.path.join(config.path_states, str(state_number)) os.mkdir(state_path) result_files['minimum.con'] = result_files['min.con'] del result_files['min.con'] for fn, fh in result_files.iteritems(): if hasattr(fh, 'getvalue') == False: continue p = os.path.join(state_path, fn) f = open(p, 'w') f.write(fh.getvalue()) f.close() return added
def add_state(self, result_files, result_info): energy = result_info['minimum_energy'] energetically_close = [] added = True if len(self.energy_table) != 0: for row in self.energy_table: if abs(energy-row['energy']) < config.comp_eps_e: energetically_close.append(row['state']) if len(energetically_close) != 0: a1 = io.loadcon(result_files['min.con']) for state_number in energetically_close: state_con_path = os.path.join(config.path_states, str(state_number), 'minimum.con') a2 = io.loadcon(state_con_path) if atoms.match(a1, a2, config.comp_eps_r, config.comp_neighbor_cutoff, True): logger.info("Found a repeat of state %i", state_number) added = False for row in self.energy_table.rows: if row['state'] == state_number: row['repeats'] += 1 self.energy_table.write() break if added: state_number = len(self.energy_table) row = { 'state':state_number, 'energy':energy, 'repeats':0 } self.energy_table.add_row(row) self.energy_table.rows.sort(key=lambda r:-r['energy']) self.energy_table.write() state_path = os.path.join(config.path_states, str(state_number)) os.mkdir(state_path) result_files['minimum.con'] = result_files['min.con'] del result_files['min.con'] for fn, fh in result_files.iteritems(): if hasattr(fh, 'getvalue') == False: continue p = os.path.join(state_path, fn) f = open(p, 'w') f.write(fh.getvalue()) f.close() return added
def find_repeat(self, saddle_file, barrier): self.load_process_table() energy_a = barrier p1 = io.loadcon(saddle_file) for id in self.procs.keys(): energy_b = self.procs[id]['barrier'] if abs(energy_a - energy_b) > config.comp_eps_e: continue if id in self.con_cache: p2 = self.con_cache[id] else: p2 = io.loadcon(self.proc_saddle_path(id)) self.con_cache[id] = p2 if atoms.match(p1, p2, config.comp_eps_r, config.comp_neighbor_cutoff, False): return id return None
def get_product_state(self, state_number, process_id): ''' Returns a State object referenced by state_number and process_id. ''' #TODO: Compare configuration of product with existing states. # If the number of states in state_table is zero #we need to add the zero state and energy to the state table. if self.get_num_states() == 0: zst = self.get_state(0) self.append_state_table(zst.get_energy()) # Load the state object containing the process we want the product for. st = self.get_state(state_number) st.load_process_table() # Get the state number for the product. newstnr = st.procs[process_id]['product'] # If the product id is not initialized, make sure it is not a copy of an existing state. # Otherwise, create it, connect it to st, and return it. if newstnr == -1: # Make a list of states for which we need to compare configurations. enew = st.procs[process_id]['product_energy'] energetically_close = [] for id in range(self.get_num_states()): if abs(self.get_state(id).get_energy() - enew) < self.epsilon_e: energetically_close.append(id) # Perform distance checks on the energetically close configurations. if len(energetically_close) > 0: pnew = st.get_process_product(process_id) for id in energetically_close: p = self.get_state(id).get_reactant() if atoms.match(p, pnew, config.comp_eps_r, config.comp_neighbor_cutoff, True): if id == state_number: logging.warning( "State %i process %i leads back to initial state", state_number, process_id) self.register_process(st.number, id, process_id) return self.get_state(id) # The id for the new state is the number of states. newstnr = self.get_num_states() # Create the new state object. newst = self.StateClass( statepath=self.state_path(newstnr), statenumber=newstnr, statelist=self, previous_state_num=state_number, reactant_path=st.proc_product_path(process_id)) self.register_process(st.number, newstnr, process_id) # Append the new state to the state table. self.append_state_table(st.procs[process_id]['product_energy']) # The product state already exists, so get it. else: newst = self.get_state(newstnr) # Return the product state. return newst
def register_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_number reactant.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. if reactant_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. if product.get_num_procs() != 0: product.load_process_table() reverse_procs = product.get_process_table() candidates = [] # An alike reverse process might already exist for id in reverse_procs.keys(): proc = reverse_procs[id] if ( abs(proc['saddle_energy'] - saddle_energy) < self.epsilon_e ) and (proc['product']==-1): candidates.append(id) if len(candidates): reactant_conf = reactant.get_reactant() for id in candidates: conf = product.get_process_product(id) # The process is known but has not been accepted yet. if atoms.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() # Remember we are now looking at the reverse processes reverse_procs[id]['product'] = reactant_number reverse_procs[id]['saddle_energy'] = saddle_energy reverse_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'] = reactant.procs[process_id]['product_prefactor'] * math.exp( - ( saddle_energy - product.get_energy() ) /self.kT) 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. 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 state barrier = saddle_energy - product.get_energy() product.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), repeats = 0) product.save_process_table() # Update the metadata. # If this the forward process was a random proc, increase the repeat count. if(process_id in reactant.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} if config.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
def register_results(comm, current_state, states): logger.info("Registering results") if os.path.isdir(config.path_jobs_in): shutil.rmtree(config.path_jobs_in) os.makedirs(config.path_jobs_in) # Function used by communicator to determine whether to discard a result def keep_result(name): return True transition = None num_registered = 0 speedup = 0 number_state = [] numres = 0 for result in comm.get_results(config.path_jobs_in, keep_result): # The result dictionary contains the following key-value pairs: # reactant.con - an array of strings containing the reactant # product.con - an array of strings containing the product # results.dat - an array of strings containing the results # id - StateNumber_WUID # # The reactant, product, and mode are passed as lines of the files because # the information contained in them is not needed for registering results state_num = int(result['name'].split("_")[0]) id = int(result['name'].split("_")[1]) + result['number'] state = states.get_state(state_num) # read in the results result['results'] = io.parse_results(result['results.dat']) speedup += result['results']['speedup'] if result['results']['transition_found'] == 1: result['results']['transition_time_s'] += state.get_time() a = result['results']['potential_energy_product'] f = open("states/0/end_state_table", "a+") lines = f.readlines() f.close() proc = [] number_state.append(0) count = 0 state_match = 0 flag = 0 product = io.loadcon(result['product.con']) for i in range(0, numres): product2 = io.loadcon("states/0/procdata/product_%i.con" % i) if atoms.match(product, product2, config.comp_eps_r, config.comp_neighbor_cutoff, True): if flag == 0: state_match = number_state[i] number_state[numres] = state_match flag = 1 break count = 0 time_to_state = 0 time_check = 0 for line in lines[1:]: l = line.split() proc.append({ 'state': l[0], 'views': l[1], 'rate': l[2], 'time': l[3] }) if float(l[3]) > time_check: time_check = float(l[3]) if flag == 0: number_state[numres] = int(l[0]) + 1 else: if state_match == int(l[0]): proc[count]['views'] = str(int(l[1]) + 1) time_to_state = float( l[3]) + result['results']['transition_time_s'] proc[count]['time'] = str(time_to_state) proc[count]['rate'] = str( 1 / (time_to_state / float(proc[count]['views']))) count += 1 if flag == 0: proc.append({ 'state': number_state[numres], 'views': 1, 'rate': 1 / (float(time_check + result['results']['transition_time_s'])), 'time': time_check + result['results']['transition_time_s'] }) g = open("states/0/end_state_table", "w") g.write('state views rate time \n') for j in range(0, len(proc)): g.write(str(proc[j]['state'])) g.write(" ") g.write(str(proc[j]['views'])) g.write(" ") g.write(str(proc[j]['rate'])) g.write(" ") g.write(str(proc[j]['time'])) g.write("\n") g.close() numres += 1 time = result['results']['transition_time_s'] process_id = state.add_process(result) logger.info("Found transition with time %.3e", time) if not transition and current_state.number == state.number: transition = {'process_id': process_id, 'time': time} state.zero_time() else: state.inc_time(result['results']['simulation_time_s']) num_registered += 1 logger.info("Processed %i (result) searches", num_registered) if num_registered >= 1: logger.info("Average speedup is %f", speedup / num_registered) return num_registered, transition, speedup
def finish_minimization(self, result): result1 = self.load_result(self.finished_min1_name) result2 = result atoms1 = io.loadcon(result1['min.con']) atoms2 = io.loadcon(result2['min.con']) results_dat1 = io.parse_results(result1['results.dat']) results_dat2 = io.parse_results(result2['results.dat']) self.data['force_calls_minimization'] += results_dat1[ 'total_force_calls'] self.data['force_calls_minimization'] += results_dat2[ 'total_force_calls'] is_reactant = lambda a: atoms.match( a, self.reactant, config.comp_eps_r, config.comp_neighbor_cutoff, False) tc1 = io.parse_results(result1['results.dat'])['termination_reason'] tc2 = io.parse_results(result2['results.dat'])['termination_reason'] termination_reason1 = self.job_termination_reasons['minimization'][tc1] termination_reason2 = self.job_termination_reasons['minimization'][tc2] if termination_reason1 == 'max_iterations' or termination_reason2 == 'max_iterations': self.data['termination_reason'] = 9 self.data['potential_energy_saddle'] = 0.0 self.data['potential_energy_reactant'] = 0.0 self.data['potential_energy_product'] = 0.0 self.data['barrier_reactant_to_product'] = 0.0 self.data['barrier_product_to_reactant'] = 0.0 return # Check the connectivity of the process if (not is_reactant(atoms1) and not is_reactant(atoms2)) or \ (is_reactant(atoms1) and is_reactant(atoms2)): # Not connected self.data['termination_reason'] = 6 self.data['potential_energy_saddle'] = 0.0 self.data['potential_energy_reactant'] = 0.0 self.data['potential_energy_product'] = 0.0 self.data['barrier_reactant_to_product'] = 0.0 self.data['barrier_product_to_reactant'] = 0.0 return elif is_reactant(atoms1): reactant_results_dat = results_dat1 product_results_dat = results_dat2 self.finished_reactant_name = self.finished_min1_name self.finished_product_name = self.finished_min2_name elif is_reactant(atoms2): reactant_results_dat = results_dat2 product_results_dat = results_dat1 self.finished_reactant_name = self.finished_min2_name self.finished_product_name = self.finished_min1_name self.data['potential_energy_reactant'] = reactant_results_dat[ 'potential_energy'] self.data['potential_energy_product'] = product_results_dat[ 'potential_energy'] self.data['barrier_reactant_to_product'] = self.data['potential_energy_saddle'] - \ self.data['potential_energy_reactant'] self.data['barrier_product_to_reactant'] = self.data['potential_energy_saddle'] - \ self.data['potential_energy_product']
def register_results(comm, current_state, states): logger.info("Registering results") if os.path.isdir(config.path_jobs_in): shutil.rmtree(config.path_jobs_in) os.makedirs(config.path_jobs_in) # Function used by communicator to determine whether to discard a result def keep_result(name): return True transition = None num_registered = 0 speedup = 0 number_state = [] numres = 0 for result in comm.get_results(config.path_jobs_in, keep_result): # The result dictionary contains the following key-value pairs: # reactant.con - an array of strings containing the reactant # product.con - an array of strings containing the product # results.dat - an array of strings containing the results # id - StateNumber_WUID # # The reactant, product, and mode are passed as lines of the files because # the information contained in them is not needed for registering results state_num = int(result['name'].split("_")[0]) id = int(result['name'].split("_")[1]) + result['number'] state = states.get_state(state_num) # read in the results result['results'] = io.parse_results(result['results.dat']) speedup += result['results']['speedup'] if result['results']['transition_found'] == 1: result['results']['transition_time_s'] += state.get_time() a = result['results']['potential_energy_product'] f = open ("states/0/end_state_table","a+") lines = f.readlines() f.close() proc = [] number_state.append(0) count = 0 state_match = 0 flag = 0 product = io.loadcon (result['product.con']) for i in range(0, numres): product2 = io.loadcon ("states/0/procdata/product_%i.con" % i ) if atoms.match(product, product2,config.comp_eps_r,config.comp_neighbor_cutoff,True): if flag == 0: state_match = number_state[i] number_state[numres] = state_match flag = 1 break count = 0 time_to_state = 0 time_check = 0 for line in lines[1:]: l = line.split() proc.append({'state': l[0], 'views': l[1], 'rate': l[2], 'time': l[3]}) if float(l[3]) > time_check: time_check = float(l[3]) if flag == 0: number_state[numres] = int(l[0])+1 else: if state_match == int(l[0]): proc[count]['views'] = str(int(l[1]) + 1) time_to_state = float(l[3]) + result['results']['transition_time_s'] proc[count]['time'] = str(time_to_state) proc[count]['rate'] = str(1/(time_to_state/float(proc[count]['views']))) count += 1 if flag == 0: proc.append({'state': number_state[numres], 'views': 1, 'rate': 1/(float(time_check+result['results']['transition_time_s'])) , 'time': time_check + result['results']['transition_time_s']}) g = open ("states/0/end_state_table","w") g.write('state views rate time \n') for j in range(0,len(proc)): g.write(str(proc[j]['state'])) g.write(" ") g.write(str(proc[j]['views'])) g.write(" ") g.write(str(proc[j]['rate'])) g.write(" ") g.write(str(proc[j]['time'])) g.write("\n") g.close() numres += 1 time = result['results']['transition_time_s'] process_id = state.add_process(result) logger.info("Found transition with time %.3e", time) if not transition and current_state.number==state.number: transition = {'process_id':process_id, 'time':time} state.zero_time() else: state.inc_time(result['results']['simulation_time_s']) num_registered += 1 logger.info("Processed %i (result) searches", num_registered) if num_registered >=1: logger.info("Average speedup is %f", speedup/num_registered) return num_registered, transition, speedup