Esempio n. 1
0
 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)
Esempio n. 2
0
    def orbkit_grid(self, qc):

        # Initialize grid
        grid.adjust_to_geo(qc, extend=5.0, step=0.4)
        grid.grid_init(force=True)
        self.slice_length = grid.N_[1] * grid.N_[2] / 2
Esempio n. 3
0
fid_molden = fid_psi4 + '.default.molden'
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,
Esempio n. 4
0
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
Esempio n. 5
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)
Esempio n. 6
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
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
from orbkit import read
from orbkit.core import rho_compute
from orbkit.test.tools import equal
from orbkit import grid
from orbkit import options

options.quiet = True

tests_home = os.path.dirname(inspect.getfile(inspect.currentframe()))
folder = os.path.join(tests_home, '../outputs_for_testing/molpro')
filepath = os.path.join(folder, 'h2o_rhf_sph.molden')
qc = read.main_read(filepath, all_mo=True)

grid.adjust_to_geo(qc, extend=2.0, step=1)
grid.grid_init(is_vector=False, force=True)

drv = [None, 'x', 'y', 'z', 'xx', 'xy', 'xz', 'yy', 'yz', 'zz']
data = []
for i in range(2):
    if i: grid.grid2vector()
    data.append([
        rho_compute(qc, slice_length=0),
        rho_compute(qc, numproc=options.numproc),
        rho_compute(qc, laplacian=True, slice_length=0)[-1],
        rho_compute(qc, laplacian=True, numproc=options.numproc)[-1],
        rho_compute(qc, calc_mo=True, drv=drv, slice_length=0),
        rho_compute(qc, calc_mo=True, drv=drv, numproc=options.numproc)
    ])

data[1] = [grid.mv2g(d=i) for i in data[1]]