def save_hdf5(fid, variables=[ 'geo_info', 'geo_spec_all', 'ao_spec', 'ao_spherical', 'mo_coeff_all', 'mo_energy_all', 'mo_occ_all', 'sym', 'index_list' ], hdf5mode='w', **kwargs): '''Writes all global variables specified in :literal:`variables` and all additional :literal:`kwargs` to an HDF5 file. ''' from orbkit.output import hdf5_open, hdf5_append # Save HDF5 File display('Saving Hierarchical Data Format file (HDF5) to %s...' % fid) data_stored = [] for HDF5_file in hdf5_open(fid, mode=hdf5mode): for i in variables: if i in globals(): data = globals()[i] if not (data == [] or data is None): if i == 'sym': data = numpy.array([[k, l] for k, l in data.items()]) hdf5_append(data, HDF5_file, name=i) data_stored.append(i) elif i not in kwargs: raise ValueError( 'Variable `%s` is not in globals() or in **kwargs' % i) for j in kwargs.keys(): hdf5_append(kwargs[j], HDF5_file, name=j) data_stored.append(j) display('\tContent: ' + ', '.join(data_stored))
def read_hdf5(fid, variables=[ 'geo_info', 'geo_spec_all', 'ao_spec', 'ao_spherical', 'mo_coeff_all', 'mo_energy_all', 'mo_occ_all', 'sym', 'index_list' ]): '''Reads all variables specified in :literal:`variables` from an HDF5 file created with :literal:`write_hdf5` and appends this data to the globals() of this module. ''' from orbkit.output import hdf5_open, hdf52dict # Read HDF5 File display('Reading Hierarchical Data Format file (HDF5) File from %s' % fid) data_stored = [] for HDF5_file in hdf5_open(fid, mode='r'): for i in variables: try: globals()[i] = hdf52dict(i, HDF5_file) data_stored.append(i) if i == 'sym': s = dict(globals()[i]) globals()[i] = {} for k, l in s.items(): globals()[i][k] = int(l) except KeyError: pass if not data_stored: raise IOError( 'Could not find any data in `%s` for the selected `variables`.' % fid) display('\tFound: ' + ', '.join(data_stored))
def fermions_stda(fname, select_state=None, threshold=0.0, **kwargs): '''Reads FermiONs++ TDDFT output. **Parameters:** fname: str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. select_state : None or list of int, optional If not None, specifies the states to be read (0 corresponds to the ground state), else read all electronic states. threshold : float, optional Specifies a read threshold for the CI coefficients. **Returns:** ci : list of CIinfo class instances See :ref:`Central Variables` for details. ''' display('\nReading data of simplified TDA calculation from FermiONs++...') return fermions_tdscf(fname, td_typ='stda', st_typ='singlet', select_state=select_state, threshold=threshold, **kwargs)
def hx_network_creator(rho, filename): '''Creates a ZIBAmira hx-network file including a colormap file (.cmap) adjusted to the density for the easy depiction of the density. ''' from .hx_network_draft import hx_network filename += '.hx' if not filename.endswith('.hx') else '' # Create a .cmap colormap file using the default values display('\tCreating ZIBAmira colormap file...\n\t\t' + filename.replace('.hx', '.cmap')) assert (rho.shape != tuple(grid.N_)), 'The grid does not fit the data.' colormap_creator(rho, filename.replace('.hx', '.cmap')) # Create a .hx network file based on the file orbkit.hx_network_draft.py # Open an empty file fid = open(filename, 'w') # Copy the content of the draft file and replace the keywords fid.write( hx_network.replace("FILENAME", os.path.splitext(os.path.basename(filename))[0])) # Close the file fid.close()
def hx_network_creator(rho, filename): '''Creates a ZIBAmira hx-network file including a colormap file (.cmap) adjusted to the density for the easy depiction of the density. ''' from orbkit.hx_network_draft import hx_network # Create a .cmap colormap file using the default values display('\tCreating ZIBAmira colormap file...\n\t\t%(f)s.cmap' % {'f': filename}) AssertionError( rho.shape != tuple(grid.N_)), 'The grid does not fit the data.' colormap_creator(rho, filename) # Create a .hx network file based on the file orbkit.hx_network_draft.py display('\tCreating ZIBAmira network file...\n\t\t%(f)s.hx' % {'f': filename}) # Open an empty file fid = open('%(f)s.hx' % {'f': filename}, 'w') filename = filename.split('/')[-1] # Copy the content of the draft file and replace the keywords fid.write(hx_network.replace("FILENAME", filename)) # Close the file fid.close()
def main_read(fname, all_mo=False, spin=None, itype='auto', check_norm=False, **kwargs): ''' This is the high-lever interface for the orbkit reading routines. **Parameters:** fname: str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. all_mo : bool, optional If True, all molecular orbitals are returned. spin : {None, 'alpha', or 'beta'}, optional If not None, returns exclusively 'alpha' or 'beta' molecular orbitals. itype : str, optional Can be used to manually specify the input filetype. check_norm : bool, optional If True, ORBKIT verifies that molecular orbitals are orthonormal. **Note:** All additional keyword arguments are forwarded to the reading functions. **Returns:** qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot : See :ref:`Central Variables` for details. ''' if isinstance(fname, str): filename = fname else: filename = fname.name if itype == 'auto': itype = find_itype(fname) display('Loading data from {0} type file {1}\n'.format(itype, filename)) qc = readers[itype](fname, all_mo=all_mo, spin=spin, **kwargs) if check_norm: deviation = check_mo_norm(qc) if deviation >= 1e-5: raise ValueError( 'Bad molecular orbital norm: {0:%4e}'.format(deviation)) return qc
def check_sel(count,i,interactive=False): if count == 0: raise IndexError elif count == 1: return 0 message = '\tPlease give an integer from 0 to %d: ' % (count-1) try: if interactive: i = int(raw_input(message)) i = range(count)[i] except (IndexError,ValueError): raise IOError(message.replace(':','!')) else: display('\tSelecting the %s' % ('last element.' if (i == count-1) else 'element %d.' % i)) return i
def hdf5_attributes(filename, gname='', **attrs): warning = [] for f in hdf5_open(filename,mode='a'): for key,value in attrs.items(): if isinstance(value,dict): for k,v in value.items(): if k in f[gname].keys(): f[os.path.join(gname,key)].attrs[k] = v else: warning.append(key) else: if key in f[gname].keys(): f[os.path.join(gname,'data')].attrs[key] = value else: warning.append('data') if warning: display('Warning: The following attributes are not datasets in '+filename) display(', '.join([os.path.join(gname,i) for i in data]))
def order_pm(x, y, backward=True, mu=1e-1, use_factor=False): '''Outdated function to order exclusively the sign of a data set. ''' if backward: st = [-2, 1, -1] else: st = [1, -2, 1] if numpy.ndim(y) == 1: diff = numpy.zeros(2) for rr in range(len(y))[st[0]:st[1]:st[2]]: m = (y[rr + st[2]] - y[rr]) / (x[rr + st[2]] - x[rr]) epol = m * (x[rr + 2 * st[2]] - x[rr]) + y[rr] for ii_d in range(2): diff[ii_d] = (((-1)**ii_d * y[rr + 2 * st[2]]) - epol)**2 if numpy.argmin(numpy.abs(diff)) == 1: y[rr + 2 * st[2]] = -y[rr + 2 * st[2]] elif numpy.ndim(y) == 2: y = numpy.array(y) shape = numpy.shape(y) for rr in range(shape[0])[st[0]:st[1]:st[2]]: for ii_s, sign in [(0, -1), (1, +1)]: f = numpy.ones(shape[1]) if use_factor: f[numpy.abs(y[rr, :]) > mu] = 1 / numpy.abs( y[rr, numpy.abs(y[rr, :]) > mu]) m = (y[rr + st[2], :] - y[rr, :]) / (x[rr + st[2]] - x[rr]) epol = f[:] * (m * (x[rr + 2 * st[2]] - x[rr]) + y[rr, :]) # Euclidean norm (2 norm) current = numpy.sum( (f[:] * sign * y[rr + 2 * st[2], :] - epol[:])**2) # Current value if ii_s == 0: diff = current new_sign = sign elif current < diff: new_sign = sign y[rr + 2 * st[2], :] *= new_sign else: display('Function order_pm only works for vectors and 2D matrices') return y
def test(): ts = unittest.TestSuite() display( '----------------------------------------------------------------------' ) display( ' Testing ORBKIT functionality ' ) display( '----------------------------------------------------------------------\n' ) tsrun = unittest.TextTestRunner(verbosity=2) tests_home = __file__.split('__')[0] + 'test/' for test in tests: ts.addTest(ScriptTestCase(filename=os.path.abspath(tests_home + test))) testdir = tests_home + 'test_tmp' clean(testdir) os.mkdir(testdir) os.chdir(testdir) results = tsrun.run(ts) clean(testdir) sys.exit(len(results.errors + results.failures))
def plot(self,mo_matrix,symmetry='1',title='All',x_label='index', y_label='MO coefficients',output_format='png', plt_dir='Plots',ylim=None,thresh=0.1,x0=0,grid=True,x_grid=None,**kwargs): '''Plots all molecular orbital coefficients of one self.symmetry.''' import pylab as plt from matplotlib.ticker import MultipleLocator import os display('Plotting data of self.symmetry %s to %s/' % (symmetry,plt_dir)) if not os.path.exists(plt_dir): os.makedirs(plt_dir) if numpy.ndim(mo_matrix) == 2: mo_matrix = mo_matrix[:,numpy.newaxis,:] shape = numpy.shape(mo_matrix) def plot_mo(i): fig=plt.figure() plt.rc('xtick', labelsize=16) plt.rc('ytick', labelsize=16) ax = plt.subplot(111) curves=[] for ij in range(shape[2]): Y = mo_matrix[:,i,ij] if x_grid is None: X = numpy.arange(len(Y))+x0 else: X = x_grid if max(numpy.abs(Y)) > thresh: curves.append(ax.plot(X,Y, '.-' ,linewidth=1.5)) plt.xlabel(x_label, fontsize=16); plt.ylabel(y_label, fontsize=16); plt.title('%s: %d.%s'% (title,i+1,symmetry)) plt.ylim(ylim) plt.tight_layout() return fig if output_format == 'pdf': from matplotlib.backends.backend_pdf import PdfPages output_fid = '%s.%s.pdf'% (title,symmetry.replace(' ','_')) display('\t%s' % output_fid) with PdfPages(os.path.join(plt_dir,output_fid)) as pdf: for i in range(shape[1]): fig = plot_mo(i) pdf.savefig(fig,**kwargs) plt.close() elif output_format == 'png': for i in range(shape[1]): fig = plot_mo(i) output_fid = '%d.%s.png' % (i+1,symmetry.replace(' ','_')) display('\t%s' % output_fid) fig.savefig(os.path.join(plt_dir, output_fid),format='png',**kwargs) plt.close() else: raise ValueError('output_format `%s` is not supported' % output_format)
def spin_check(spin, restricted, has_alpha, has_beta): '''Check if `spin` keyword is valid. ''' if spin is not None: if restricted: raise IOError( 'The keyword `spin` is only supported for unrestricted calculations.' ) if spin != 'alpha' and spin != 'beta': raise IOError('`spin=%s` is not a valid option' % spin) elif spin == 'alpha' and has_alpha: display('Reading only molecular orbitals of spin alpha.') elif spin == 'beta' and has_beta: display('Reading only molecular orbitals of spin beta.') elif (not has_alpha) and (not has_beta): raise IOError( 'Molecular orbitals in the input file do not contain `Spin=` keyword' ) elif ((spin == 'alpha' and not has_alpha) or (spin == 'beta' and not has_beta)): raise IOError( 'You requested `%s` orbitals, but None of them are present.' % spin)
def mo_transition_flux_density(i,j,qc,drv='x', ao_list=None,mo_list=None, delta_ao_list=None,delta_mo_list=None): '''Calculate one component (e.g. drv='x') of the transition electoronic flux density between the molecular orbitals i and j. .. math:: moTEFD_{i,j}(r) = <mo_i|\delta(r-r')\\nabla_x|mo_j> **Parameters:** i: int index of the first mo (Bra) j: int index of the second mo (Ket) drv: {0,1,2,'x','y','z'} The desired component of the vector field of the transition electoronic flux density **Returns:** mo_tefd : numpy.ndarray ''' if mo_list is None: if ao_list is None: display('\tComputing ao_list and ' + 'mo #%d, since it is not given.' % i) ao_list = core.ao_creator(qc.geo_spec,qc.ao_spec) else: display('\tComputing mo #%d, since it is not given.' % i) mo = core.mo_creator(ao_list,[qc.mo_spec[i]])[0] else: mo = mo_list[i] if delta_mo_list is None: if delta_ao_list is None: display('\tComputing delta_ao_list and the derivative of ' + 'mo #%d, since it is not given.' % j) delta_ao_list = core.ao_creator(qc.geo_spec,qc.ao_spec,drv=drv) else: display('\tComputing mo #%d, since it is not given.' % j) delta_mo = core.mo_creator(delta_ao_list,[qc.mo_spec[j]])[0] else: delta_mo = delta_mo_list[i] return mo*delta_mo
def numerical_mulliken_charges(atom, qc, ao_list=None, mo_list=None, rho_atom=None): r'''Compute the Mulliken charges and gross atomic populations of the selected atoms *numerically* using the respective gross atomic densities. .. math:: P^a = \int \rho^a(x,y,z) {\rm d}^3r **Parameters:** atom : 'all' or int or list of int Specifies the atom (numbering starting from one) to which the numerical Mulliken charges and gross populations will be computed. If (atom == 'all') or (atom == -1), computes the charges and populations for all atoms. **Returns:** rho_atom : list of numpy.ndarrays, shape=(len(atoms,) + N) Contains the atom gross atomic density on a grid. mulliken_num : dict, (present if not is_vector) Contains information of Mulliken charge analysis and has following members: :population: - Mulliken population for each atom. :charges: - Mulliken charges for each atom. ''' if (atom == 'all' or atom == -1 or atom == [-1]): atom = range(1, len(qc.geo_info) + 1) atom, index = atom2index(atom, geo_info=qc.geo_info) rho_atom = gross_atomic_density(atom, qc, ao_list=ao_list, mo_list=mo_list) if grid.is_vector: display('Warning: You have applied a vector grid.\n' + 'The integration is not implemented for such a grid!\n' + '\nReturning only the gross atomic densities...') return rho_atom GP_A = numpy.array([core.integration(i) for i in rho_atom]) mulliken_num = { 'population': GP_A, 'charge': numpy.array(qc.geo_info[:, 2], dtype=float) - GP_A } display('\nNumerical Mulliken Charges Q and Gross Atomic Populations GP:') for i, a in enumerate(index): a = int(a) display('\tAtom %s (%s):\tQ = %+0.4f ( GP = %0.4f )' % (qc.geo_info[a][1], qc.geo_info[a][0], mulliken_num['charge'][i], mulliken_num['population'][i])) return rho_atom, mulliken_num
def order_using_analytical_overlap(fid_list, itype='molden', deg=0, numproc=1, **kwargs): '''Performs an ordering routine using analytical overlap integrals between molecular orbitals. Set fid_list to None to omit the reading of input files. If :literal:`deg` is set to a value larger than zero, the molecular orbital coefficients are extrapolated with a polynomial of degree :literal:`deg`, before computing the molecular orbital overlap matrix. **Paramerters:** fid_list : list of str or None If not None, it contains the list of input file names. itype : str, choices={'molden', 'gamess', 'gaussian.log', 'gaussian.fchk'} Specifies the type of the input files. deg : int, optional If greater than zero, specifies the degree of the extrapolation polynomial for the molecular orbital coefficients. **Returns:** index_list : numpy.ndarray, shape=(Nfiles,NMO) Contains the new indices of the molecular orbitals. If index < 0, the molecular orbital changes its sign. mo_overlap : numpy.ndarray, shape=((Nfiles - 1),NMO,NMO) Contains the overlap matrix between the molecular orbitals of two neighboring geometries, i.e., mo_overlap[i,j,k] corresponds to overlap between the jth molecular orbital at geometry i to the kth molecular orbital at geometry (i+1). **Global Variables:** geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list ''' global geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list if fid_list is not None: read(fid_list, itype=itype, **kwargs) display( '\nStarting the ordering routine using the molecular orbital overlap...' ) iterate = list(range(1, len(geo_spec_all))) if deg > 0: display('\tThe molecular orbital coefficients will be extrapolated') display('\tusing a least squares polynomial fit of degree %d.' % deg) std = numpy.array( [numpy.std(i - geo_spec_all[0]) for i in geo_spec_all]) mo_overlap = [[] for i in sym.keys()] index_list = [[] for i in sym.keys()] for s in sym.values(): shape = numpy.shape(mo_coeff_all[s]) index_list[s] = numpy.ones((shape[0], shape[1]), dtype=int) index_list[s] *= numpy.arange(shape[1], dtype=int) c = 0 t = time() for rr in iterate: r1 = rr - 1 r2 = rr if (deg is None) or (deg > 0 and r1 >= deg): ao_overlap = get_ao_overlap(geo_spec_all[r2], geo_spec_all[r2], ao_spec, ao_spherical=ao_spherical) else: ao_overlap = get_ao_overlap(geo_spec_all[r1], geo_spec_all[r2], ao_spec, ao_spherical=ao_spherical) cs = 0 for s in sym.values(): mo_coeff = mo_coeff_all[s] shape = numpy.shape(mo_coeff) if deg is not None and deg > 0 and r1 >= deg: mo_r1 = get_extrapolation(r1, r2, mo_coeff, grid1d=std, deg=deg) else: mo_r1 = mo_coeff[r1] overlap = get_mo_overlap_matrix(mo_r1, mo_coeff[r2], ao_overlap, numproc=numproc) for i in range(shape[1]): # Iterate the rows of the overlap matrix line_max = None # variable for maximum value in the current row line_sort = numpy.argsort(numpy.abs( overlap[i, :]))[::-1] # sort the row for k in line_sort[::-1]: # Is this value the maximum in the current column? col_max = numpy.argmax(numpy.abs(overlap[:, k])) if i == col_max: line_max = k break if line_max is not None: # Interchange the coefficients mo_coeff[r2, [i, line_max], :] = mo_coeff[r2, [line_max, i], :] overlap[:, [i, line_max]] = overlap[:, [line_max, i]] index_list[s][r2, [i, line_max]] = index_list[s][r2, [line_max, i]] for i in range(shape[1]): # Change the signs mo_coeff[r2, i, :] *= numpy.sign(overlap[i, i]) overlap[:, i] *= numpy.sign(overlap[i, i]) index_list[s][r2, i] *= numpy.sign(overlap[i, i]) mo_overlap[cs].append(overlap) cs += 1 mo_coeff_all[s] = mo_coeff index = numpy.abs(index_list[s])[r2, :] mo_energy_all[s][r2, :] = mo_energy_all[s][r2, index] mo_occ_all[s][r2, :] = mo_occ_all[s][r2, index] c += 1 #if not c % int(numpy.ceil(len(iterate)/10.)): display('\tFinished %d of %d geometries (%.1f s)' % (c, len(iterate), time() - t)) t = time() tmp = [] for i in mo_overlap: tmp.append(numpy.array(i)) mo_overlap = tmp return index_list, mo_overlap
def read_gamess(fname, all_mo=False, spin=None, read_properties=False, **kwargs): '''Reads all information desired from a Gamess-US output file. **Parameters:** fname : str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. all_mo : bool, optional If True, all molecular orbitals are returned. **Returns:** qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot : See :ref:`Central Variables` for details. ''' if isinstance(fname, str): filename = fname fname = descriptor_from_file(filename, index=0) else: filename = fname.name from io import TextIOWrapper if isinstance(fname, TextIOWrapper): flines = fname.readlines() # Read the WHOLE file into RAM else: magic = 'This is an Orbkit magic string' text = fname.read().decode("iso-8859-1").replace( '\n', '\n{}'.format(magic)) flines = text.split(magic) flines.pop() # Initialize the variables qc = QCinfo() qc.ao_spec = AOClass([]) qc.mo_spec = MOClass([]) has_alpha = False # Flag for alpha electron set has_beta = False # Flag for beta electron set restricted = True # Flag for restricted calculation sec_flag = None # A Flag specifying the current section is_pop_ana = True # Flag for population analysis for ground state keyword = [' ATOM ATOMIC COORDINATES', ''] # Keywords for single point calculation and # geometry optimization mokey = 'EIGENVECTORS' # Keyword for MOs unrestopt = False # Flag for unrestricted optimization bopt = False # Flag for geometry optimization sym = {} # Symmetry of MOs geo_skip = 1 # Number of lines to skip in geometry section for il in range(len(flines)): line = flines[il] # The current line as string thisline = line.split() # The current line split into segments # Check the file for keywords if 'RUNTYP=OPTIMIZE' in line: keyword = [ ' COORDINATES OF ALL ATOMS ARE', '***** EQUILIBRIUM GEOMETRY LOCATED *****' ] geo_skip = 2 bopt = True if 'SCFTYP=UHF' in line: mokey = ' SET ****' restricted = False else: mokey = 'EIGENVECTORS' elif keyword[0] in line and keyword[1] in flines[il - 1]: # The section containing information about # the molecular geometry begins sec_flag = 'geo_info' atom_count = 0 # Counter for Atoms angstrom = not '(BOHR)' in line elif 'ATOMIC BASIS SET' in line: # The section containing information about # the atomic orbitals begins sec_flag = 'ao_info' ao_skip = 6 # Number of lines to skip AO = [] # Atomic orbitals elif '----- ALPHA SET ' in line: # The section for alpha electrons has_alpha = True has_beta = False restricted = False elif '----- BETA SET ' in line: # The section for alpha electrons restricted = False has_alpha = False has_beta = True elif mokey in line and len(thisline) < 3: # The section containing information about # the molecular orbitals begins sec_flag = 'mo_info' mo_skip = 1 len_mo = 0 # Number of MOs init_mo = False # Initialize new MO section info_key = None # A Flag specifying the energy and symmetry section lxlylz = [] if 'ALPHA' in line: has_alpha = True mo_skip = 0 elif 'BETA' in line: has_beta = True has_alpha = False mo_skip = 0 elif 'NATURAL ORBITALS' in line and len(thisline) <= 3: display('The natural orbitals are not extracted.') elif ' NUMBER OF OCCUPIED ORBITALS (ALPHA) =' in line: occ = [] # occupation number of molecular orbitals occ.append(int(thisline[-1])) elif ' NUMBER OF OCCUPIED ORBITALS (BETA ) =' in line: occ.append(int(thisline[-1])) # elif 'ECP POTENTIALS' in line: # sec_flag = 'ecp_info' # ecp = '' elif ' NUMBER OF OCCUPIED ORBITALS (ALPHA) KEPT IS =' in line: occ = [] # occupation number of molecular orbitals occ.append(int(thisline[-1])) elif ' NUMBER OF OCCUPIED ORBITALS (BETA ) KEPT IS =' in line: occ.append(int(thisline[-1])) elif 'NUMBER OF STATES REQUESTED' in line and read_properties: # get the number of excited states and initialize variables for # transition dipole moment and energies exc_states = int(line.split('=')[1]) # Number of excited states # Dipole moments matrix: Diagonal elements -> permanent dipole moments # Off-diagonal elements -> transition dipole moments qc.dipole_moments = numpy.zeros( ((exc_states + 1), (exc_states + 1), 3)) # Multiplicity of ground and excited states qc.states['multiplicity'] = numpy.zeros(exc_states + 1) # Energies of ground and excited states qc.states['energy'] = numpy.zeros(exc_states + 1) qc.states['energy'][0] = qc.etot qc.states['multiplicity'][0] = gs_multi dm_flag = None # Flag specifying the dipole moments section elif 'TRANSITION DIPOLE MOMENTS' in line and read_properties: # Section containing energies of excited states sec_flag = 'dm_info' # Energy and Multiplicity for ground state elif 'SPIN MULTIPLICITY' in line and read_properties: # odd way to get gound state multiplicity gs_multi = int(line.split()[3]) elif 'FINAL' in line and read_properties: # get (last) energy qc.etot = float(line.split()[4]) elif 'TOTAL MULLIKEN AND LOWDIN ATOMIC POPULATIONS' in line and is_pop_ana == True and read_properties: # Read Mulliken and Lowdin Atomic Populations sec_flag = 'pop_info' pop_skip = 1 is_pop_ana == False qc.pop_ana['Lowdin'] = [] qc.pop_ana['Mulliken'] = [] else: # Check if we are in a specific section if sec_flag == 'geo_info': if not geo_skip: if len(line) < 2: sec_flag = None else: qc.geo_info.append( [thisline[0], atom_count + 1, thisline[1]]) qc.geo_spec.append([float(ii) for ii in thisline[2:]]) atom_count += 1 elif geo_skip: geo_skip -= 1 elif sec_flag == 'ao_info': if not ao_skip: if ' TOTAL NUMBER OF BASIS SET SHELLS' in line: sec_flag = None else: if len(thisline) == 1: # Read atom type at_type = thisline[0] AO.append([]) new_ao = False elif len(thisline) == 0 and new_ao == False: new_ao = True else: coeffs = [float(ii) for ii in thisline[3:]] if new_ao: ao_type = thisline[1].lower().replace( 'l', 'sp') for i_ao, t_ao in enumerate(ao_type): AO[-1].append({ 'atom_type': at_type, 'type': t_ao, 'pnum': 1, 'coeffs': [[coeffs[0], coeffs[1 + i_ao]]] }) new_ao = False else: for i_ao in range(len(ao_type)): AO[-1][-len(ao_type) + i_ao]['coeffs'].append( [coeffs[0], coeffs[1 + i_ao]]) AO[-1][-len(ao_type) + i_ao]['pnum'] += 1 elif ao_skip: ao_skip -= 1 elif sec_flag == 'mo_info': if not mo_skip: if 'END OF' in line and 'CALCULATION' in line or '-----------' in line: sec_flag = None has_alpha = False has_beta = False else: if thisline == []: info_key = None init_mo = True try: int(flines[il + 1].split()[0]) except ValueError: sec_flag = None init_mo = False elif init_mo: init_len = len(thisline) lxlylz = [] for ii in range(len(thisline)): if has_alpha == True or has_beta == True: qc.mo_spec.append({ 'coeffs': [], 'energy': 0.0, 'occ_num': 0.0, 'sym': '', 'spin': '' }) else: qc.mo_spec.append({ 'coeffs': [], 'energy': 0.0, 'occ_num': 0.0, 'sym': '' }) init_mo = False info_key = 'energy' elif len( thisline) == init_len and info_key == 'energy': for ii in range(init_len, 0, -1): qc.mo_spec[-ii]['energy'] = float( thisline[init_len - ii]) info_key = 'symmetry' elif len(thisline ) == init_len and info_key == 'symmetry': for ii in range(init_len, 0, -1): len_mo += 1 a = thisline[init_len - ii] if a not in sym.keys(): sym[a] = 1 else: sym[a] = len_mo if has_alpha: qc.mo_spec[-ii]['sym'] = '%d.%s_a' % ( sym[a], thisline[init_len - ii]) qc.mo_spec[-ii]['spin'] = 'alpha' elif has_beta: qc.mo_spec[-ii]['sym'] = '%d.%s_b' % ( sym[a], thisline[init_len - ii]) qc.mo_spec[-ii]['spin'] = 'beta' else: qc.mo_spec[-ii]['sym'] = '%d.%s' % ( sym[a], thisline[init_len - ii]) info_key = 'coeffs' elif thisline != [] and info_key == 'coeffs': lxlylz.append((line[11:17])) for ii, m in enumerate( re.finditer('-?\d+\.\d+', line[16:])): qc.mo_spec[-init_len + ii]['coeffs'].append( float(m.group())) elif mo_skip: mo_skip -= 1 elif sec_flag == 'ecp_info': if 'THE ECP RUN REMOVES' in line: sec_flag = None elif 'PARAMETERS FOR' in line: if line[17:25].split()[0] != ecp: ecp = line[17:25].split()[0] zcore = float(line[51:55].split()[0]) ii_geo = int(line[35:41].split()[0]) - 1 qc.geo_info[ii_geo][2] = str( float(qc.geo_info[ii_geo][2]) - zcore) else: ii_geo = int(line[35:41].split()[0]) - 1 qc.geo_info[ii_geo][2] = str( float(qc.geo_info[ii_geo][2]) - zcore) elif sec_flag == 'dm_info': # instead of giving the output in a useful human and machine readable # way, gamess output syntax differs for transitions involving the # ground state compared to transitions between excited states... if 'GROUND STATE (SCF) DIPOLE=' in line: # ground state dipole is in debye...convert to atomic units for ii in range(3): qc.dipole_moments[0][0][ii] = float( thisline[ii + 4]) * 0.393430307 if 'EXPECTATION VALUE DIPOLE MOMENT FOR EXCITED STATE' in line: state = (int(line.replace('STATE', 'STATE ').split()[7])) dm_flag = 'state_info' if 'TRANSITION FROM THE GROUND STATE TO EXCITED STATE' in line: state = [ 0, int(line.replace('STATE', 'STATE ').split()[8]) ] dm_flag = 'transition_info' if 'TRANSITION BETWEEN EXCITED STATES' in line: state = [ int(thisline[4]), int(line.replace('AND', 'AND ').split()[6]) ] dm_flag = 'transition_info' if 'NATURAL ORBITAL OCCUPATION NUMBERS FOR EXCITED STATE' in line: sec_flag = None dm_flag = None if dm_flag == 'state_info': if 'STATE MULTIPLICITY' in line: qc.states['multiplicity'][state] = int( line.split('=')[1]) if 'STATE ENERGY' in line: qc.states['energy'][state] = float(line.split('=')[1]) if 'STATE DIPOLE' and 'E*BOHR' in line: for ii in range(3): qc.dipole_moments[state][state][ii] = float( thisline[ii + 3]) elif dm_flag == 'transition_info': if 'TRANSITION DIPOLE' and 'E*BOHR' in line: for ii in range(3): qc.dipole_moments[state[0]][state[1]][ii] = float( thisline[ii + 3]) qc.dipole_moments[state[1]][state[0]][ii] = float( thisline[ii + 3]) elif sec_flag == 'pop_info': if not pop_skip: if line == '\n': sec_flag = None else: qc.pop_ana = {} qc.pop_ana['Lowdin'].append(float(thisline[5])) qc.pop_ana['Mulliken'].append(float(thisline[3])) elif pop_skip: pop_skip -= 1 # Check usage of same atomic basis sets basis_set = {} for ii in range(len(AO)): if not AO[ii][0]['atom_type'] in basis_set.keys(): basis_set[AO[ii][0]['atom_type']] = AO[ii] else: for jj in range(len(AO[ii])): if AO[ii][jj]['coeffs'] != basis_set[ AO[ii][0]['atom_type']][jj]['coeffs']: raise IOError('Different basis sets for the same atom.') # Numpy array for ii in basis_set.keys(): for jj in range(len(basis_set[ii])): basis_set[ii][jj]['coeffs'] = numpy.array( basis_set[ii][jj]['coeffs']) for kk in range(len(qc.mo_spec)): qc.mo_spec[kk]['coeffs'] = numpy.array(qc.mo_spec[kk]['coeffs']) # Complement atomic basis sets for kk in range(len(qc.geo_info)): for ll in range(len(basis_set[qc.geo_info[kk][0]])): qc.ao_spec.append({ 'atom': qc.geo_info[kk][1] - 1, 'type': basis_set[qc.geo_info[kk][0]][ll]['type'], 'pnum': basis_set[qc.geo_info[kk][0]][ll]['pnum'], 'coeffs': basis_set[qc.geo_info[kk][0]][ll]['coeffs'], 'lxlylz': None }) # Reconstruct exponents list for ao_spec count = 0 for i, j in enumerate(qc.ao_spec): l = l_deg(lquant[j['type']]) j['lxlylz'] = [] for i in range(l): j['lxlylz'].append((lxlylz[count].lower().count('x'), lxlylz[count].lower().count('y'), lxlylz[count].lower().count('z'))) count += 1 j['lxlylz'] = numpy.array(j['lxlylz'], dtype=numpy.int64) if restricted: for ii in range(len(qc.mo_spec)): if occ[0] and occ[1]: qc.mo_spec[ii]['occ_num'] += 2.0 occ[0] -= 1 occ[1] -= 1 if not occ[0] and occ[1]: qc.mo_spec[ii]['occ_num'] += 1.0 occ[1] -= 1 if not occ[1] and occ[0]: qc.mo_spec[ii]['occ_num'] += 1.0 occ[0] -= 1 if restricted == False: for ii in range(len(qc.mo_spec)): if qc.mo_spec[ii]['spin'] == 'alpha' and occ[0] > 0: qc.mo_spec[ii]['occ_num'] += 1.0 occ[0] -= 1 has_alpha = True elif qc.mo_spec[ii]['spin'] == 'beta' and occ[1] > 0: qc.mo_spec[ii]['occ_num'] += 1.0 occ[1] -= 1 has_beta = True if spin is not None: if restricted: raise IOError( 'The keyword `spin` is only supported for unrestricted calculations.' ) if spin != 'alpha' and spin != 'beta': raise IOError('`spin=%s` is not a valid option' % spin) elif spin == 'alpha' and has_alpha == True: display('Reading only molecular orbitals of spin alpha.') elif spin == 'beta' and has_beta == True: display('Reading only molecular orbitals of spin beta.') elif (not has_alpha) and (not has_beta): raise IOError('No spin molecular orbitals available') elif ((spin == 'alpha' and not has_alpha) or (spin == 'beta' and not has_beta)): raise IOError( 'You requested `%s` orbitals, but None of them are present.' % spin) # Are all MOs requested for the calculation? if not all_mo: for i in range(len(qc.mo_spec))[::-1]: if qc.mo_spec[i]['occ_num'] < 0.0000001: del qc.mo_spec[i] # Only molecular orbitals of one spin requested? if spin is not None: for i in range(len(qc.mo_spec))[::-1]: if qc.mo_spec[i]['spin'] != spin: del qc.mo_spec[i] # Convert geo_info and geo_spec to numpy.ndarrays qc.format_geo(is_angstrom=angstrom) qc.mo_spec.update() qc.ao_spec.update() return qc
def gaussian_tddft(fname,select_state=None,threshold=0.0,**kwargs): '''Reads Gaussian16 TDDFT output. **Parameters:** fname: str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. select_state : None or list of int, optional If not None, specifies the states to be read (0 corresponds to the ground state), else read all electronic states. threshold : float, optional Specifies a read threshold for the CI coefficients. **Returns:** ci : list of CIinfo class instances See :ref:`Central Variables` for details. ''' display('\nReading data of TDDFT calculation from Gaussian...') # Initialize variables ci = [] ci_flag = False prttol = False init_state = False rhfspin = 0 spin = 'Unknown' nel = 0 deex = [] if isinstance(select_state,int): select_state = [select_state] if isinstance(fname, str): filename = fname fname = descriptor_from_file(filename, index=0, ci_descriptor=True) else: filename = fname.name for line in fname: thisline = line.split() # The current line split into segments #--- Check the file for keywords --- # Initialize Hartree-Fock ground state if ' SCF Done: E(' in line: ci.append(CIinfo(method='tddft')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].occ.append([0,0]) ci[-1].coeffs.append(1.0) ci[-1].info = {'state': '0', 'energy': float(thisline[4]), 'energy_nm': 0.0, 'fileinfo': filename, 'read_threshold': threshold, 'spin': spin, 'f_0i': 0.0} # Initialize new excited state elif ' Excited State' in line and 'eV' in line and 'nm' in line: if select_state is None or int(thisline[2].replace(':',' ')) in select_state: init_state = True tddft_skip = 1 ci.append(CIinfo(method='tddft')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].info = {'state': thisline[2][:-1], 'energy': float(thisline[-6])*ev_to_ha + ci[0].info['energy'], 'energy_nm': float(thisline[-4]), 'fileinfo': filename, 'read_threshold': threshold, 'spin': thisline[3].split('-')[0], 'f_0i': float(thisline[8].replace('=',' ').split()[-1])} deex.append([]) if init_state == True: if not tddft_skip: if thisline == [] or '->' not in line and '<-' not in line: init_state = False else: if '->' in line: thisline = line.replace('->','-> ').split() if abs(float(thisline[-1])) > threshold: tmp_occ = [thisline[0],thisline[2]] ci[-1].occ.append(tmp_occ) ci[-1].coeffs.append(float(thisline[-1])*numpy.sqrt(2)) elif '<-' in line: deex[-1].append(float(thisline[-1])*numpy.sqrt(2)) elif tddft_skip: tddft_skip -= 1 fname.close() deex = numpy.array(deex) #--- Calculating norm of CI states display('\nIn total, %d states have been read.' % len(ci)) display('Norm of the states:') for i in range(len(ci)): j = numpy.array(ci[i].coeffs,dtype=float) norm = numpy.sum(j**2) ci[i].coeffs = j # Write Norm to log-file display('\tState %s:\tNorm = %0.8f (%d Coefficients)' % (ci[i].info['state'],norm, len(ci[i].coeffs))) # Transform to numpy arrays ci[i].occ = numpy.array([s for s in ci[i].occ],dtype=numpy.intc)-1 return ci
def molpro_mcscf(filename, select_run=0, threshold=0.0, **kwargs): '''Reads MOLPRO MCSCF output. **Parameters:** filename : str Specifies the filename for the input file. select_run : (list of) int Specifies the MCSCF calculation (1PROGRAM * MULTI) to be read. For the selected MCSCF calculation, all electronic states will be read. threshold : float, optional Specifies a read threshold for the CI coefficients. **Returns:** ci : list of CIinfo class instances See :ref:`Central Variables` for details. ..ATTENTION: Changed return value to list of CI classes ''' display('\nReading data of MCSCF calculation from MOLPRO...') method = 'mcscf' available = {'mcscf': 'MULTI'} single_run_selected = isinstance(select_run, int) count = 0 numci = [] # Go through the file line by line with open(filename) as fileobject: for line in fileobject: if '1PROGRAM * %s' % available[method] in line: count += 1 numci.append(0) if '!%s state' % method in line.lower() and 'energy' in line.lower( ): numci[-1] += 1 if count == 0: display( 'The input file %s does not contain any DETCI calculations!\n' % (filename) + 'It does not contain the keyword:\n\t1PROGRAM * MULTI') raise IOError('Not a valid input file') else: string = ', '.join(map(str, numci)).rsplit(', ', 1) string = ' and '.join(string) if len( string[0].split(',')) < 2 else ', and '.join(string) display('The input file %s contains' % (filename)) display('%d MCSCF calculation(s) with %s root(s)%s.' % (count, string, ', respectively' if len(numci) > 1 else '')) if select_run is None: select_run = numpy.arange(count) if isinstance(select_run, int) and 0 <= select_run < count: select_run = [select_run] ci = [[]] elif isinstance(select_run, (list, numpy.ndarray)): ci = [] for i in select_run: ci.append([]) if not isinstance(i, int): raise IOError( str(i) + ' is not a valid selection for select_run') else: raise IOError( str(select_run) + ' is a not valid selection for select_run') select_run = numpy.array(select_run) display('\tYour selection (counting from zero): %s' % ', '.join(map(str, select_run))) general_information = {'fileinfo': filename, 'read_threshold': threshold} ci_skip = 0 count = 0 count_runs = 0 min_c = 1 start_reading = False sec_flag = False info_flag = False info_sep = False info_split = False occ_types = ['core', 'closed', 'active', 'external'] with open(filename) as fileobject: for line in fileobject: thisline = line.split() # The current line split into segments if '1PROGRAM *' in line: start_reading = False #--- Number of IRREPs if 'Point group' in line or '_PGROUP' in line: nIRREP = point_groups()[thisline[-1].lower()] rhf_occ = numpy.zeros(nIRREP, dtype=numpy.intc) #--- RHF occupation elif 'Final occupancy:' in line: c_occ = line.split()[2:] for ii in range(len(c_occ)): rhf_occ[ii] = int(c_occ[ii]) #--- A MCSCF Calculation starts --- elif '1PROGRAM * %s' % available[method] in line: occ_info = {} for i in occ_types: occ_info[i] = numpy.zeros(nIRREP, dtype=numpy.intc) state_info = [] i = numpy.argwhere(select_run == count_runs) if len(i) > 0: index_run = int(i) start_reading = True count = 0 old = 0 count_runs += 1 elif start_reading: #--- Active space --- if 'Number of ' in line and 'orbitals:' in line: line = line.replace('(', '').replace(')', '').replace('-shell', '') c_occ = numpy.array(line.split()[-nIRREP:], dtype=numpy.intc) occ_info[line.split()[2]] += c_occ elif 'State symmetry' in line: fileobject.next() thisline = fileobject.next() if 'State symmetry' in thisline: fileobject.next() thisline = fileobject.next() thisline = thisline.replace('=', ' ').split() data = { 'nel': thisline[3], 'spin': thisline[6], 'sym': thisline[9] } thisline = fileobject.next().split() state_info.extend([data for i in range(int(thisline[-1]))]) elif '!%s state' % method in line.lower( ) and 'energy' in line.lower(): ci[index_run].append(CIinfo(method=method)) info = state_info[count] thisline = line.lower().replace('state', 'state ').split() ci[index_run][count].info = copy(general_information) ci[index_run][count].info['fileinfo'] += '@%d' % index_run ci[index_run][count].info['state'] = thisline[2] ci[index_run][count].info['energy'] = float(thisline[4]) ci[index_run][count].info['spin'] = info['spin'] ci[index_run][count].info['nel'] = info['nel'] ci[index_run][count].info['occ_info'] = occ_info count += 1 elif 'CI vector' in line: sec_flag = 'mcscf' info_split = ' ' ci_skip = 3 info = thisline[-1] count = old first = True if not ci_skip: if line == '\n' or '/EOF' in line: sec_flag = False elif sec_flag != False: split_line = filter(None, line.split(info_split)) if len(split_line) > 1: occupation = numpy.zeros( (numpy.sum(occ_info['active']), 2), dtype=numpy.intc) for i, j in enumerate(split_line[0].replace( ' ', '')): if j == '2': occupation[i, :] = 1 elif j == 'a': occupation[i, 0] = 1 elif j == 'b': occupation[i, 1] = 1 c0 = 0 coeffs = split_line[-1].split() for i, j in enumerate(coeffs): if first: old += 1 min_c = min(min_c, abs(float(j))) if abs(float(j)) > threshold: ci[index_run][count + c0 + i].coeffs.append( float(j)) ci[index_run][count + c0 + i].occ.append(occupation) c0 += len(coeffs) first = False else: ci_skip -= 1 #--- Calculating norm of CI states display('\nIn total, %d states have been read.' % sum([len(i) for i in ci])) display('Norm of the states:') for i in range(len(ci)): for j in range(len(ci[i])): ci[i][j].coeffs = numpy.array(ci[i][j].coeffs) ci[i][j].occ = numpy.array(ci[i][j].occ, dtype=numpy.intc) norm = sum(ci[i][j].coeffs**2) # Write Norm to log-file display('\tState %s (%s):\tNorm = %0.8f (%d Coefficients)' % (ci[i][j].info['state'], ci[i][j].info['spin'], norm, len(ci[i][j].coeffs))) display('') if min_c > threshold: display( '\nInfo:' + '\n\tSmallest coefficient (|c|=%f) larger than the read threshold (%f).' % (min_c, threshold) + '\n\tUse `gthresh, printci=0.0` in the MOLPRO input file to print ' + 'all CI coefficients.\n') #if single_run_selected and len(ci) == 1: #ci = ci[0] ci_new = [] for i in ci: ci_new.extend(i) return ci_new
def mo_set(qc, fid_mo_list, drv=None, laplacian=None, otype=None, ofid=None, return_all=True, numproc=None, slice_length=None): '''Calculates and saves the density or the derivative thereof using selected molecular orbitals. **Parameters:** qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec : See :ref:`Central Variables` for details. fid_mo_list : str Specifies the filename of the molecular orbitals list or list of molecular orbital labels (cf. :mod:`orbkit.orbitals.MOClass.select` for details). otype : str or list of str, optional Specifies output file type. See :data:`otypes` for details. ofid : str, optional Specifies output file name. If None, the filename will be based on :mod:`orbkit.options.outputname`. drv : string or list of strings {None,'x','y', 'z', 'xx', 'xy', ...}, optional If not None, a derivative calculation is requested. return_all : bool If False, no data will be returned. numproc : int, optional Specifies number of subprocesses for multiprocessing. If None, uses the value from :mod:`options.numproc`. slice_length : int, optional Specifies the number of points per subprocess. If None, uses the value from :mod:`options.slice_length`. **Returns:** datasets : numpy.ndarray, shape=((NSET,) + N) Contains the NSET molecular orbital sets on a grid. delta_datasets : numpy.ndarray, shape=((NSET,NDRV) + N) Contains the NDRV NSET molecular orbital set on a grid. This is only present if derivatives are requested. ''' #Can be an mo_spec or a list of mo_spec # For later iteration we'll make it into a list here if it is not mo_info_list = qc.mo_spec.select(fid_mo_list, flatten_input=False) drv = options.drv if drv is None else drv laplacian = options.laplacian if laplacian is None else laplacian slice_length = options.slice_length if slice_length is None else slice_length numproc = options.numproc if numproc is None else numproc if ofid is None: ofid = options.outputname datasets = [] datalabels = [] delta_datasets = [] delta_datalabels = [] cube_files = [] for i_file, mo_info in enumerate(mo_info_list): qc_select = qc.copy() qc_select.mo_spec = mo_info label = 'mo_set:' + mo_info.selection_string display('\nStarting with the molecular orbital list \n\t' + label + '\n\t(Only regarding existing and occupied mos.)\n') data = core.rho_compute(qc_select, drv=drv, laplacian=laplacian, slice_length=slice_length, numproc=numproc) if drv is None: rho = data delta_datasets = numpy.zeros((0, ) + rho.shape) elif laplacian: rho, delta_rho, laplacian_rho = data delta_datasets.extend(delta_rho) delta_datasets.append(laplacian_rho) delta_datalabels.extend( ['d^2/d%s^2 %s' % (i, label) for i in 'xyz']) delta_datalabels.append('laplacian_of_' + label) else: rho, delta_rho = data delta_datasets.extend(delta_rho) delta_datalabels.extend(['d/d%s %s' % (i, label) for i in drv]) datasets.append(rho) datalabels.append(label) datasets = numpy.array(datasets) delta_datasets = numpy.array(delta_datasets) delta_datalabels.append('mo_set') data = numpy.append(datasets, delta_datasets, axis=0) if not options.no_output: output_written = main_output(data, qc, outputname=ofid, datalabels=datalabels + delta_datalabels, otype=otype, drv=None) return data
def order_using_extrapolation(fid_list, itype='molden', deg=1, use_mo_values=False, matrix=None, **kwargs): '''Performs an ordering routine using extrapolation of quantities related to the molecular orbitals. Set fid_list to None to omit the reading of input files. The molecular orbital coefficients (If use_mo_values is False) are extrapolated with a polynomial of degree :literal:`deg` and ordered by minimizing a selected norm (default: Euclidian norm). **Paramerters:** fid_list : list of str or None If not None, it contains the list of input file names. itype : str, choices={'molden', 'gamess', 'gaussian.log', 'gaussian.fchk'} Specifies the type of the input files. deg : int Specifies the degree of the extrapolation polynomial. use_mo_values : bool, optional If True, some molecular orbital values and their derivatives are computed at the nuclear positions. The ordering routine is applied for those values instead. matrix : None or numpy.ndarray with shape=(Nfiles,N,M) If not None, contains the data to be ordered. **Returns:** :if matrix is None: - index_list :else: - matrix, index_list index_list : numpy.ndarray, shape=(Nfiles,NMO) Contains the new indices of the molecular orbitals. If index < 0, the molecular orbital changes its sign. matrix : numpy.ndarray, shape=(Nfiles,N,M) Contains the ordered matrix. **Global Variables:** geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list ''' global geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list # Read all input files if fid_list is not None: read(fid_list, itype=itype, **kwargs) radius = range(len(geo_spec_all)) #: We assume an equally spaced grid if deg < 2: function = order_mo else: function = order_mo_higher_deg if matrix is not None: display('\tOdering backward') matrix, index_list = function(matrix, index_list=index_list[ii_s], backward=True, mu=mu, deg=deg) display('\tOdering forward') matrix, index_list = function(matrix, index_list=index_list[ii_s], backward=False, mu=mu, deg=deg) return matrix, index_list index_list = [None for i in sym.keys()] for s, ii_s in sym.items(): display('Starting ordering of MOs of symmetry %s' % s) shape = numpy.shape(mo_coeff_all[ii_s]) mu = 5e-2 matrix = mo_coeff_all[ii_s] if use_mo_values: display('\tComputing molecular orbitals at the nuclear positions') matrix = compute_mo_list(geo_spec_all, ao_spec, matrix, ao_spherical=ao_spherical, iter_drv=[None, 'x', 'y', 'z']) display('\tOdering backward') matrix, index_list[ii_s] = function(matrix, index_list=index_list[ii_s], backward=True, mu=mu, deg=deg) display('\tOdering forward') matrix, index_list[ii_s] = function(matrix, index_list=index_list[ii_s], backward=False, mu=mu, deg=deg) for rr in range(shape[0]): index = numpy.abs(index_list[ii_s])[rr, :] sign = (-1)**(index_list[ii_s][rr] < 0) mo_energy_all[ii_s][rr, :] = mo_energy_all[ii_s][rr, index] mo_occ_all[ii_s][rr, :] = mo_occ_all[ii_s][rr, index] mo_coeff_all[ii_s][ rr, :, :] = sign[:, numpy.newaxis] * mo_coeff_all[ii_s][ rr, index, :] # numpy.array(matrix,copy=True) return index_list
def main_output(data, geo_info, geo_spec, outputname='new', otype='h5', drv=None, omit=[], **kwargs): '''Creates the requested output. **Parameters:** data : numpy.ndarray, shape=N or shape=((NDRV,) + N) Contains the output data. The shape (N) depends on the grid and the data, i.e., 3d for regular grid, 1d for vector grid. geo_info, geo_spec : See :ref:`Central Variables` for details. outputname : str Contains the base name of the output file. otype : str or list of str Contains the output file type. Possible options: 'h5', 'cb', 'am', 'hx', 'vmd', 'mayavi' drv : None or list of str, optional If not None, a 4d(regular)/2d(vector) input data array will be expected with NDRV = len(drv). omit : list of str, optional If not empty, the input file types specified here are omitted. **Note:** All additional keyword arguments are forwarded to the output functions. ''' print_waring = False output_written = [] if isinstance(otype, str): otype = [otype] if 'vmd' in otype and not 'cb' in otype: otype.append('cb') otype = [i for i in otype if i not in omit] if otype is None or otype == []: return output_written # Convert the data to a regular grid, if possible output_not_possible = (grid.is_vector and not grid.is_regular) is_regular_vector = (grid.is_vector and grid.is_regular) if is_regular_vector: display( '\nConverting the regular 1d vector grid to a 3d regular grid.') grid.vector2grid(*grid.N_) data = grid.mv2g(data=data) if 'mayavi' in otype: if output_not_possible: print_waring = True else: view_with_mayavi(grid.x, grid.y, grid.z, data, geo_spec=geo_spec, **kwargs) if drv is not None: fid = '%(f)s_d%(d)s' it = enumerate(drv) else: fid = '%(f)s' it = [(0, None)] data = [data] f = {'f': outputname} for i, j in it: f['d'] = j d = data[i] if 'h5' in otype: display('\nSaving to Hierarchical Data Format file (HDF5)...' + '\n\t%(o)s.h5' % {'o': fid % f}) HDF5_creator(d, (fid % f), geo_info, geo_spec, **kwargs) output_written.append('%s.h5' % (fid % f)) if 'am' in otype or 'hx' in otype and not print_waring: if output_not_possible: print_waring = True else: display('\nSaving to ZIBAmiraMesh file...' + '\n\t%(o)s.am' % {'o': fid % f}) amira_creator(d, (fid % f)) output_written.append('%s.am' % (fid % f)) if 'hx' in otype and not print_waring: if output_not_possible: print_waring = True else: # Create Amira network incl. Alphamap display('\nCreating ZIBAmira network file...') hx_network_creator(data, (fid % f)) output_written.append('%s.hx' % (fid % f)) if 'cb' in otype or 'vmd' in otype and not print_waring: if output_not_possible: print_waring = True else: display('\nSaving to .cb file...' + '\n\t%(o)s.cb' % {'o': fid % f}) cube_creator(d, (fid % f), geo_info, geo_spec, **kwargs) output_written.append('%s.cb' % (fid % f)) #else: output_creator(d,(fid % f),geo_info,geo_spec) # Axel's cube files if 'vmd' in otype and not print_waring: if output_not_possible: print_waring = True else: # Create VMD network display('\nCreating VMD network file...' + '\n\t%(o)s.vmd' % {'o': fid % f}) vmd_network_creator((fid % f), cube_files=['%s.cb' % (fid % f)], **kwargs) output_written.append('%s.vmd' % (fid % f)) if print_waring: display( 'For a non-regular vector grid (`if grid.is_vector and not grid.is_regular`)' ) display('only HDF5 is available as output format...') display('Skipping all other formats...') if is_regular_vector: # Convert the data back to a regular vector grid grid.grid2vector() return output_written
def vmd_network_creator(filename, cube_files=None, render=False, iso=(-0.01, 0.01), abspath=False, **kwargs): '''Creates a VMD script file from a list of cube files provided. **Parameters:** filename : str Contains the base name of the output file. cube_files : None or list of str Specifies the cube files which serve as input for the VMD script. If None, searches the directory for '.cb' and '.cube' files. render : bool If True, the VMD script will automatically create '.tga' files for each cube file. iso : tuple Specifies the isovalue for the blue and the red isosurface, respectively. abspath : bool If True, the paths of the cube files will be expanded to absolute file paths. ''' from os import path, listdir import linecache from orbkit import vmd_network_draft if cube_files is None: display( 'No list of cube (.cb or .cube) filenames provided. Checking the directory' + ' of the outputfile...') cube_files = [] for fid in listdir(path.dirname(filename)): if fid.endswith('.cb') or fid.endswith('.cube'): cube_files.append(fid) if cube_files == []: raise IOError('Could not find valid cube files in %s' % path.dirname(filename)) elif isinstance(cube_files, str): cube_files = [cube_files] elif not isinstance(cube_files, list): raise IOError('`cube_files` has to be a list of strings.') title = [] mo = '' for i, f in enumerate(cube_files): title = linecache.getline(f, 2) if title.split() == []: title = path.splitext(path.basename(f))[0] else: title = title.replace('\n', '').replace(' ', '') linecache.clearcache() pid = path.abspath(f) if abspath else path.relpath( f, path.dirname(filename)) mo += vmd_network_draft.mo_string % { 'c': i, 'n1': pid, 'n2': title, 'isored': iso[0], 'isoblue': iso[1], 'render': '' if render else '#' } f = open('%(f)s.vmd' % {'f': filename}, 'w') f.write(vmd_network_draft.vmd_string % {'mo': mo}) f.close()
def gamess_cis(filename, select_state=None, threshold=0.0, **kwargs): '''Reads GAMESS-US CIS output. **Parameters:** filename : str Specifies the filename for the input file. select_state : None or list of int, optional If not None, specifies the states to be read (0 corresponds to the ground state), else read all electronic states. threshold : float, optional Specifies a read threshold for the CI coefficients. **Returns:** ci : list of CIinfo class instances See :ref:`Central Variables` for details. ''' display('\nReading data of CIS calculation from GAMESS-US...') # Initialize variables ci = [] ci_flag = False prttol = False init_state = False rhfspin = 0 min_c = -1 if isinstance(select_state, int): select_state = [select_state] with open(filename) as fileobject: for line in fileobject: thisline = line.split() # The current line split into segments #--- Check the file for keywords --- # Initialize Hartree-Fock ground state if 'NUMBER OF ELECTRONS' in line and "=" in line: nel = int(thisline[-1]) elif 'SPIN MULTIPLICITY' in line: rhfspin = int(thisline[-1]) elif ' FINAL RHF ENERGY IS' in line and (select_state is None or 0 in select_state): ci.append(CIinfo(method='cis')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].occ.append([0, 0]) ci[-1].coeffs.append(1.0) ci[-1].info = { 'state': '0', 'energy': float(thisline[4]), 'fileinfo': filename, 'read_threshold': threshold, 'spin': multiplicity()[rhfspin], 'nel': nel } # Printing parameter elif ' PRINTING CIS COEFFICIENTS LARGER THAN' in line: min_c = float(thisline[-1]) # Initialize new excited state elif ' EXCITED STATE ' in line and 'ENERGY=' and 'SPACE SYM' in line: if select_state is None or int(thisline[2]) in select_state: init_state = True cis_skip = 6 ci.append(CIinfo(method='cis')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].info = { 'state': thisline[2], 'energy': float(thisline[4]), 'fileinfo': filename, 'read_threshold': threshold, 'spin': multiplicity()[int(2 * float(thisline[7]) + 1)], 'nel': nel } if init_state == True: if not cis_skip: if '----------------------------------------------' in line: init_state = False else: if abs(float(thisline[2])) > threshold: ci[-1].occ.append(thisline[:2]) ci[-1].coeffs.append(thisline[2]) elif cis_skip: cis_skip -= 1 #--- Calculating norm of CI states display('\nIn total, %d states have been read.' % len(ci)) display('Norm of the states:') for i in range(len(ci)): j = numpy.array(ci[i].coeffs, dtype=float) norm = numpy.sum(j**2) ci[i].coeffs = j # Write Norm to log-file display('\tState %s:\tNorm = %0.8f (%d Coefficients)' % (ci[i].info['state'], norm, len(ci[i].coeffs))) # Transform to numpy arrays ci[i].occ = numpy.array([s for s in ci[i].occ], dtype=numpy.intc) - 1 display('') if min_c > threshold: display( '\nInfo:' + '\n\tSmallest coefficient (|c|=%f) is larger than the read threshold (%f).' % (min_c, threshold) + '\n\tUse `PRTTOL=0.0` in the `$CIS` input card to print ' + 'all CI coefficients.\n') return ci
def gamess_tddft(fname, select_state=None, threshold=0.0, **kwargs): '''Reads GAMESS-US TDDFT output. **Parameters:** fname: str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. select_state : None or list of int, optional If not None, specifies the states to be read (0 corresponds to the ground state), else read all electronic states. threshold : float, optional Specifies a read threshold for the CI coefficients. **Returns:** ci : list of CIinfo class instances See :ref:`Central Variables` for details. ''' display('\nReading data of TDDFT calculation from GAMESS-US...') # Initialize variables ci = [] ci_flag = False prttol = False init_state = False rhfspin = 0 spin = 'Unknown' if isinstance(select_state, int): select_state = [select_state] if isinstance(fname, str): filename = fname fname = descriptor_from_file(filename, index=0, ci_descriptor=True) else: filename = fname.name for line in fname: thisline = line.split() # The current line split into segments #--- Check the file for keywords --- # Initialize Hartree-Fock ground state if 'NUMBER OF ELECTRONS' in line: nel = int(thisline[-1]) elif 'SPIN MULTIPLICITY' in line: rhfspin = int(thisline[-1]) elif 'SINGLET EXCITATIONS' in line: spin = 'Singlet' #elif ' FINAL RHF ENERGY IS' in line and (select_state is None or 0 in select_state): elif ' FINAL' in line and ' ENERGY IS' in line and ( select_state is None or 0 in select_state): ci.append(CIinfo(method='tddft')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].occ.append([0, 0]) ci[-1].coeffs.append(1.0) ci[-1].info = { 'state': '0', 'energy': float(thisline[4]), 'fileinfo': filename, 'read_threshold': threshold, 'spin': spin, 'nel': nel } # Initialize new excited state elif 'STATE #' in line and 'ENERGY =' in line: if select_state is None or int(thisline[2]) in select_state: init_state = True tddft_skip = 8 ci.append(CIinfo(method='cis')) ci[-1].info = [] ci[-1].coeffs = [] ci[-1].occ = [] ci[-1].info = { 'state': thisline[2], 'energy': float(thisline[-2]) * ev_to_ha + ci[0].info['energy'], 'fileinfo': filename, 'read_threshold': threshold, 'spin': 'Unknown', 'nel': nel } if init_state == True and line != '\n' and 'WARNING:' not in line: if not tddft_skip: if 'NON-ABELIAN' in line or 'SUMMARY' in line or 'SYMMETRY' in line or 'STATE #' in line: init_state = False else: if abs(float(thisline[2])) > threshold: ci[-1].occ.append(thisline[:2]) ci[-1].coeffs.append(thisline[2]) elif tddft_skip: tddft_skip -= 1 fname.close() #--- Calculating norm of CI states display('\nIn total, %d states have been read.' % len(ci)) display('Norm of the states:') for i in range(len(ci)): j = numpy.array(ci[i].coeffs, dtype=float) norm = numpy.sum(j**2) ci[i].coeffs = j # Write Norm to log-file display('\tState %s:\tNorm = %0.8f (%d Coefficients)' % (ci[i].info['state'], norm, len(ci[i].coeffs))) # Transform to numpy arrays ci[i].occ = numpy.array([s for s in ci[i].occ], dtype=numpy.intc) - 1 return ci
def order_mo_higher_deg(mo, index_list=None, backward=True, mu=1e-1, deg=2, **kwargs): '''Orders a 3d-matrix (shape=(Nfiles,NMO,NAO)) by interchanging the axis=1, i.e., NMO, applying an extrapolation a polynomial fit with a Vandermonde matrix as implemented in numpy.''' shape = numpy.shape(mo) # Check if degree is correctly set if not isinstance(deg, int) or deg < 1 or deg > (shape[0] - 1): raise IOError('Wrong choice for degree of the fitting polynomial!') display('\tusing a least squares polynomial fit of degree %d.' % deg) if index_list == None: index_list = numpy.ones((shape[0], shape[1]), dtype=int) index_list *= numpy.arange(shape[1], dtype=int) if 'criterion' in kwargs: if kwargs['criterion'] == '1-norm': test = lambda x, y: numpy.sum(numpy.abs(x)) < numpy.sum( numpy.abs(y)) if kwargs['criterion'] == '2-norm': test = lambda x, y: ((x**2).sum()) < ((y**2).sum()) elif kwargs['criterion'] == 'infty-norm': test = lambda x, y: abs(x).max() < abs(y).max() elif kwargs['criterion'] == 'perc': test = lambda x, y: ( (x**2 < y**2).sum() / float(shape[2])) > 1. / 2. else: raise ValueError('creterion %s is not defined!' % kwargs['criterion']) else: # Take 2-norm by default test = lambda x, y: ((x**2).sum()) < ((y**2).sum()) if backward: st = [-(deg + 1), 0, -1] x = numpy.arange(0, deg + 1) else: st = [deg, -1, 1] x = numpy.arange(-deg, 1) for i, i_0 in enumerate(range(shape[1])[:-1]): for rr in range(shape[0])[st[0]:st[1]:st[2]]: epol = numpy.zeros(shape[2]) for k in range(shape[2]): if mo[rr, i_0, k] != 0.: xnew = rr + st[2] y = mo[rr + x, i_0, k] z = numpy.polyfit(rr + x, y, deg) epol[k] = numpy.poly1d(z)(xnew) cp = ((mo[rr + st[2], i_0, :] - epol[:])**2) cm = ((-1 * mo[rr + st[2], i_0, :] - epol[:])**2) is_smaller = test(cm, cp) current = cm if is_smaller else cp diff = current i_1 = i_0 new_signs = [1, (-1)**is_smaller] # Check other molecular orbitals for ik_index, ik in enumerate(range(shape[1])[i + 1:]): cp = ((mo[rr + st[2], ik, :] - epol[:])**2) cm = ((-1 * mo[rr + st[2], ik, :] - epol[:])**2) is_smaller = test(cm, cp) current = cm if is_smaller else cp if test(current, diff): diff = current i_1 = ik new_signs = [1, (-1)**is_smaller] if i_0 != i_1: mo[rr + st[2], [i_0, i_1], :] = mo[rr + st[2], [i_1, i_0], :] index_list[rr + st[2], [i_0, i_1]] = index_list[rr + st[2], [i_1, i_0]] mo[rr, i_0, :] *= new_signs[0] mo[rr + st[2], i_0, :] *= new_signs[1] index_list[rr, i_0] *= new_signs[0] index_list[rr + st[2], i_0] *= new_signs[1] return mo, index_list
def run_orbkit(use_qc=None, check_options=True, standalone=False): '''Controls the execution of all computational tasks. **Parameters:** use_qc : QCinfo, optional If not None, the reading of a quantum chemistry output is omitted and the given QCinfo class is used for all computational tasks. (See :ref:`Central Variables` in the manual for details on QCinfo.) check_options : bool, optional If True, the specified options will be validated. **Returns:** data : type and shape depend on the options. Contains orbkit's output. See :ref:`High-Level Interface` in the manual for details. ''' # Set some global variables global qc # Display program information display(lgpl_short) # Check for the correctness of orbkit.options if check_options: display('Checking orbkit.options...\n') options.check_options(display=display, interactive=False, info=True, check_io=(use_qc is None)) # Measurement of required execution time t = [time.time()] # Do we need to read out the info of all MOs? if (options.mo_set or options.calc_mo) is not False: options.all_mo = True if use_qc is None: # Read the input file qc = read.main_read(options.filename, itype=options.itype, all_mo=options.all_mo, spin=options.spin, cclib_parser=options.cclib_parser) else: # Use a user defined QCinfo class. qc = use_qc display('\nSetting up the grid...') if options.grid_file is not None: # Read the grid from an external file grid.read(options.grid_file) elif options.adjust_grid is not None: # Adjust the grid to geo_spec extend, step = options.adjust_grid grid.adjust_to_geo(qc, extend=extend, step=step) elif options.random_grid: # Create a randomized grid grid.random_grid(qc.geo_spec) # Initialize grid grid.grid_init(is_vector=options.is_vector) if options.is_vector: grid.is_regular = False display(grid.get_grid()) # Display the grid if not grid.is_regular and options.center_grid is not None: raise IOError( 'The option --center is only supported for regular grids.') elif options.center_grid is not None: atom = grid.check_atom_select(options.center_grid, qc.geo_info, qc.geo_spec, interactive=True, display=display) # Center the grid to a specific atom and (0,0,0) if requested grid.center_grid(qc.geo_spec[atom - 1], display=display) if check_options or standalone: options.check_grid_output_compatibilty() t.append(time.time()) # A new time step # The calculation of all AOs (--calc_ao) if options.calc_ao != False: data = extras.calc_ao(qc, drv=options.drv, otype=options.otype) t.append(time.time()) # Final time good_bye_message(t) return data # The calculation of selected MOs (--calc_mo) or # the density formed by selected MOs (--mo_set) if (options.mo_set or options.calc_mo) != False: # What should the program do? if options.calc_mo != False: fid_mo_list = options.calc_mo elif options.mo_set != False: fid_mo_list = options.mo_set # Call the function for actual calculation if options.calc_mo != False: data = extras.calc_mo(qc, fid_mo_list, drv=options.drv, otype=options.otype) elif options.mo_set != False: data = extras.mo_set(qc, fid_mo_list, drv=options.drv, laplacian=options.laplacian, otype=options.otype) t.append(time.time()) # Final time good_bye_message(t) return data if options.gross_atomic_density is not None: atom = options.gross_atomic_density rho_atom = extras.numerical_mulliken_charges(atom, qc) if not grid.is_vector: mulliken_num = rho_atom[1] rho_atom = rho_atom[0] if not options.no_output: fid = '%s.h5' % options.outputname display('\nSaving to Hierarchical Data Format file (HDF5)...' + '\n\t%(o)s' % {'o': fid}) output.hdf5_write(fid, mode='w', gname='', atom=core.numpy.array(atom), geo_info=qc.geo_info, geo_spec=qc.geo_spec, gross_atomic_density=rho_atom, x=grid.x, y=grid.y, z=grid.z) if not options.is_vector: output.hdf5_write( fid, mode='a', gname='/numerical_mulliken_population_analysis', **mulliken_num) t.append(time.time()) good_bye_message(t) return rho_atom if options.mo_tefd is not None: mos = options.mo_tefd ao_list = core.ao_creator(qc.geo_spec, qc.ao_spec) mo_tefd = [] index = [] for i, j in mos: mo_tefd.append([]) index.append([]) for ii_d in options.drv: display('\nMO-TEFD: %s->%s %s-component' % (i, j, ii_d)) tefd = extras.mo_transition_flux_density(i, j, qc, drv=ii_d, ao_list=ao_list) mo_tefd[-1].append(tefd) index[-1].append('%s->%s:%s' % (i, j, ii_d)) if not options.no_output: from numpy import array fid = '%s.h5' % options.outputname display('\nSaving to Hierarchical Data Format file (HDF5)...' + '\n\t%(o)s' % {'o': fid}) HDF5_File = output.hdf5_open(fid, mode='w') data = { 'geo_info': array(qc.geo_info), 'geo_spec': array(qc.geo_spec), 'mo_tefd:info': array(index), 'mo_tefd': array(mo_tefd), 'x': grid.x, 'y': grid.y, 'z': grid.z } output.hdf5_append(data, HDF5_File, name='') HDF5_File.close() t.append(time.time()) good_bye_message(t) return mo_tefd t.append(time.time()) # A new time step # Compute the (derivative of the) electron density if options.no_slice: data = core.rho_compute_no_slice(qc, drv=options.drv, laplacian=options.laplacian, return_components=False) else: data = core.rho_compute(qc, drv=options.drv, slice_length=options.slice_length, laplacian=options.laplacian, numproc=options.numproc) if options.drv is None: rho = data elif options.laplacian: rho, delta_rho, laplacian_rho = data else: rho, delta_rho = data # Compute the reduced electron density if requested if options.z_reduced_density: if grid.is_vector: display('\nSo far, reducing the density is not supported for ' + 'vector grids.\nSkipping the reduction...\n') elif options.drv is not None: display( '\nSo far, reducing the density is not supported for ' + 'the derivative of the density.\nSkipping the reduction...\n') else: from scipy import integrate display('\nReducing the density with respect to the z-axis.\n') rho = integrate.simps(rho, grid.x, dx=grid.delta_[0], axis=0, even='avg') rho = integrate.simps(rho, grid.y, dx=grid.delta_[1], axis=0, even='avg') t.append(time.time()) # A new time step # Generate the output requested if not options.no_output: output_written = output.main_output(rho, qc.geo_info, qc.geo_spec, outputname=options.outputname, otype=options.otype, data_id='rho', omit=['vmd', 'mayavi'], mo_spec=qc.mo_spec) if options.drv is not None: output_written.extend( output.main_output(delta_rho, qc.geo_info, qc.geo_spec, outputname=options.outputname, otype=options.otype, data_id='delta_rho', omit=['vmd', 'mayavi'], mo_spec=qc.mo_spec, drv=options.drv)) if options.laplacian: output_written.extend( output.main_output(laplacian_rho, qc.geo_info, qc.geo_spec, outputname=options.outputname + '_laplacian', otype=options.otype, data_id='laplacian_rho', omit=['vmd', 'mayavi'], mo_spec=qc.mo_spec)) if 'vmd' in options.otype: # Create VMD network display('\nCreating VMD network file...' + '\n\t%(o)s.vmd' % {'o': options.outputname}) cube_files = [] for i in output_written: if i.endswith('.cb'): cube_files.append(i) output.vmd_network_creator(options.outputname, cube_files=cube_files) t.append(time.time()) # Final time good_bye_message(t) if 'mayavi' in options.otype: plt_data = [rho] datalabels = ['rho'] if options.drv is not None: plt_data.extend(delta_rho) datalabels.extend( ['d/d%s of %s' % (ii_d, 'rho') for ii_d in options.drv]) if options.laplacian: plt_data.append(laplacian_rho) datalabels.append('laplacian of rho') output.main_output(plt_data, qc.geo_info, qc.geo_spec, otype='mayavi', datalabels=datalabels) # Return the computed data, i.e., rho for standard, and (rho,delta_rho) # for derivative calculations. For laplacian (rho,delta_rho,laplacian_rho) return data
def read_gaussian_log(fname, all_mo=False, spin=None, orientation='standard', i_link=-1, i_geo=-1, i_ao=-1, i_mo=-1, interactive=True, **kwargs): '''Reads all information desired from a Gaussian .log file. **Parameters:** fname: str, file descriptor Specifies the filename for the input file. fname can also be used with a file descriptor instad of a filename. all_mo : bool, optional If True, all molecular orbitals are returned. spin : {None, 'alpha', or 'beta'}, optional If not None, returns exclusively 'alpha' or 'beta' molecular orbitals. orientation : string, choices={'input', 'standard'}, optional Specifies orientation of the molecule in Gaussian nomenclature. [#first]_ i_link : int, default=-1 Selects the file for linked Gaussian jobs. i_geo : int, default=-1 Selects the geometry section of the output file. i_ao : int, default=-1 Selects the atomic orbital section of the output file. i_mo : int, default=-1 Selects the molecular orbital section of the output file. interactive : bool If True, the user is asked to select the different sets. **Returns:** qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, ao_spherical, mo_spec, etot : See :ref:`Central Variables` for details. .. [#first] Attention: The MOs in the output are only valid for the standard orientation! ''' if isinstance(fname, str): filename = fname fname = descriptor_from_file(filename, index=0) else: filename = fname.name flines = fname.readlines() # Read the WHOLE file into RAM if isinstance(fname, str): fname.close() # Leave existing file descriptors alive # Search the file the specific sections count = { 'link': 0, 'geometry': 0, 'geometry_input': 0, 'atomic orbitals': 0, 'molecular orbitals': [], 'state': [] } def check_sel(count, i, interactive=False, default=-1): if count == 0: raise IndexError elif count == 1: return 0 message = '\tPlease give an integer from 0 to {0} (default: {0}): '.format( count - 1) try: if interactive: i = raw_input(message) i = default if i == '' else int(i) i = range(count)[i] except (IndexError, ValueError): raise IOError(message.replace(':', '!')) else: display('\tSelecting the %s' % ('last element.' if (i == count - 1) else 'element %d.' % i)) return i # Go through the file line by line for il in range(len(flines)): line = flines[il] # The current line as string # Check the file for keywords if ' Entering Link 1' in line: count['link'] += 1 try: display('\tFound %d linked GAUSSIAN files.' % count['link']) i_link = check_sel(count['link'], i_link, interactive=interactive) except IndexError: raise IOError('Found no `Entering Link 1` keyword!') cartesian_basis = True c_link = 0 # Go through the file line by line for il in range(len(flines)): line = flines[il] # The current line as string thisline = line.split() # The current line split into segments # Check the file for keywords if ' Entering Link 1' in line: c_link += 1 if i_link == (c_link - 1): if ' orientation:' in line: if '%s orientation:' % orientation in line.lower(): count['geometry'] += 1 if 'input orientation:' in line.lower(): count['geometry_input'] += 1 elif 'Standard basis:' in line or 'General basis read from cards:' in line: # Check if a cartesian basis has been applied if '(5D, 7F)' in line: cartesian_basis = False elif '(6D, 10F)' not in line: raise IOError( 'Please apply a Spherical Harmonics (5D, 7F) or ' + 'a Cartesian Gaussian Basis Set (6D, 10F)!') elif 'AO basis set' in line: count['atomic orbitals'] += 1 elif 'The electronic state is ' in line: count['state'].append(thisline[-1][:-1]) elif 'Orbital Coefficients:' in line: mo_type = thisline[0] if mo_type != 'Beta': count['molecular orbitals'].append(mo_type) else: count['molecular orbitals'][-1] = 'Alpha&Beta' display('\nContent of the GAUSSIAN .log file:') display('\tFound %d geometry section(s). (%s orientation)' % (count['geometry'], orientation)) try: i_geo = check_sel(count['geometry'], i_geo, interactive=interactive) except IndexError: count['geometry'] = count['geometry_input'] orientation = 'input' display('\Looking for "Input orientation": \n' + '\tFound %d geometry section(s). (%s orientation)' % (count['geometry'], orientation)) try: i_geo = check_sel(count['geometry'], i_geo, interactive=interactive) except IndexError: raise IOError('Found no geometry section!' + ' Are you sure this is a GAUSSIAN .log file?') try: display('\tFound %d atomic orbitals section(s) %s.' % (count['atomic orbitals'], '(6D, 10F)' if cartesian_basis else '(5D, 7F)')) i_ao = check_sel(count['atomic orbitals'], i_ao, interactive=interactive) except IndexError: raise IOError('Write GFINPUT in your GAUSSIAN route section to print' + ' the basis set information!') try: display('\tFound the following %d molecular orbitals section(s):' % len(count['molecular orbitals'])) except IndexError: raise IOError( 'Write IOP(6/7=3) in your GAUSSIAN route section to print\n' + ' all molecular orbitals!') for i, j in enumerate(count['molecular orbitals']): string = '\t\tSection %d: %s Orbitals' % (i, j) try: string += ' (electronic state: %s)' % count['state'][i] except IndexError: pass display(string) i_mo = check_sel(len(count['molecular orbitals']), i_mo, interactive=interactive) if spin is not None: if spin != 'alpha' and spin != 'beta': raise IOError('`spin=%s` is not a valid option' % spin) else: display('Reading only molecular orbitals of spin %s.' % spin) # Set a counter for the AOs basis_count = 0 # Initialize some variables sec_flag = None skip = 0 c_link = 0 c_geo = 0 c_ao = 0 c_mo = 0 c_sao = 0 old_ao = -1 orb_sym = [] qc = QCinfo() index = [] # Go through the file line by line for il in range(len(flines)): line = flines[il] # The current line as string thisline = line.split() # The current line split into segments # Check the file for keywords if ' Entering Link 1' in line: c_link += 1 if i_link == (c_link - 1): if '%s orientation:' % orientation in line.lower(): # The section containing information about # the molecular geometry begins if i_geo == c_geo: qc.geo_info = [] qc.geo_spec = [] sec_flag = 'geo_info' c_geo += 1 skip = 4 elif 'Standard basis:' in line or 'General basis read from cards:' in line: # Check if a cartesian basis has been applied if '(5D, 7F)' in line: cartesian_basis = False elif '(6D, 10F)' not in line: raise IOError( 'Please apply a Spherical Harmonics (5D, 7F) or ' + 'a Cartesian Gaussian Basis Sets (6D, 10F)!') elif 'AO basis set' in line: # The section containing information about # the atomic orbitals begins if i_ao == c_ao: qc.ao_spec = [] if not cartesian_basis: qc.ao_spherical = [] sec_flag = 'ao_info' c_ao += 1 basis_count = 0 bNew = True # Indication for start of new AO section elif 'Orbital symmetries:' in line: sec_flag = 'mo_sym' add = '' orb_sym = [] elif 'Orbital Coefficients:' in line: # The section containing information about # the molecular orbitals begins if (i_mo == c_mo): sec_flag = 'mo_info' mo_type = count['molecular orbitals'][i_mo] qc.mo_spec = [] offset = 0 add = '' orb_spin = [] if orb_sym == []: if 'Alpha' in mo_type: add = '_a' orb_spin = ['alpha'] * basis_count orb_sym = ['A1' + add] * basis_count if 'Beta' in mo_type: add = '_b' orb_spin += ['beta'] * basis_count orb_sym += ['A1' + add] * basis_count for i in range(len(orb_sym)): # for numpy version < 1.6 c = ((numpy.array(orb_sym[:i + 1]) == orb_sym[i]) != 0).sum() # for numpy version >= 1.6 this could be used: #c = numpy.count_nonzero(numpy.array(orb_sym[:i+1]) == orb_sym[i]) qc.mo_spec.append({ 'coeffs': numpy.zeros(basis_count), 'energy': 0., 'sym': '%d.%s' % (c, orb_sym[i]) }) if orb_spin != []: qc.mo_spec[-1]['spin'] = orb_spin[i] if mo_type != 'Beta': c_mo += 1 bNew = True # Indication for start of new MO section elif 'E(' in line: qc.etot = float(line.split('=')[1].split()[0]) else: # Check if we are in a specific section if sec_flag == 'geo_info': if not skip: qc.geo_info.append( [thisline[1], thisline[0], thisline[1]]) qc.geo_spec.append([float(ij) for ij in thisline[3:]]) if '-----------' in flines[il + 1]: sec_flag = None else: skip -= 1 if sec_flag == 'ao_info': # Atomic orbital section if ' ****' in line: # There is a line with stars after every AO bNew = True # If there is an additional blank line, the AO section is complete if flines[il + 1].split() == []: sec_flag = None elif bNew: # The following AOs are for which atom? bNew = False at_num = int(thisline[0]) - 1 ao_num = 0 elif len(thisline) == 4: # AO information section # Initialize a new dict for this AO ao_num = 0 # Initialize number of atomic orbiatls ao_type = thisline[0].lower() # Type of atomic orbital pnum = int(thisline[1]) # Number of primatives for i_ao in ao_type: # Calculate the degeneracy of this AO and increase basis_count basis_count += l_deg( lquant[i_ao], cartesian_basis=cartesian_basis) qc.ao_spec.append({ 'atom': at_num, 'type': i_ao, 'pnum': pnum, 'coeffs': numpy.zeros((pnum, 2)) }) else: # Append the AO coefficients coeffs = numpy.array(line.replace('D', 'e').split(), dtype=numpy.float64) for i_ao in range(len(ao_type)): qc.ao_spec[-len(ao_type) + i_ao]['coeffs'][ao_num, :] = [ coeffs[0], coeffs[1 + i_ao] ] ao_num += 1 if sec_flag == 'mo_sym': if 'electronic state' in line: sec_flag = None else: info = line[18:].replace('(', '').replace(')', '').split() if 'Alpha' in line: add = '_a' elif 'Beta' in line: add = '_b' for i in info: orb_sym.append(i + add) if sec_flag == 'mo_info': # Molecular orbital section info = line[:21].split() if info == []: coeffs = line[21:].split() if bNew: index = [offset + i for i in range(len(coeffs))] bNew = False else: for i, j in enumerate(index): qc.mo_spec[j]['occ_num'] = int( 'O' in coeffs[i]) if mo_type not in 'Alpha&Beta': qc.mo_spec[j]['occ_num'] *= 2 elif 'Eigenvalues' in info: coeffs = line[21:].replace('-', ' -').split() if mo_type == 'Natural': key = 'occ_num' else: key = 'energy' for i, j in enumerate(index): qc.mo_spec[j][key] = float(coeffs[i]) else: coeffs = line[21:].replace('-', ' -').split() if not cartesian_basis and offset == 0: if old_ao != line[:14].split()[-1] or len( line[:14].split()) == 4: old_ao = line[:14].split()[-1] c_sao += 1 i = c_sao - 1 l = lquant[line[13].lower()] m = line[14:21].replace(' ', '').lower() p = 'yzx'.find(m) if len(m) == 1 else -1 if p != -1: m = p - 1 elif m == '': m = 0 else: m = int(m) qc.ao_spherical.append([i, (l, m)]) for i, j in enumerate(index): qc.mo_spec[j]['coeffs'][int(info[0]) - 1] = float( coeffs[i]) if int(info[0]) == basis_count: bNew = True offset = index[-1] + 1 if index[-1] + 1 == len(orb_sym): sec_flag = None orb_sym = [] # Are all MOs requested for the calculation? if not all_mo: for i in range(len(qc.mo_spec))[::-1]: if qc.mo_spec[i]['occ_num'] < 0.0000001: del qc.mo_spec[i] if spin is not None: if orb_spin == []: raise IOError( 'You requested `%s` orbitals, but None of them are present.' % spin) else: for i in range(len(qc.mo_spec))[::-1]: if qc.mo_spec[i]['spin'] != spin: del qc.mo_spec[i] # Convert geo_info and geo_spec to numpy.ndarrays qc.format_geo(is_angstrom=True) return qc
def mo_select(mo_spec, fid_mo_list, strict=False): '''Selects molecular orbitals from an external file or a list of molecular orbital labels. **Parameters:** mo_spec : See :ref:`Central Variables` for details. strict : bool, optional If True, orbkit will follow strictly the fid_mo_list, i.e., the order of the molecular orbitals will be kept and multiple occurrences of items will evoke multiple calculations of the respective molecular orbitals. fid_mo_list : str, `'all_mo'`, or list | If fid_mo_list is a str, specifies the filename of the molecular orbitals list. | If fid_mo_list is 'all_mo', creates a list containing all molecular orbitals. | If fid_mo_list is a list, provides a list (or a list of lists) of molecular orbital labels. **Supported Formats:** Integer List (Counting from **ONE**!):: 1 2 3 5 4 h**o lumo+2:lumo+4 List with Symmetry Labels:: 1.1 2.1 1.3 1.1 4.1 4.1 2.3 2.1 **Returns:** Dictionary with following Members: :mo: - List of molecular orbital labels. :mo_ii: - List of molecular orbital indices. :mo_spec: - Selected elements of mo_spec. See :ref:`Central Variables` for details. :mo_in_file: - List of molecular orbital labels within the fid_mo_list file. :sym_select: - If True, symmetry labels have been used. ..attention: For **unrestricted** calculations, orbkit adds `_a` (alpha) or `_b` (beta) to the symmetry labels, e.g., `1.1_a`. If you have specified the option `spin=alpha` or `spin=beta`, only the alpha or the beta orbitals are taken into account for the counting within the Integer List. ''' import re display('\nProcessing molecular orbital list...') mo_in_file = [] selected_mo = [] sym_select = False def assign_selected_mo(selected_mo, mo_spec, strict=False, what=lambda x, y: y[x]['sym']): selected_mo_spec = [] selected_mo_ii = [] for i in selected_mo: is_present = False for k in range(len(mo_spec)): if (what(k, mo_spec) == i): is_present = True if strict or (i not in selected_mo_ii): selected_mo_spec.append(mo_spec[k]) selected_mo_ii.append(what(k, mo_spec)) if not is_present: raise IOError('Cannot find %s in mo_spec' % i) selected_mo_ii = numpy.array(selected_mo_ii) return selected_mo_spec, selected_mo_ii def expr2int(expr): if isinstance(expr, int): return expr x = 0 for i in re.findall(r'\d+|[+-]\d+', expr): x += int(i) return x def get_selection(selected_mo): mo_occup = numpy.array([i['occ_num'] for i in mo_spec]) h**o = (mo_occup > 0.).nonzero()[0][-1] + 1 # molden numbering lumo = (mo_occup > 0.).nonzero()[0][-1] + 1 + 1 # molden numbering mo_energy = numpy.array([i['energy'] for i in mo_spec]) last_bound = sum(mo_energy <= 0.0) # molden numbering sel = [] for i in selected_mo: i = i.lower().replace('h**o', str(h**o)).replace('lumo', str(lumo)) i = i.replace('last_bound', str(last_bound)) if ':' in i: k = [1, len(mo_spec) + 1, 1] i = i.split(':') for ik, j in enumerate(i): if j != '': k[ik] = j i = list(range(*[expr2int(j) for j in k])) sel.extend(i) else: sel.append(int(i)) return sel if isinstance(fid_mo_list, str) and fid_mo_list.lower() == 'all_mo': selected_mo = numpy.array(numpy.arange(len(mo_spec)) + 1, dtype=numpy.str) mo_in_file = [selected_mo] selected_mo_spec = mo_spec selected_mo_ii = numpy.array([i['sym'] for i in selected_mo_spec]) else: if isinstance(fid_mo_list, str) and not path.exists(fid_mo_list): if ',' in fid_mo_list: fid_mo_list = fid_mo_list.split(',') else: fid_mo_list = [fid_mo_list] if isinstance(fid_mo_list, list): for i in fid_mo_list: if not isinstance(i, list): i = i.split(',') if isinstance(i, str) else [i] selected_mo.extend(list(map(str, i))) mo_in_file.append(list(map(str, i))) else: try: fid = open(fid_mo_list, 'r') flines = fid.readlines() fid.close() for line in flines: integer = line.replace(',', ' ').split() mo_in_file.append(integer) selected_mo.extend(integer) except: raise IOError('The selected mo-list (%(m)s) is not valid!' % {'m': fid_mo_list} + '\ne.g.\n\t1\t3\n\t2\t7\t9\n') # Print some information for i, j in enumerate(mo_in_file): display('\tLine %d: %s' % (i + 1, ', '.join(j))) # Check if the molecular orbitals are specified by symmetry # (e.g. 1.1 in MOLPRO nomenclature) or # by the number in the input file (e.g. 1) try: # Try to convert selections into integer for i in selected_mo: if isinstance(i, int): continue i = i.replace('h**o', '1').replace('lumo', '2').replace('last_bound', '3') for r in ['-', '+', ':']: i = i.replace(r, '') int(i) except ValueError: sym_select = True errors = [] for i in range(len(selected_mo)): if not '.' in selected_mo[i]: errors.append(i) if errors: err = [selected_mo[i] for i in errors] raise IOError( '`%s` are no valid labels according ' % ', '.join(err) + 'to the MOLPRO nomenclature, e.g., `5.1` or `5.A1`.' + '\n\tHint: You cannot mix integer numbering and MOLPRO\'s ' + 'symmetry labels') if sym_select: what = lambda x, y: y[x]['sym'] selected_mo_spec, selected_mo_ii = assign_selected_mo( selected_mo, mo_spec, strict=strict, what=what) else: selected_mo = get_selection(selected_mo) if not strict: selected_mo = list(map(int, selected_mo)) selected_mo.sort() selected_mo = list(map(str, selected_mo)) what = lambda x, y: str(x + 1) selected_mo_spec, selected_mo_ii = assign_selected_mo( selected_mo, mo_spec, strict=strict, what=what) selected_mo = selected_mo_ii for i in range(len(mo_in_file)): mo_in_file[i] = list(map(str, get_selection(mo_in_file[i]))) # Print some information display('\nThe following orbitals will be considered...') for i, j in enumerate(mo_in_file): display('\tLine %d: %s' % (i + 1, ', '.join(j))) display('') return { 'mo': selected_mo, 'mo_ii': selected_mo_ii, 'mo_spec': selected_mo_spec, 'mo_in_file': mo_in_file, 'sym_select': sym_select }
def main_output(data, qc=None, outputname='data', otype='auto', gname='', drv=None, omit=[], datalabels='', mode='w', **kwargs): '''Creates the requested output. **Parameters:** data : numpy.ndarray, shape=N, shape=((NDRV,) + N), shape=(n, (NDRV,) + N) or list of numpy.ndarrays Contains the output data. The shape (N) depends on the grid and the data, i.e., 3d for regular grid, 1d for vector grid. qc : class or dict QCinfo class or dictionary containing the following attributes/keys. See :ref:`Central Variables` for details. outputname : str or list of str Contains the base name of the output file. If outputname contains @, string will be split and first part interpreted as outputname and second as gname (cf. Parameters:gname). otype : str or list of str, optional Contains the output file type. Possible options: 'auto', 'h5', 'cb', 'am', 'hx', 'vmd', 'mayavi' If otype='native', a native input file will be written, the type of which may be specifie by ftype='numpy'. gname : str, optional For native, HDF5, or npz output, specifies the group, where the data will be stored. drv : None, list of str or list of list of str, optional If not None, a 4d(regular)/2d(vector) input data array will be expected with NDRV = len(drv). Specifies the file labels, i.e. e.g., data_d{drv}.cube for 4d array. For 5d arrays i.e., data_0_d{drv}.cube datalabels : list of str, optional If not empty, the output file types specified here are omitted. omit : list of str, optional If not empty, the output file types specified here are omitted. mode : str={'r', 'w', 'a'}, optional Specifies the mode used to open the file (native, HDF5, or npz). **Note:** All additional keyword arguments are forwarded to the output functions. ''' if otype is None or otype == []: return [] if isinstance(outputname, str): if '@' in outputname: outputname, gname = outputname.split('@') if isinstance(otype, str): if otype == 'auto': outputname, otype = path.splitext(outputname) otype = otype[1:] otype = [otype] elif isinstance(otype, list) and len(otype) == 1: if otype[0] == 'auto': outputname, otype = path.splitext(outputname) otype = [otype[1:]] else: for iot in range(len(otype)): if otype[iot] == 'auto': outputname, tmp = path.splitext(outputname) if tmp != '': otype[iot] = tmp[1:] # Catch our native format before all else # We can't figure this out by the file ending alone # as we support hdf5 for output of both grid-based data # as well as our internal format output_written = [] internals = [i for i in range(len(otype)) if otype[i] == 'native'] if len(internals) > 0: if not isinstance(data, list): data = [data] if isinstance(outputname, str): outputname = [outputname for _ in data] if 'ftype' in kwargs.keys(): if isinstance(kwargs['ftype'], str): ftype = [kwargs['ftype'] for _ in data] else: ftype = ['numpy' for _ in data] if 'group' in kwargs.keys(): if isinstance(kwargs['group'], str): group = [kwargs['group'] for _ in data] else: group = [i.__class__.__name__.lower() for i in data] display('Writing native input file...') for i, oname in enumerate(outputname): output_written.append( write_native(data[i], oname, ftype[i], mode=mode, gname=path.join(gname, group[i]))) display('\n'.join(['\t' + i for i in output_written])) else: print_waring = False output_not_possible = (grid.is_vector and not grid.is_regular) # Shape shall be (Ndrv,Ndata,Nx,Ny,Nz) or (Ndrv,Ndata,Nxyz) data = numpy.array(data) dims = 1 if grid.is_vector else 3 shape = data.shape if drv is not None and isinstance(drv, str): drv = [drv] if data.ndim < dims: output_not_possible = True display('data.ndim < ndim of grid') elif data.ndim == dims: # 3d data set data = data[numpy.newaxis, numpy.newaxis] elif data.ndim == dims + 1: # 4d data set if drv is not None: data = data[:, numpy.newaxis] else: data = data[numpy.newaxis] elif data.ndim == dims + 2: # 5d data set check if drv matches Ndrv if drv is None or len(drv) != data.shape[0]: drv = list(range(data.shape[0])) elif data.ndim > dims + 2: output_not_possible = True display('data.ndim > (ndim of grid) +2') if 'vmd' in otype and not ('cb' in otype or 'cube' in otype): otype.append('cube') if 'hx' in otype and not 'am' in otype: otype.append('am') otype = [i for i in otype if i not in omit] otype_synonyms = [synonyms[i] for i in otype] otype_ext = dict(zip(otype_synonyms, otype)) # Convert the data to a regular grid, if possible is_regular_vector = (grid.is_vector and grid.is_regular) if is_regular_vector: display( '\nConverting the regular 1d vector grid to a 3d regular grid.' ) grid.vector2grid(*grid.N_) data = numpy.array(grid.mv2g(data)) isstr = isinstance(outputname, str) if isinstance(datalabels, str): if data.shape[1] > 1: datalabels = numpy.array([ str(idata) + ',' + datalabels for idata in range(data.shape[1]) ]) else: datalabels = numpy.array([datalabels]) elif isinstance(datalabels, list): datalabels = numpy.array(datalabels) if drv is not None: fid = '%(f)s_d%(d)s.' datalabel_id = 'd/d%(d)s %(f)s' contents = { 'axis:0': numpy.array( ['d/d%s' % i if i is not None else str(i) for i in drv]), 'axis:1': datalabels } it = enumerate(drv) elif data.shape[0] > 1: fid = '%(f)s_%(d)s.' datalabel_id = '%(d)s %(f)s' it = enumerate(data.shape[0]) contents = { 'axis:0': numpy.arange(data.shape[0]).astype(str), 'axis:1': datalabels } else: fid = '%(f)s.' datalabel_id = '%(f)s' it = [(0, None)] if data.shape[1] > 1: contents = {'axis:0': datalabels} else: contents = datalabels cube_files = [] all_datalabels = [] for idrv, jdrv in it: datasetlabels = [] for idata in range(data.shape[1]): if isstr: f = { 'f': outputname + '_' + str(idata) if data.shape[1] > 1 else outputname, 'd': jdrv } else: f = {'f': outputname[idata], 'd': jdrv} c = {'f': datalabels[idata], 'd': jdrv} datalabel = datalabel_id % c datasetlabels.append(datalabel) if 'am' in otype_synonyms and not print_waring: if output_not_possible: print_waring = True else: filename = fid % f + otype_ext['am'] display('\nSaving to ZIBAmiraMesh file...\n\t' + filename) amira_creator(data[idrv, idata], filename) output_written.append(filename) if 'hx' in otype_synonyms and not print_waring: if output_not_possible: print_waring = True else: filename = fid % f + otype_ext['hx'] display('\nCreating ZIBAmira network file...\n\t' + filename) hx_network_creator(data[idrv, idata], filename) output_written.append(filename) if 'cube' in otype_synonyms and not print_waring: if output_not_possible: print_waring = True elif qc is None: display( '\nFor cube file output `qc` is a required keyword parameter in `main_output`.' ) else: filename = fid % f + otype_ext['cube'] display('\nSaving to cube file...\n\t' + filename) cube_creator(data[idrv, idata], filename, qc.geo_info, qc.geo_spec, comments=datalabel, **kwargs) output_written.append(filename) cube_files.append(filename) all_datalabels.extend(datasetlabels) if 'vmd' in otype_synonyms and not print_waring: if output_not_possible: print_waring = True else: filename = (outputname if isstr else outputname[-1]) + '.' + otype_ext['vmd'] display('\nCreating VMD network file...\n\t' + filename) vmd_network_creator(filename, cube_files=cube_files, **kwargs) output_written.append(filename) if 'h5' in otype_synonyms: filename = (outputname if isstr else outputname[-1]) + '.' + otype_ext['h5'] display('\nSaving to Hierarchical Data Format file (HDF5)...\n\t' + filename) hdf5_creator(data.reshape(shape), filename, qcinfo=qc, gname=gname, ftype='hdf5', contents=contents, mode=mode, **kwargs) output_written.append(filename) if 'npz' in otype_synonyms: filename = (outputname if isstr else outputname[-1]) display('\nSaving to a compressed .npz archive...\n\t' + filename + '.npz') hdf5_creator(data.reshape(shape), filename, qcinfo=qc, gname=gname, ftype='numpy', contents=contents, mode=mode, **kwargs) output_written.append(filename) if 'mayavi' in otype_synonyms: if output_not_possible: print_waring = True else: display('\nDepicting the results with MayaVi...\n\t') if drv == ['x', 'y', 'z'] or drv == [0, 1, 2]: is_vectorfield = True data = numpy.swapaxes(data, 0, 1) datalabels = datalabels else: is_vectorfield = False data = data.reshape((-1, ) + grid.get_shape()) datalabels = all_datalabels view_with_mayavi(grid.x, grid.y, grid.z, data, is_vectorfield=is_vectorfield, geo_spec=qc.geo_spec, datalabels=datalabels, **kwargs) if print_waring: display( 'For a non-regular vector grid (`if grid.is_vector and not grid.is_regular`)' ) display('only HDF5 is available as output format...') display('Skipping all other formats...') if is_regular_vector: # Convert the data back to a regular vector grid grid.grid2vector() return output_written
def gross_atomic_density(atom, qc, bReturnmo=False, ao_list=None, mo_list=None, drv=None): r'''Computes the gross atomic density with respect to the selected atoms. .. math:: \rho^a = \sum_i^{N_{\rm MO}} {\rm occ}_i \cdot \varphi_i^a \cdot \varphi_i **Parameters:** atom : 'all' or int or list of int Specifies the atoms (counting from one) for which the gross atomic density will be computed. If (atom == 'all') or (atom == -1), computes the gross atomic density for all atoms. qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec : See :ref:`Central Variables` for details. bReturnmo : bool, optional If True, the gross atomic molecular orbitals are additionally returned. **Returns:** rho_atom : list of numpy.ndarrays, shape=(len(atoms,) + N) Contains the atom gross atomic density on a grid. mo_atom : list of numpy.ndarrays, shape=(len(atoms,NMO) + N) Contains the NMO=len(mo_spec) gross atomic molecular orbitals on a grid. ''' if (atom == 'all' or atom == -1): atom = range(1, len(qc.geo_info) + 1) atom, index = atom2index(atom, geo_info=qc.geo_info) display('Computing the gross atomic density with respect to ' + 'the atom(s) (internal numbering)') outp = '\t[' for i, a in enumerate(atom): if not i % 10 and i != 0: outp += '\n\t' outp += '%d,\t' % a display('%s]\n' % outp[:-2]) display('\tCalculating ao_list & mo_list') if ao_list is None: ao_list = core.ao_creator(qc.geo_spec, qc.ao_spec, drv=drv) if mo_list is None: mo_list = core.mo_creator(ao_list, qc.mo_spec) display('\tCalculating the gross atomic density') N = mo_list.shape[1:] if bReturnmo: mo_atom = [[] for a in index] rho_atom = [numpy.zeros(N) for a in index] for i, a in enumerate(index): display('\t\tFinished %d of %d' % (i + 1, len(index))) ao_index = [] ao = [] ll = 0 for ii in qc.ao_spec: for l in range(core.l_deg(l=ii['type'])): if ii['atom'] == a: ao_index.append(ll) ao.append(ao_list[ll]) ll += 1 for ii_mo, spec in enumerate(qc.mo_spec): mo_info = numpy.zeros(N) for jj in range(len(ao_index)): mo_info += spec['coeffs'][ao_index[jj]] * ao[jj] rho_atom[i] += spec['occ_num'] * mo_list[ii_mo] * mo_info if bReturnmo: mo_atom[i].append(mo_info) string = 'Returning the gross atomic density' if bReturnmo: display(string + ' and\n\tthe gross atomic molecular orbitals') return rho_atom, mo_atom else: display(string) return rho_atom