def align_all_phases(self): """ align_all_phases() Makes sure the eigenfunctions saved to file does not change sign from one R to another. """ #File where the eigenstates are stored. filename = name_gen.electronic_eigenstates_R(self.basis.config) m_max = self.basis.config.m_max #q_max is the same as mu_max. q_max = self.basis.config.mu_max f = tables.openFile(filename, "r+") try: for m in range(-m_max, m_max + 1): m_group = name_gen.m_name(m) for q in range(q_max + 1): q_group = name_gen.q_name(q) V = eval("f.root.%s.%s.V"%(m_group, q_group)) #Flipping the appropriate wavefunctions. self.align_phases(V) finally: f.close()
def el_tdse_problem_parameters(): """ filename, m, q, E_lim = el_tdse_problem_parameters() This is the place to choose the problem parameters of the electronic TDSE problem. """ #The m values to be included in the TDSE basis. m = [0] #The q values to be included in the TDSE basis. q = [0,1,2,3] #The highest energy states to include (for R = 2). E_lim = 4 #Name of the file where the electronic states are stored. #---------------- #Independent problem: #filename = "el_states_m_0_nu_25_mu_15_beta_1_00_theta_0_00.h5" #------------- #Generate name from info in el_tise_problem_parameters(). m_max, nu_max, mu_max, R_grid, beta, theta = el_tise_problem_parameters() conf = config.Config(m = m_max, nu = nu_max, mu = mu_max, R = R_grid[0], beta = beta, theta = theta) filename = name_gen.electronic_eigenstates_R(conf) #------------- return filename, m, q, E_lim
def save_eigenfunctions_R(self, E, V, R): """ save_eigenfunctions_R(E, V, R) Saves the eigenfunctions and eigenvalues to an HDF5 file, sorted by m and q quantum number. Used when evaluating for several R. Parameters ---------- E : 1D float array, containing the sorted eigenvalues. V : 2D complex array, containing the normalized eigenvectors. R : float, the internuclear distance in this case. Notes ----- Assumes that the file is already made, the arrays are initialized, and the basis instance and the R vector are stored. The file is initialized from the assumption that the eigenstates are equally distributed among the q values. Occasionaly this is not the case, due to either our q-finding method, numerical inaccuracies, or perhaps the problem itself. This is most common when mu_max < 15. When this occurs, it leads to an error during runtime. """ #Construct an appropriate filename. filename = name_gen.electronic_eigenstates_R(self.basis.config) #Organizing with regards to the quantum numbers. E_and_V_dictionary = self.sort_in_m_and_q(E,V) #Open an HDF5 file, provided it exists. f = tables.openFile(filename, 'r+') try: R_grid = f.root.R_grid[:] #Find index of current R in the R_grid. R_index = find(R_grid == self.basis.config.R)[0] #The file is organized in this way: #/ # R_grid # config # m/ # q/ # E # V for m_key, m_value in E_and_V_dictionary.iteritems(): for q_key, q_value in m_value.iteritems(): #Storing E & V at the right place in the arrays. E_handle = eval("f.root.%s.%s.E"%(m_key, q_key)) E_handle[:,R_index] = E_and_V_dictionary[m_key][q_key][0] V_handle = eval("f.root.%s.%s.V"%(m_key, q_key)) V_handle[:,:,R_index] =E_and_V_dictionary[m_key][q_key][1] finally: f.close()
def __init__(self, path_to_output_dir): """ Analysis(path_to_output_dir) Constructor. Makes an instance of the Analysis class. Parameters ---------- path_to_output_dir : string, the path to the relevant output directory. """ #Remove trailing slash. if len(path_to_output_dir.split("/")[-1]) == 0: path_to_output_dir = path_to_output_dir[:-1] self.path_to_output_dir = path_to_output_dir #Name of the file where the vibrational things are stored. self.name_vib_states = "../Data/vib_states_%s.h5"%( path_to_output_dir.split("/")[-1]) #Name of file where the electronic couplings are. f = tables.openFile(self.name_vib_states) self.name_el_couplings = "../" + f.root.electronicFilename[0] self.overlap_matrix = f.root.overlap[:] self.spline_info = f.root.splineInfo[:] f.close() #Name of the file where the electronic states are. el_config = config.Config(filename = self.name_el_couplings) self.name_el_states = "../" + name_gen.electronic_eigenstates_R( el_config) #Loading the vibrational B-spline basis. self.vib_methods = vibrational_methods.Bspline_basis( float(self.spline_info[0]), float(self.spline_info[1]), int(self.spline_info[2]), int(self.spline_info[3])) self.vib_basis = bsplines.load_spline_object(self.name_vib_states) #Basis sizes. f = tables.openFile(self.name_el_couplings) self.el_basis_size = f.root.index_array.shape[0] self.index_array = f.root.index_array[:] f.close() self.vib_basis_size = self.vib_basis.number_of_bsplines self.basis_size = self.vib_basis_size * self.el_basis_size self.psi_final = None self.splines = None self.times = None self.field = None #Continuum. self.find_continuum()
def __init__(self, filename = None, conf = None): """ Contructor should be further implemented in the subclasses. """ if filename != None: conf = config.Config(filename = filename) elif conf != None: pass else: raise IOError("Wrong input parameters.") #Adds the config instance as a class variable. self.config = conf #Name of HDF5 file where the eigenstates are stored. self.eigenstate_file = name_gen.electronic_eigenstates_R(self.config) #Variables to be filled in the subclasses. self.coupling_file = None self.laser_info = None
def save_electronic_eigenstates(m_max, nu_max, mu_max, R_grid, beta, theta): """ save_electronic_eigenstates(m_max, nu_max, mu_max, R_grid, beta, theta) This program solves the electronic TISE for a range of internuclear distances, given in <R_grid>, and stores them in an HDF5 file. This program must be run in parallel. Example ------- To run this program on 5 processors: $ mpirun -n 5 python electronic_BO.py """ #Parallel stuff #-------------- #Get processor 'name'. my_id = pypar.rank() #Get total number of processors. nr_procs = pypar.size() #Get number of tasks. nr_tasks = len(R_grid) #Get a list of the indices of this processors share of R_grid. my_tasks = nice_stuff.distribute_work(nr_procs, nr_tasks, my_id) #The processors will be writing to the same file. #In order to avoid problems, the procs will do a relay race of writing to #file. This is handeled by blocking send() and receive(). #Hopefully there will not be to much waiting. #ID of the processor that will start writing. starter = 0 #ID of the processor that will be the last to write. ender = (nr_tasks - 1) % nr_procs #Buffer for the baton, i.e. the permission slip for file writing. baton = r_[0] #The processor one is to receive the baton from. receive_from = (my_id - 1) % nr_procs #The processor one is to send the baton to. send_to = (my_id + 1) % nr_procs #------------------------------- #Initializing the HDF5 file #-------------------------- if my_id == 0: #Creates a config instance. my_config = config.Config(m = m_max, nu = nu_max, mu = mu_max, R = R_grid[0], beta = beta, theta = theta) #Number of basis functions. basis_size = (2 * m_max + 1) * (nu_max + 1) * (mu_max + 1) #Generate a filename. filename = name_gen.electronic_eigenstates_R(my_config) f = tables.openFile(filename, 'w') try: f.createArray("/", "R_grid", R_grid) #Looping over the m values. for m in range(-1 * m_max, m_max + 1): #Creating an m group in the file. m_group = name_gen.m_name(m) f.createGroup("/", m_group) #Looping over th q values. for q in range(mu_max + 1): #Creating a q group in the m group in the file. q_group = name_gen.q_name(q) f.createGroup("/%s/"%m_group, q_group) #Initializing the arrays for the eigenvalues and states. f.createCArray('/%s/%s/'%(m_group, q_group),'E', tables.atom.FloatAtom(), (basis_size/(mu_max + 1), nr_tasks), chunkshape=(basis_size/(mu_max + 1), 1)) f.createCArray('/%s/%s/'%(m_group, q_group),'V', tables.atom.ComplexAtom(16), (basis_size, basis_size/(mu_max + 1), nr_tasks), chunkshape=(basis_size, basis_size/(mu_max + 1), 1)) finally: f.close() #Save config instance. my_config.save_config(filename) #---------------------------------- #Solving the TISE #---------------- #Looping over the tasks of this processor. for i in my_tasks: #Creating TISE instance. tise = tise_electron.TISE_electron(m = m_max, nu = nu_max, mu = mu_max, R = R_grid[i], beta = beta, theta = theta) #Diagonalizing the hamiltonian. E,V = tise.solve() #First file write. (Send, but not receive baton.) if starter == my_id: #Write to file. tise.save_eigenfunctions_R(E, V, R_grid[i]) #Avoiding this statement 2nd time around. starter = -1 #Sending the baton to the next writer. pypar.send(baton, send_to, use_buffer = True) #Last file write. (Receive, but not send baton.) elif i == my_tasks[-1] and ender == my_id : #Receiving the baton from the previous writer. pypar.receive(receive_from, buffer = baton) #Write to file. tise.save_eigenfunctions_R(E, V, R_grid[i]) #The rest of the file writes. else: #Receiving the baton from the previous writer. pypar.receive(receive_from, buffer = baton) #Write to file. tise.save_eigenfunctions_R(E, V, R_grid[i]) #Sending the baton to the next writer. pypar.send(baton, send_to, use_buffer = True) #Showing the progress of the work. if my_id == 0: nice_stuff.status_bar("Electronic BO calculations", i, len(my_tasks)) #---------------------------- #Letting everyone catch up. pypar.barrier() #Since the sign of the eigenfunctions are completely arbitrary, one must #make sure they do not change sign from one R to another. if my_id == 0: tise.align_all_phases() #Letting 0 catch up. pypar.barrier()