Beispiel #1
0
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
Beispiel #2
0
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)
Beispiel #3
0
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