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()