def compute_mo_list(self,ao_spec,mo_matrix, iter_drv=[None, 'x', 'y', 'z']): '''Computes the values of the molecular orbitals and, if requested, their derivatives at the nuclear positions for a complete mo_matrix (shape=(Nfiles,NMO,NAO)).''' from orbkit.core import ao_creator shape = numpy.shape(mo_matrix) mo_list = numpy.zeros((shape[0],shape[1],4*numpy.shape(self.geo_spec_all)[1])) for rr in range(shape[0]): geo_spec = self.geo_spec_all[rr] x = geo_spec[:,0] y = geo_spec[:,1] z = geo_spec[:,2] N = len(x) for i,drv in enumerate(iter_drv): ao_list = ao_creator(geo_spec,self.ao_spec, exp_list=False, is_vector=True, drv=drv, x=x,y=y,z=z) for i_mo in range(shape[1]): for i_ao in range(shape[2]): mo_list[rr,i_mo,N*i+numpy.arange(N)] += mo_matrix[rr,i_mo,i_ao] * ao_list[i_ao,:] return mo_list
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 show_selected_mos(self,selected_mos,r0=0,steps=1,select_slice='xz',where=0.0, npts=[26,51],minpts=[-3,-6],maxpts=[3,6],nuclear_pos='x'): '''Uses orbkit to compute selected molecular orbitals and plots it with :func:`contour_mult_mo`.''' from orbkit import grid from orbkit.core import ao_creator,mo_creator r = range(r0,r0+steps) grid.N_ = [1,1,1] grid.min_ = [0,0,0] grid.max_ = [0,0,0] if select_slice == 'xy': k = [0,1] grid.min_[2] += where grid.max_[2] += where elif select_slice == 'yz': k = [1,2] grid.min_[0] += where grid.max_[0] += where elif select_slice == 'xz': k = [0,2] grid.min_[1] += where grid.max_[1] += where else: raise ValueError('`show_selected_mos` currently only' + 'supports slices parallel to the following planes:' + 'select_slice = `xy`, `yz`, or `xz`') for i,j in enumerate(k): grid.N_[j] = npts[i] grid.min_[j] = minpts[i] grid.max_[j] = maxpts[i] # Initialize grid grid.is_initialized = False grid.grid_init(force=True) xyz = grid.x,grid.y,grid.z for mo_sel in selected_mos: i,j = mo_sel.split('.') mo = [] for rr in r: ao_list = ao_creator(self.geo_spec_all[rr],self.ao_spec) mo.append(mo_creator(ao_list,mo_coeff_all[self.sym[j]][rr,int(i)-1,numpy.newaxis])[0].reshape(tuple(npts))) f, pics = contour_mult_mo(xyz[k[0]],xyz[k[1]],mo, xlabel=select_slice[0],ylabel=select_slice[1], title='MO:%s' % mo_sel,r0=r0) for i,pic in enumerate(pics): pic.plot(self.geo_spec_all[rr,:,k[1]],self.geo_spec_all[rr,:,k[0]],nuclear_pos, markersize=10,markeredgewidth=2)
def get_ao(x): ao_list = core.ao_creator(global_args['geo_spec'], [global_args['ao_spec'][int(x)]], drv=global_args['drv']) if global_args['otype'] is not None: drv = global_args['drv'] comments = '%03d.lxlylz=%s,at=%d' %(x, global_args['ao_spec'][x]['exp_list'][0], global_args['ao_spec'][x]['atom']) output.main_output(ao_list[0] if drv is None else ao_list, global_args['geo_info'], global_args['geo_spec'], comments=comments, outputname='%s_AO_%03d' % (global_args['ofid'],x), otype=global_args['otype'], omit=['h5','vmd','mayavi'], drv = None if drv is None else [drv]) return ao_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 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