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
qc = read.main_read(fid_molden, all_mo=True, interactive=False) qc, ci = detci.ci_read.main_ci_read(qc, fid_psi4, itype='psi4_detci', threshold=ci_readthreshold) print('=' * 80) print('Preparing All Subsequent Calculations') print('=' * 80 + '\n') # 1b. print('Setting up the grid...') grid.min_ = [-3.9, 0.0, -5.9] grid.max_ = [3.9, 0.0, 9.9] grid.delta_ = [0.2, 0.0, 0.2] grid.grid_init() print(grid.get_grid()) print('Computing the Molecular Orbitals and the Derivatives Thereof...\n') molist = core.rho_compute(qc, calc_mo=True, slice_length=slice_length, drv=[None, 'x', 'y', 'z', 'xx', 'yy', 'zz'], numproc=numproc) molistdrv = molist[1:4] # \nabla of MOs molistdrv2 = molist[-3:] # \nabla^2 of MOs molist = molist[0] # MOs print('\nComputing the Analytical Overlaps of the Molecular Orbitals...\n') aoom = get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec,
def rho_compute_no_slice(qc, calc_ao=False, calc_mo=False, drv=None, laplacian=False, return_components=False, x=None, y=None, z=None, is_vector=None, **kwargs): r'''Calculates the density, the molecular orbitals, or the derivatives thereof without slicing the grid. **Parameters:** qc : class or dict QCinfo class or dictionary containing the following attributes/keys. See :ref:`Central Variables` for details. qc.geo_spec : numpy.ndarray, shape=(3,NATOMS) See :ref:`Central Variables` for details. qc.ao_spec : List of dictionaries See :ref:`Central Variables` for details. qc.mo_spec : List of dictionaries See :ref:`Central Variables` for details. calc_mo : bool, optional If True, the computation of the molecular orbitals requested is only carried out. is_vector : bool, optional If True, performs the computations for a vector grid, i.e., with x, y, and z as vectors. drv : string or list of strings {None,'x','y', or 'z'}, optional If not None, computes the analytical derivative of the requested quantities with respect to DRV. laplacian : bool, optional If True, computes the laplacian of the density. return_components : bool, optional If True, returns the atomic and molecular orbitals, and the density, and if requested, the derivatives thereof as well. x,y,z : numpy.ndarray, optional If not None, provides a list of Cartesian coordinates, else the respective coordinates of the module :mod:`orbkit.grid` will be used. **Returns:** :if not return_components: :if calc_mo and drv is None: - mo_list :if calc_mo and drv is not None: - delta_mo_list :if not calc_mo and drv is None: - rho :if not calc_mo and drv is not None: - rho, delta_rho :if not calc_mo and laplacian: - rho, delta_rho, laplacian_rho :else: | :if calc_mo and drv is None: - ao_list,mo_list :if calc_mo and drv is not None: - delta_ao_list,delta_mo_list :if not calc_mo and drv is None: - ao_list,mo_list,rho :if not calc_mo and drv is not None: - ao_list, mo_list, rho, delta_ao_list, delta_mo_list, delta_rho :if not calc_mo and laplacian: - ao_list, mo_list, rho, delta_ao_list, delta_mo_list, delta_rho, laplacian_rho ao_list : numpy.ndarray, shape=((NAO,) + N) Contains the NAO=len(ao_spec) atomic orbitals on a grid. delta_ao_list : numpy.ndarray, shape=((NDRV,NAO) + N) Contains the derivatives with respect to drv (NDRV=len(drv)) of the NAO=len(ao_spec) atomic orbitals on a grid. mo_list : numpy.ndarray, shape=((NMO,) + N) Contains the NMO=len(qc.mo_spec) molecular orbitals on a grid. delta_mo_list : numpy.ndarray, shape=((NDRV,NMO) + N) Contains the derivatives with respect to drv (NDRV=len(drv)) of the NMO=len(qc.mo_spec) molecular orbitals on a grid. mo_norm : numpy.ndarray, shape=(NMO,) Contains the numerical norms of the molecular orbitals. rho : numpy.ndarray, shape=(N) Contains the density on a grid. delta_rho : numpy.ndarray, shape=((NDRV,) + N) Contains the derivatives with respect to drv (NDRV=len(drv)) of the density on a grid. laplacian_rho : numpy.ndarray, shape=(N) Contains the laplacian of the density on a grid, i.e. :math:`\nabla^2 \rho = \nabla^2_x \rho + \nabla^2_y \rho + \nabla^2_z \rho`. ''' if calc_ao and calc_mo: raise ValueError( 'calc_ao and calc_mo are mutually exclusive arguments.' + 'Use calc_mo and return_components instead!') # Create the grid if all(v is None for v in [x, y, z, is_vector]) and not grid.is_initialized: display('\nSetting up the grid...') grid.grid_init(is_vector=True) display(grid.get_grid()) # Display the grid if x is None: x = grid.x if y is None: y = grid.y if z is None: z = grid.z if is_vector is None: is_vector = grid.is_vector def convert(data, was_vector, N): data = numpy.array(data, order='C') if not was_vector: data = data.reshape(data.shape[:-1] + N, order='C') return data was_vector = is_vector if not is_vector: N = (len(x), len(y), len(z)) d3r = numpy.product([x[1] - x[0], y[1] - y[0], z[1] - z[0]]) # Convert regular grid to vector grid x, y, z = cy_grid.grid2vector(x.copy(), y.copy(), z.copy()) is_vector = True display('Converting the regular grid to a vector grid containing ' + '%.2e grid points...' % len(grid.x)) else: if len(x) != len(y) or len(x) != len(z): raise ValueError('Dimensions of x-, y-, and z- coordinate differ!') N = (len(x), ) if not isinstance(qc, dict): qc = qc.todict() geo_spec = qc['geo_spec'] ao_spec = qc['ao_spec'] ao_spherical = qc['ao_spherical'] mo_spec = qc['mo_spec'] if laplacian: if not (drv is None or drv == ['xx', 'yy', 'zz'] or drv == ['x2', 'y2', 'z2']): display( 'Note: You have set the option `laplacian` and specified values\n' + 'for `drv`. Both options are not compatible.\n' + 'The option `drv` has been changed to `drv=["xx","yy","zz"]`.') drv = ['xx', 'yy', 'zz'] display('\nStarting the calculation without slicing the grid...') display('\nThere are %d contracted %s AOs' % (len(Spec['mo_spec'][0]['coeffs']), 'Cartesian' if not Spec['ao_spherical'] else 'spherical') + ('' if calc_ao else ' and %d MOs to be calculated.' % len(Spec['mo_spec']))) if drv is not None: try: drv = list(drv) except TypeError: drv = [drv] display( '\nCalculating the derivatives of the atomic and molecular orbitals...' ) delta_ao_list = [[] for ii_d in drv] delta_mo_list = [[] for ii_d in drv] for i, ii_d in enumerate(drv): display('\t...with respect to %s' % ii_d) # Calculate the derivatives of the AOs and MOs delta_ao_list[i] = ao_creator(geo_spec, ao_spec, ao_spherical=ao_spherical, drv=ii_d, is_vector=True, x=x, y=y, z=z) if not calc_ao: delta_mo_list[i] = mo_creator(delta_ao_list[i], mo_spec) delta_ao_list = convert(delta_ao_list, was_vector, N) if calc_ao: return delta_ao_list delta_mo_list = convert(delta_mo_list, was_vector, N) if calc_mo: return ((delta_ao_list, delta_mo_list) if return_components else delta_mo_list) delta2_mo_list = [None for ii_d in drv] for i, ii_d in enumerate(drv): if len(ii_d) == 2: display('\t...with respect to %s' % ii_d[0]) ao_0 = ao_creator(geo_spec, ao_spec, ao_spherical=ao_spherical, drv=ii_d[0], is_vector=True, x=x, y=y, z=z) if '2' in ii_d or ii_d == 'xx' or ii_d == 'yy' or ii_d == 'zz': delta2_mo_list[i] = mo_creator(ao_0, mo_spec)**2 else: display('\t...with respect to %s' % ii_d[1]) ao_1 = ao_creator(geo_spec, ao_spec, ao_spherical=ao_spherical, drv=ii_d[1], is_vector=True, x=x, y=y, z=z) delta2_mo_list[i] = (mo_creator(ao_0, mo_spec) * mo_creator(ao_1, mo_spec)) delta2_mo_list[i] = convert(delta2_mo_list[i], was_vector, N) display('\nCalculating the atomic and molecular orbitals...') # Calculate the AOs and MOs ao_list = ao_creator(geo_spec, ao_spec, ao_spherical=ao_spherical, is_vector=True, x=x, y=y, z=z) if not calc_ao: mo_list = convert(mo_creator(ao_list, mo_spec), was_vector, N) ao_list = convert(ao_list, was_vector, N) if calc_ao: return ao_list if not was_vector: # Print the norm of the MOs display('\nNorm of the MOs:') for ii_mo in range(len(mo_list)): display( '\t%(m).6f\tMO %(n)s' % { 'm': numpy.sum(mo_list[ii_mo]**2) * d3r, 'n': mo_spec[ii_mo]['sym'] }) if calc_mo: return ((ao_list, mo_list) if return_components else mo_list) # Initialize a numpy array for the density rho = numpy.zeros(N) display('\nCalculating the density...') for ii_mo in range(len(mo_list)): rho += numpy.square(numpy.abs( mo_list[ii_mo])) * mo_spec[ii_mo]['occ_num'] if not was_vector: # Print the number of electrons display('We have ' + str(numpy.sum(rho) * d3r) + ' electrons.') if drv is None: return ((ao_list, mo_list, rho) if return_components else rho) # Print information display('\nCalculating the derivative of the density...') delta_rho = numpy.zeros((len(drv), ) + N) # Loop over spatial directions for i, ii_d in enumerate(drv): display('\t...with respect to %s' % ii_d) # Calculate the derivative of the density for ii_mo in range(len(mo_list)): delta_rho[i] += (mo_spec[ii_mo]['occ_num'] * 2 * delta_mo_list[i, ii_mo] * mo_list[ii_mo]) if len(ii_d) == 2: delta_rho[i] += mo_spec[ii_mo]['occ_num'] * 2 * delta2_mo_list[ i][ii_mo] delta = (delta_rho, delta_rho.sum(axis=0)) if laplacian else (delta_rho, ) return (( ao_list, mo_list, rho, delta_ao_list, delta_mo_list, ) + delta if return_components else (rho, ) + delta)
def ao_creator(geo_spec, ao_spec, ao_spherical=None, drv=None, x=None, y=None, z=None, is_vector=None): '''Calculates all contracted atomic orbitals or its derivatives with respect to a specific variable (e.g. drv = 'x' or drv = 0). **Parameters:** geo_spec,ao_spec : See :ref:`Central Variables` in the manual for details. sel_ao : int Index of the requested atomic orbital drv : int or string, {None, 'x', 'y', 'z', 0, 1, 2}, optional If not None, an analytical calculation of the derivatives for the atomic orbitals with respect to DRV is requested. x,y,z : None or list of floats, optional If not None, provides a list of Cartesian coordinates, else the respective coordinates of grid. will be used is_vector : bool, optional If True, a vector grid will be applied **Returns:** ao_list : numpy.ndarray, shape=((NAO,) + N) Contains the computed NAO atomic orbitals on a grid. ''' # Create the grid if all(v is None for v in [x, y, z, is_vector]) and not grid.is_initialized: display('\nSetting up the grid...') grid.grid_init(is_vector=True) display(grid.get_grid()) # Display the grid if x is None: x = grid.x if y is None: y = grid.y if z is None: z = grid.z if is_vector is None: is_vector = grid.is_vector was_vector = is_vector if not is_vector: N = (len(x), len(y), len(z)) # Convert regular grid to vector grid x, y, z = cy_grid.grid2vector(x.copy(), y.copy(), z.copy()) else: if len(x) != len(y) or len(x) != len(z): raise ValueError("Dimensions of x-, y-, and z- coordinate differ!") N = (len(x), ) x = require(x, dtype='f') y = require(y, dtype='f') z = require(z, dtype='f') geo_spec = require(geo_spec, dtype='f') lxlylz, assign = get_lxlylz(ao_spec, get_assign=True, bincount=True) ao_coeffs, pnum_list, atom_indices = prepare_ao_calc(ao_spec) is_normalized = each_ao_is_normalized(ao_spec) drv = validate_drv(drv) lxlylz = require(lxlylz, dtype='i') assign = require(assign, dtype='i') ao_list = cy_core.aocreator(lxlylz, assign, ao_coeffs, pnum_list, geo_spec, atom_indices, x, y, z, drv, is_normalized) if 'N' in ao_spec[0]: # Renormalize atomic orbital ao_list *= ao_spec[0]['N'] if not (ao_spherical is None or ao_spherical == []): ao_list = cartesian2spherical(ao_list, ao_spec, ao_spherical) if not was_vector: return ao_list.reshape((len(ao_list), ) + N, order='C') return ao_list
def rho_compute(qc, calc_ao=False, calc_mo=False, drv=None, laplacian=False, numproc=1, slice_length=1e4, vector=None, save_hdf5=False, **kwargs): r'''Calculate the density, the molecular orbitals, or the derivatives thereof. orbkit divides 3-dimensional regular grids into 2-dimensional slices and 1-dimensional vector grids into 1-dimensional slices of equal length. By default, 3-dimensional grids are used (:literal:`vector=None`). The computational tasks are distributed to the worker processes. **Parameters:** qc : class or dict QCinfo class or dictionary containing the following attributes/keys. See :ref:`Central Variables` for details. qc.geo_spec : numpy.ndarray, shape=(3,NATOMS) See :ref:`Central Variables` for details. qc.ao_spec : List of dictionaries See :ref:`Central Variables` for details. qc.mo_spec : List of dictionaries See :ref:`Central Variables` for details. calc_mo : bool, optional If True, the computation of the molecular orbitals requested is only carried out. slice_length : int, optional Specifies the number of points per subprocess. drv : string or list of strings {None,'x','y', 'z', 'xx', 'xy', ...}, optional If not None, computes the analytical derivative of the requested quantities with respect to DRV. laplacian : bool, optional If True, computes the laplacian of the density. numproc : int Specifies number of subprocesses for multiprocessing. grid : module or class, global Contains the grid, i.e., grid.x, grid.y, and grid.z. If grid.is_initialized is not True, functions runs grid.grid_init(). **Returns:** :if calc_mo and drv is None: - mo_list :if calc_mo and drv is not None: - delta_mo_list :if not calc_mo and drv is None: - rho :if not calc_mo and drv is not None: - rho, delta_rho :if not calc_mo and laplacian: - rho, delta_rho, laplacian_rho mo_list : numpy.ndarray, shape=((NMO,) + N) Contains the NMO=len(qc.mo_spec) molecular orbitals on a grid. delta_mo_list : numpy.ndarray, shape=((NDRV,NMO) + N) Contains the derivatives with respect to drv (NDRV=len(drv)) of the NMO=len(qc.mo_spec) molecular orbitals on a grid. mo_norm : numpy.ndarray, shape=(NMO,) Contains the numerical norms of the molecular orbitals. rho : numpy.ndarray, shape=(N) Contains the density on a grid. delta_rho : numpy.ndarray, shape=((NDRV,) + N) Contains derivatives with respect to drv (NDRV=len(drv)) of the density on a grid. laplacian_rho : numpy.ndarray, shape=(N) Contains the laplacian of the density on a grid, i.e. :math:`\nabla^2 \rho = \nabla^2_x \rho + \nabla^2_y \rho + \nabla^2_z \rho`. ''' if calc_ao and calc_mo: raise ValueError('Choose either calc_ao=True or calc_mo=True') elif calc_ao: calc_mo = True slice_length = slice_length if not vector else vector if slice_length == 0: return rho_compute_no_slice(qc, calc_ao=calc_ao, calc_mo=calc_mo, drv=drv, laplacian=laplacian, **kwargs) if laplacian: if not (drv is None or drv == ['xx', 'yy', 'zz'] or drv == ['x2', 'y2', 'z2']): display( 'Note: You have set the option `laplacian` and specified values\n' + 'for `drv`. Both options are not compatible.\n' + 'The option `drv` has been changed to `drv=["xx","yy","zz"]`.') drv = ['xx', 'yy', 'zz'] if drv is not None: is_drv = True try: drv = list(drv) except TypeError: drv = [drv] else: is_drv = False # Specify the global variable containing all desired information needed # by the function slice_rho if isinstance(qc, dict): Spec = qc else: Spec = qc.todict() Spec['calc_ao'] = calc_ao Spec['calc_mo'] = calc_mo Spec['Derivative'] = drv if calc_ao: if Spec['ao_spherical'] is None: lxlylz, assign = get_lxlylz(Spec['ao_spec'], get_assign=True) labels = [ 'lxlylz=%s,atom=%d' % (lxlylz[i], Spec['ao_spec'][assign[i]]['atom']) for i in range(len(lxlylz)) ] mo_num = len(lxlylz) else: mo_num = len(Spec['ao_spherical']) labels = [ 'l,m=%s,atom=%d' % (j, Spec['ao_spec'][i]['atom']) for i, j in Spec['ao_spherical'] ] else: mo_num = len(Spec['mo_spec']) labels = [ii_mo['sym'] for ii_mo in Spec['mo_spec']] if not grid.is_initialized: display('\nSetting up the grid...') grid.grid_init(is_vector=True) display(grid.get_grid()) # Display the grid was_vector = grid.is_vector N = (len(grid.x), ) if was_vector else (len(grid.x), len(grid.y), len(grid.z)) if not was_vector: grid.grid2vector() display('Converting the regular grid to a vector grid containing ' + '%.2e grid points...' % len(grid.x)) # Define the slice length npts = len(grid.x) if slice_length < 0: slice_length = numpy.ceil(npts / float(numproc)) + 1 sNum = int(numpy.floor(npts / slice_length) + 1) # The number of worker processes is capped to the number of # grid points in x-direction. if numproc > sNum: numproc = sNum # Print information regarding the density calculation display('\nStarting the calculation of the %s...' % ('molecular orbitals' if calc_mo else 'density')) display( 'The grid has been separated into %d slices each having %.2e grid points.' % (sNum, slice_length)) if numproc <= 1: display( 'The calculation will be carried out using only one process.\n' + '\n\tThe number of subprocesses can be changed with -p\n') else: display('The calculation will be carried out with %d subprocesses.' % numproc) display('\nThere are %d contracted %s AOs' % (len(Spec['mo_spec'][0]['coeffs']), 'Cartesian' if not Spec['ao_spherical'] else 'spherical') + ('' if calc_ao else ' and %d MOs to be calculated.' % mo_num)) # Initialize some additional user information status_old = 0 s_old = 0 t = [time.time()] # Make slices # Initialize an array to store the results mo_norm = numpy.zeros((mo_num, )) def zeros(shape, name, save_hdf5): if not save_hdf5: return numpy.zeros(shape) else: return f.create_dataset(name, shape, dtype=numpy.float64, chunks=shape[:-1] + (slice_length, )) def reshape(data, shape): if not save_hdf5: return data.reshape(shape) else: data.attrs['shape'] = shape return data[...].reshape(shape) if save_hdf5: import h5py f = h5py.File(str(save_hdf5), 'w') f['x'] = grid.x f['y'] = grid.y f['z'] = grid.z if calc_mo: mo_list = zeros((mo_num, npts) if drv is None else (len(drv), mo_num, npts), 'ao_list' if calc_ao else 'mo_list', save_hdf5) else: rho = zeros(npts, 'rho', save_hdf5) if is_drv: delta_rho = zeros((len(drv), npts), 'rho', save_hdf5) # Write the slices in x to an array xx xx = [] i = 0 for s in range(sNum): if i == npts: sNum -= 1 break elif (i + slice_length) >= npts: xx.append((numpy.array([i, npts], dtype=int))) else: xx.append((numpy.array([i, i + slice_length], dtype=int))) i += slice_length # Start the worker processes if numproc > 1: pool = Pool(processes=numproc, initializer=initializer, initargs=(Spec, )) it = pool.imap(slice_rho, xx) else: initializer(Spec) # Compute the density slice by slice for s in range(sNum): # Which slice do we compute i = xx[s][0] j = xx[s][1] # Perform the compution for the current slice result = it.next() if numproc > 1 else slice_rho(xx[s]) # What output do we expect if calc_mo: if not is_drv: mo_list[:, i:j] = result[:, :] else: for ii_d in range(len(drv)): mo_list[ii_d, :, i:j] = result[ii_d, :, :, ] else: rho[i:j] = result[0] mo_norm += result[1] if is_drv: for ii_d in range(len(drv)): delta_rho[ii_d, i:j] = result[2][ii_d, :] # Print out the progress of the computation status = numpy.floor(s * 10 / float(sNum)) * 10 if not status % 10 and status != status_old: t.append(time.time()) display('\tFinished %(f)d %% (%(s)d slices in %(t).3f s)' % { 'f': status, 's': s + 1 - s_old, 't': t[-1] - t[-2] }) status_old = status s_old = s + 1 # Close the worker processes if numproc > 1: pool.close() pool.join() if not was_vector: grid.vector2grid(*N) display( 'Converting the output from a vector grid to a regular grid...') if not was_vector and drv is None: # Print the norm of the MOs display('\nNorm of the MOs:') for ii_mo in range(len(mo_norm)): if calc_mo: norm = numpy.sum(numpy.square(mo_list[ii_mo])) * grid.d3r else: norm = mo_norm[ii_mo] * grid.d3r display('\t%(m).6f\t%(t)s %(n)s' % { 'm': norm, 'n': labels[ii_mo], 't': 'AO' if calc_ao else 'MO' }) if calc_mo: #if not was_vector: mo_list = reshape(mo_list, ((mo_num, ) if drv is None else ( len(drv), mo_num, )) + N) if save_hdf5: f.close() return mo_list if not was_vector: # Print the number of electrons display('We have ' + str(numpy.sum(rho) * grid.d3r) + ' electrons.') #if not was_vector: rho = reshape(rho, N) if not is_drv: if save_hdf5: f.close() return rho else: #if not was_vector: delta_rho = reshape(delta_rho, (len(drv), ) + N) if save_hdf5: f.close() if laplacian: return rho, delta_rho, delta_rho.sum(axis=0) return rho, delta_rho
from orbkit import read, grid, display, core, output ''' Identify the non-covalent interaction regions using the reduced density gradient ''' # open molden file and read parameters qc = read.main_read('h2o_dimer.molden',itype='molden') # Adjust the grid parameters to the molecular structure grid.adjust_to_geo(qc,extend=1.0,step=0.1) # initialize grid grid.grid_init() # print grid information display.display(grid.get_grid()) # Run orbkit rho,delta_rho = core.rho_compute(qc,drv=['x','y','z'],numproc=4) # Compute the reduced density gradient from numpy import sqrt,pi s = (1./(2*(3*pi**2)**(1/3.)) * sqrt((delta_rho**2).sum(axis=0))/(rho**(4/3.))) # Apply a density cutoff, i.e., consider only values for rho < 0.05 a.u. s[rho>0.05] = 1e3 # Write a cube file and vmd script for the reduced density gradient output.main_output(s, qc.geo_info, # atomic information qc.geo_spec, # atomic coordinates
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 if 'native' in options.otype: output.main_output(qc, outputname=options.outputname, otype='native', ftype=options.niotype) options.otype.remove('native') if not len(options.otype): t.append(time.time()) # Final time good_bye_message(t) return 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: rho_atom = extras.gross_atomic_density(options.gross_atomic_density,qc, drv=options.drv) if not options.no_output: output_written = output.main_output(rho_atom, qc, outputname=options.outputname, otype=options.otype) t.append(time.time()) good_bye_message(t) return rho_atom 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 t.append(time.time()) # A new time step # Generate the output requested if not options.no_output: if not (options.drv is not None or options.laplacian): plt_data = rho datalabels = 'rho' else: 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,outputname=options.outputname, otype=options.otype,datalabels=datalabels) t.append(time.time()) # Final time good_bye_message(t) # 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