def grid2vector(): '''Converts the regular grid characterized by x-, y-, z-vectors to a (3, (Nx*Ny*Nz)) grid matrix (vector grid). Reverse operation: :mod:`orbkit.grid.vector2grid` ''' # All grid related variables should be globals global x, y, z, is_vector, is_regular if not is_initialized: raise ValueError('You have to initialize a grid before calling '+ ' `grid.grid2vector`, i.e., `grid.is_initialized=True`.') x,y,z = cy_grid.grid2vector(x,y,z) is_vector = True is_regular = True
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