Source code for eon.statelist


""" The statelist module. """

import logging
logger = logging.getLogger('statelist')
import os

from eon import atoms
from eon.config import config


[docs] class StateList: """ The StateList class. Serves as an interface to State objects and StateList metadata. """ def __init__(self, StateClass, initial_state = None): ''' Check to see if state_path exists and that state zero exists. Initializes state zero when passed a initial_state only if state zero doesn't already exist. ''' self.path = config.path_states self.epsilon_e = config.comp_eps_e self.epsilon_r = config.comp_eps_r self.use_identical = config.comp_use_identical self.StateClass = StateClass # Paths self.state_table_path = os.path.join(self.path, "state_table") # Create the statelist directory if it does not exist. if not os.path.isdir(self.path): logger.warning("State list path does not exist; Creating: %s" % self.path) os.makedirs(self.path) open(self.state_table_path, 'w').close() # Create the zero state directory if it does not exist. if not os.path.isdir(os.path.join(self.path, "0")): if initial_state is None: raise IOError("Missing zeroth state directory and no reactant provided") self.StateClass(statepath = os.path.join(self.path, "0"), statenumber = 0, statelist = self, previous_state_num = -1, reactant_path = initial_state) # Other class variables. self.states = {} self.state_table = None
[docs] def get_num_states(self): """ Returns the number of lines in the state_table file. """ self.load_state_table() return len(self.state_table)
[docs] 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
[docs] def get_state(self, state_number): ''' Returns a state object. ''' if state_number in self.states: return self.states[state_number] st = self.StateClass(statepath = os.path.join(self.path, str(state_number)), statenumber = state_number, statelist = self) self.states[state_number] = st return st
[docs] def load_state_table(self): if self.state_table is None: f = open(self.state_table_path, 'r') lines = f.readlines() f.close() self.state_table = [] for l in lines: self.state_table.append(float(l.strip().split()[1]))
[docs] def save_state_table(self): if self.state_table != None: f = open(self.state_table_path, 'w') for i in range(len(self.state_table)): f.write("% 7d %16.5f\n" % (i, self.state_table[i])) f.close()
[docs] def append_state_table(self, energy): number = self.get_num_states() f = open(self.state_table_path, 'a') f.write("% 7d %16.5f\n" % (number, energy)) f.close() if self.state_table != None: self.state_table.append(energy)
[docs] def state_path(self, state_number): """ Utility function to return the compiled path of a state, whether it exists or not. """ return os.path.join(self.path, str(state_number))
if __name__ == "__main__": pass