コード例 #1
0
ファイル: atomic_populations.py プロジェクト: wangvei/orbkit
def lowdin(qc):
    '''Calculates the Lowdin populations and charges for each atom
      in the system.

  **Parameters:**
   
    qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec :
      See :ref:`Central Variables` for details.
    
  **Returns:**
    lowdin_pop : dict 
      Contains information of Lowdin charge analysis and has following members:
        :population: - Lowdin population for each atom.
        :charges: - Lowdin charges for each atom.
      
  '''
    # Calculate AO-overlap matrix
    S = get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec)

    # Get MO-coefficients
    mo = qc.mo_spec.get_coeffs()
    mo_dim, ao_dim = mo.shape

    # Orthogonalize basis set
    s_eval, S_evec = numpy.linalg.eigh(S)
    S_eval = numpy.eye(len(s_eval)) * s_eval**(0.5)
    S12 = numpy.dot(S_evec, numpy.dot(S_eval, S_evec.T))

    # Calculate density matrix
    P = numpy.zeros((ao_dim, ao_dim))
    P_i = numpy.zeros((mo_dim, ao_dim, ao_dim))
    for i, m, n in itertools.product(range(mo_dim), range(ao_dim),
                                     range(ao_dim)):
        P_i[i, m, n] = mo[i, m] * mo[i, n]
        k = qc.mo_spec[i]
        if k['occ_num'] > 0:
            P[m, n] += k['occ_num'] * P_i[i, m, n]

    # Calculate Lowdin population
    PS = 0
    for m in itertools.product(range(ao_dim)):
        PS += (P[:, m] * S12[m, :])

    N = 0
    for m in itertools.product(range(ao_dim)):
        N += (S12[:, m] * PS[m, :])

    GP = N.diagonal()
    atom2mo = get_atom2mo(qc)

    GP_A = numpy.zeros(len(qc.geo_spec))
    for a in range(len(qc.geo_spec)):
        GP_A[a] = GP[get_lc(a, atom2mo)].sum()

    lowdin = {
        'population': GP_A,
        'charge': numpy.array(qc.geo_info[:, 2], dtype=float) - GP_A
    }

    return lowdin
コード例 #2
0
 def get_overlap_matrix(self):
     self.ao_overlap_matrix = ai.get_ao_overlap(
         self.qc.geo_spec,
         self.qc.geo_spec,
         self.qc.ao_spec,
         ao_spherical=self.qc.ao_spherical)
     return self.ao_overlap_matrix
コード例 #3
0
def mulliken(qc):
    '''Calculates the Mulliken populations (gross atomic populations) and Mulliken
  charges for each atom in the system.

  **Parameters:**
   
    qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec :
      See :ref:`Central Variables` for details.
    
  **Returns:**
    mulliken_pop : dict 
      Contains information of Mulliken charge analysis and has following members:
        :population: - Mulliken population for each atom.
        :charges: - Mulliken charges for each atom.
      
  '''
    # Calculate AO-overlap matrix

    S = get_ao_overlap(qc.geo_spec,
                       qc.geo_spec,
                       qc.ao_spec,
                       ao_spherical=qc.ao_spherical)

    # Get MO-coefficients
    mo = create_mo_coeff(qc.mo_spec)
    mo_dim, ao_dim = mo.shape

    # Calculate density matrix
    P = numpy.zeros((ao_dim, ao_dim))
    P_i = numpy.zeros((mo_dim, ao_dim, ao_dim))
    for i, m, n in itertools.product(range(mo_dim), range(ao_dim),
                                     range(ao_dim)):
        P_i[i, m, n] = mo[i, m] * mo[i, n]
        k = qc.mo_spec[i]
        if k['occ_num'] > 0:
            P[m, n] += k['occ_num'] * P_i[i, m, n]

    # Calculate Mulliken population
    N = 0
    for m in itertools.product(range(ao_dim)):
        N += (P[:, m] * S[m, :])

    GP = N.diagonal()
    atom2mo = get_atom2mo(qc)
    GP_A = numpy.zeros(len(qc.geo_spec))
    for a in range(len(qc.geo_spec)):
        GP_A[a] = GP[get_lc(a, atom2mo)].sum()

    # Save Mulliken population and charges to dictionary
    mulliken_pop = {
        'population': GP_A,
        'charge': numpy.array(qc.geo_info[:, 2], dtype=float) - GP_A
    }

    return mulliken_pop
コード例 #4
0
ファイル: tools.py プロジェクト: marsoner/orbkit
def check_mo_norm(qc):
    geo_spec = qc.geo_spec
    ao_spec = qc.ao_spec
    ao_spherical = qc.ao_spherical

    aoom = analytical_integrals.get_ao_overlap(geo_spec, geo_spec, ao_spec,
                                               ao_spherical)
    moom = analytical_integrals.get_mo_overlap_matrix(mo_spec,
                                                      mo_spec,
                                                      aoom,
                                                      numproc=options.numproc)

    deviation = numpy.linalg.norm(moom - numpy.eye(len(moom)))
    return deviation
コード例 #5
0
ファイル: atomic_populations.py プロジェクト: wangvei/orbkit
def mulliken(qc):
    '''Calculates the Mulliken populations (gross atomic populations) and Mulliken
  charges for each atom in the system.

  **Parameters:**
   
    qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec :
      See :ref:`Central Variables` for details.
    
  **Returns:**
    mulliken_pop : dict 
      Contains information of Mulliken charge analysis and has following members:
        :population: - Mulliken population for each atom.
        :charges: - Mulliken charges for each atom.
      
  '''

    # Calculate AO-overlap matrix
    S = get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec)

    # Get MO-coefficients
    mo = qc.mo_spec.get_coeffs()
    modim = mo.shape[0]

    # Calculate population matrix
    atom2mo = get_atom2mo(qc)
    mull_pop = numpy.zeros(len(qc.geo_spec))
    for i in range(len(qc.geo_spec)):
        for j in range(modim):
            k = qc.mo_spec[j]
            if k['occ_num'] > 0:
                for l in get_lc(i, atom2mo):
                    mull_pop[i] += numpy.sum(k['occ_num'] * mo[j, l] *
                                             mo[j, :] * S[l, :])

    # Save Mulliken population and charges to dictionary
    mulliken = {
        'population': mull_pop,
        'charge': numpy.array(qc.geo_info[:, 2], dtype=float) - mull_pop
    }

    return mulliken
コード例 #6
0
ファイル: multiple_files.py プロジェクト: felixplasser/orbkit
def order_using_analytical_overlap(fid_list,
                                   itype='molden',
                                   deg=0,
                                   numproc=1,
                                   **kwargs):
    '''Performs an ordering routine using analytical overlap integrals between 
  molecular orbitals. Set fid_list to None to omit the reading of input files.
  
  If :literal:`deg` is set to a value larger than zero, the molecular orbital 
  coefficients are extrapolated with a polynomial of degree :literal:`deg`,
  before computing the molecular orbital overlap matrix.
  
  **Paramerters:**
  
  fid_list : list of str or None
    If not None, it contains the list of input file names.
  itype : str, choices={'molden', 'gamess', 'gaussian.log', 'gaussian.fchk'}
    Specifies the type of the input files.
  deg : int, optional
    If greater than zero, specifies the degree of the extrapolation polynomial
    for the molecular orbital coefficients.  
  
  **Returns:**
  
  index_list : numpy.ndarray, shape=(Nfiles,NMO)
    Contains the new indices of the molecular orbitals. If index < 0, the 
    molecular orbital changes its sign.
  mo_overlap : numpy.ndarray, shape=((Nfiles - 1),NMO,NMO)
    Contains the overlap matrix between the molecular orbitals of two neighboring
    geometries, i.e., mo_overlap[i,j,k] corresponds to overlap between the 
    jth molecular orbital at geometry i to the kth molecular orbital at 
    geometry (i+1).
  
  **Global Variables:**
  
  geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list
  '''
    global geo_spec_all, geo_info, ao_spec, ao_spherical, mo_coeff_all, mo_energy_all, mo_occ_all, sym, index_list

    if fid_list is not None:
        read(fid_list, itype=itype, **kwargs)

    display(
        '\nStarting the ordering routine using the molecular orbital overlap...'
    )

    iterate = list(range(1, len(geo_spec_all)))

    if deg > 0:
        display('\tThe molecular orbital coefficients will be extrapolated')
        display('\tusing a least squares polynomial fit of degree %d.' % deg)
        std = numpy.array(
            [numpy.std(i - geo_spec_all[0]) for i in geo_spec_all])

    mo_overlap = [[] for i in sym.keys()]
    index_list = [[] for i in sym.keys()]

    for s in sym.values():
        shape = numpy.shape(mo_coeff_all[s])
        index_list[s] = numpy.ones((shape[0], shape[1]), dtype=int)
        index_list[s] *= numpy.arange(shape[1], dtype=int)

    c = 0
    t = time()
    for rr in iterate:
        r1 = rr - 1
        r2 = rr

        if (deg is None) or (deg > 0 and r1 >= deg):
            ao_overlap = get_ao_overlap(geo_spec_all[r2],
                                        geo_spec_all[r2],
                                        ao_spec,
                                        ao_spherical=ao_spherical)
        else:
            ao_overlap = get_ao_overlap(geo_spec_all[r1],
                                        geo_spec_all[r2],
                                        ao_spec,
                                        ao_spherical=ao_spherical)

        cs = 0
        for s in sym.values():
            mo_coeff = mo_coeff_all[s]
            shape = numpy.shape(mo_coeff)
            if deg is not None and deg > 0 and r1 >= deg:
                mo_r1 = get_extrapolation(r1,
                                          r2,
                                          mo_coeff,
                                          grid1d=std,
                                          deg=deg)
            else:
                mo_r1 = mo_coeff[r1]
            overlap = get_mo_overlap_matrix(mo_r1,
                                            mo_coeff[r2],
                                            ao_overlap,
                                            numproc=numproc)
            for i in range(shape[1]):
                # Iterate the rows of the overlap matrix
                line_max = None  # variable for maximum value in the current row
                line_sort = numpy.argsort(numpy.abs(
                    overlap[i, :]))[::-1]  # sort the row
                for k in line_sort[::-1]:
                    # Is this value the maximum in the current column?
                    col_max = numpy.argmax(numpy.abs(overlap[:, k]))
                    if i == col_max:
                        line_max = k
                        break
                if line_max is not None:
                    # Interchange the coefficients
                    mo_coeff[r2, [i, line_max], :] = mo_coeff[r2,
                                                              [line_max, i], :]
                    overlap[:, [i, line_max]] = overlap[:, [line_max, i]]
                    index_list[s][r2,
                                  [i, line_max]] = index_list[s][r2,
                                                                 [line_max, i]]

            for i in range(shape[1]):
                # Change the signs
                mo_coeff[r2, i, :] *= numpy.sign(overlap[i, i])
                overlap[:, i] *= numpy.sign(overlap[i, i])
                index_list[s][r2, i] *= numpy.sign(overlap[i, i])

            mo_overlap[cs].append(overlap)
            cs += 1

            mo_coeff_all[s] = mo_coeff

            index = numpy.abs(index_list[s])[r2, :]
            mo_energy_all[s][r2, :] = mo_energy_all[s][r2, index]
            mo_occ_all[s][r2, :] = mo_occ_all[s][r2, index]

        c += 1
        #if not c % int(numpy.ceil(len(iterate)/10.)):
        display('\tFinished %d of %d geometries (%.1f s)' %
                (c, len(iterate), time() - t))
        t = time()

    tmp = []
    for i in mo_overlap:
        tmp.append(numpy.array(i))

    mo_overlap = tmp

    return index_list, mo_overlap
コード例 #7
0
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,
                      ao_spherical=qc.ao_spherical,
                      drv=[None, 'x', 'y', 'z'])
dm_aoom = get_ao_dipole_matrix(qc, component=['x', 'y', 'z'])

moom = get_mo_overlap_matrix(qc.mo_spec, qc.mo_spec, aoom[0],
                             numproc=numproc)  # <m|n>
omr = numpy.zeros((3, ) + moom.shape)  # <m|r|n>
omv = numpy.zeros((3, ) + moom.shape)  # <m|\nabla|n>
for i in range(3):
    omr[i] = get_mo_overlap_matrix(qc.mo_spec,
                                   qc.mo_spec,
                                   dm_aoom[i],
                                   numproc=numproc)
    omv[i] = get_mo_overlap_matrix(qc.mo_spec,
                                   qc.mo_spec,
コード例 #8
0
ファイル: lih_example.py プロジェクト: wangvei/orbkit
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,
                      drv=[None,'x','y','z'])
dm_aoom = get_ao_dipole_matrix(qc,component=['x','y','z'])

moom = get_mo_overlap_matrix(qc.mo_spec,qc.mo_spec,aoom[0],
                             numproc=numproc)          # <m|n>
omr = numpy.zeros((3,) + moom.shape)                   # <m|r|n>
omv = numpy.zeros((3,) + moom.shape)                   # <m|\nabla|n>
for i in range(3):
  omr[i] = get_mo_overlap_matrix(qc.mo_spec,qc.mo_spec,dm_aoom[i],numproc=numproc)
  omv[i] = get_mo_overlap_matrix(qc.mo_spec,qc.mo_spec,aoom[i+1],numproc=numproc)

print('''
==========================================
  Starting the detCI@ORBKIT Computations
==========================================
''')
コード例 #9
0
    <\phi_k|z|\phi_l> = \int dxdydz (z - Z_k)^{k_z} e^{\alpha_k r_k^2} (z - Z_l)^{l_z+1} e^{\alpha_l r_l^2} 
                        + Z_l \int dxdydz (z - Z_k)^{k_z} e^{\alpha_k r_k^2} (z - Z_l)^{l_z} e^{\alpha_l r_l^2} 
                      = ao_part_1 + ao_part_2

with :math:`r_l = \sqrt{(x-X_l)^2 + (y-Y_l)^2 + (z - Z_l)^2)}`
'''
from orbkit.read import main_read
from orbkit.tools import *
from orbkit.analytical_integrals import get_ao_overlap, get_mo_overlap, print2D

in_fid = 'h2o.molden'
# Read the input file
qc = main_read(in_fid, itype='molden', all_mo=False)

# Compute atomic orbital overlap matrix
ao_overlap_matrix = get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec)

# Compute the overlap of the molecular orbitals and weight it with the occupation number
electron_number = 0.
for i_mo in qc.mo_spec:
    electron_number += i_mo['occ_num'] * get_mo_overlap(
        i_mo['coeffs'], i_mo['coeffs'], ao_overlap_matrix)

print('The total number of electrons is %.8f' % electron_number)
# Compute the x-, y-, and z-component of the dipole moment
dipole_moment = []
for component in range(3):

    # Compute the first part of the expectation value:
    # Get the the exponents lx, ly, lz for the primitive Cartesian Gaussians of
    # the `Ket` basis set, and increase lz by one.
コード例 #10
0
                        + Z_l \int dxdydz (z - Z_k)^{k_z} e^{\alpha_k r_k^2} (z - Z_l)^{l_z} e^{\alpha_l r_l^2} 
                      = ao_part_1 + ao_part_2

with :math:`r_l = \sqrt{(x-X_l)^2 + (y-Y_l)^2 + (z - Z_l)^2)}`
'''
from orbkit.read import main_read
from orbkit.core import get_lxlylz, l_deg
from orbkit.analytical_integrals import get_ao_overlap, get_mo_overlap, print2D

in_fid = 'h2o.molden'
# Read the input file
qc = main_read(in_fid, itype='molden', all_mo=False)

# Compute atomic orbital overlap matrix
ao_overlap_matrix = get_ao_overlap(qc.geo_spec,
                                   qc.geo_spec,
                                   qc.ao_spec,
                                   ao_spherical=qc.ao_spherical)

# Compute the overlap of the molecular orbitals and weight it with the occupation number
electron_number = 0.
for i_mo in qc.mo_spec:
    electron_number += i_mo['occ_num'] * get_mo_overlap(
        i_mo['coeffs'], i_mo['coeffs'], ao_overlap_matrix)

print('The total number of electrons is %.8f' % electron_number)
# Compute the x-, y-, and z-component of the dipole moment
dipole_moment = []
for component in range(3):

    # Compute the first part of the expectation value:
    # Get the the exponents lx, ly, lz for the primitive Cartesian Gaussians of
コード例 #11
0
save_data_values = False  #: Saves the grid and output values computed. This requires more RAM and time.

# create_plot needs the data values
if create_plot and not save_data_values:
    save_data_values = True

numproc = 4  #: Specifies number of subprocesses.
slice_length = 1e4  #: Specifies number of points per subprocess.

in_fid = 'h2o.molden'  #: Specifies input file name.

# Open molden file and read parameters
qc = read.main_read(in_fid, itype='molden', all_mo=False)

# Compute atomic orbital overlap matrix
ao_overlap_matrix = get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec)

# Compute the overlap of the molecular orbitals and weight it with the occupation number
analytical_integral = 0.
for i_mo in qc.mo_spec:
    analytical_integral += i_mo['occ_num'] * get_mo_overlap(
        i_mo['coeffs'], i_mo['coeffs'], ao_overlap_matrix)

print('Analytical Integral: %.12f' % analytical_integral)

# Disable orbkit terminal output for each run
options.quiet = True
options.no_log = True

# Initialize some variables
t = [time()]
コード例 #12
0
ファイル: molden.py プロジェクト: jkn93/orbkit
def read_molden(fname,
                all_mo=False,
                spin=None,
                i_md=-1,
                interactive=True,
                **kwargs):
    '''Reads all information desired from a molden file.

  **Parameters:**

    fname : str, file descriptor
      Specifies the filename for the input file.
      fname can also be used with a file descriptor instad of a filename.
    all_mo : bool, optional
      If True, all molecular orbitals are returned.
    spin : {None, 'alpha', or 'beta'}, optional
      If not None, returns exclusively 'alpha' or 'beta' molecular orbitals.
    i_md : int, default=-1
      Selects the `[Molden Format]` section of the output file.
    interactive : bool
      If True, the user is asked to select the different sets.

  **Returns:**

    qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot :
        See :ref:`Central Variables` for details.
  '''

    if 'index' not in kwargs.keys():
        kwargs['index'] = 0

    if isinstance(fname, str):
        fd = descriptor_from_file(fname, index=kwargs['index'])
    else:
        fd = fname
        fname = fd.name

    ### read the whole file into RAM
    # TODO: optimize for large files

    molden = fd.read()
    if isinstance(molden, bytes):
        molden = molden.decode()

    ### find number of [Molden Format] entries and figure our which one to use
    entries = [m.start() for m in regex_molden.finditer(molden)]
    count = len(entries)

    if count == 0:
        raise IOError('The input file {:s} is no valid molden file!\n\nIt does'
                      .format(fname) +
                      ' not contain the keyword: [Molden Format]\n')

    if count > 1:
        display('\nContent of the molden file:')
        display('\tFound {:d} [Molden Format] keywords, i.e., '.format(count) +
                'this file contains {:d} molden files.'.format(count))

        if interactive:
            message = '\tPlease give an integer from 0 to {0}: '.format(count -
                                                                        1)
            from builtins import input  # Python2 compatibility

            while 1:
                try:
                    i_md = int(input(message))
                except ValueError:
                    print('An Integer is required!')
                else:
                    if i_md >= count or i_md < -count:
                        # invalid index
                        continue
                    break

        i_md = list(range(count))[i_md]

        # log selected index
        display('\tSelecting the element with index {:d}.'.format(i_md))

        # select molden entry
        start = entries[i_md]
        end = (entries + [None])[i_md + 1]
        molden = molden[start:end]

    molden = molden.splitlines()

    ### parse [Atoms] and [GTO] section
    qc = QCinfo()
    has_alpha = False
    has_beta = False
    restricted = False
    spherical_basis = []  # found flags for spherical basis
    cartesian_basis = []  # found flags for cartesian basis
    angular = []  # angular momentum actually used
    by_orca = False

    for iline, line in enumerate(molden):

        if 'orca' in line.lower():
            by_orca = True
            continue

        if '_ENERGY=' in line:
            try:
                qc.etot = float(line.split()[1])
            except IndexError:
                pass
            continue

        # [Atoms] section (geo_info)
        m = regex_atoms.match(line)
        if m:
            angstrom = 'angs' == m.group(1).lower()
            continue

        m = regex_atom.match(line)
        if m:
            qc.geo_info.append(list(m.groups()[:3]))
            qc.geo_spec.append([float(f) for f in m.groups()[3:]])
            continue

        # [GTO] section (ao_info)
        if '[sto]' in line.lower():
            # orbkit does not support Slater type orbitals
            raise IOError('orbkit does not work for STOs!\nEXIT\n')

        m = regex_basis.match(line)
        if m:
            at_num = int(m.group(1)) - 1
            #ao_num = 0
            continue

        # check spherical/cartesian flags
        m = regex_flagline.match(line.lower())
        if m:
            # get list of all flags in line
            flags = regex_flag.findall(m.group(1))
            # check whether cartesian or spherical
            for flag in flags:
                if flag in FLAGS_SPH:
                    spherical_basis.append(flag)
                if flag in FLAGS_CART:
                    cartesian_basis.append(flag)

        m = regex_contraction.match(line)
        if m:
            ao_num = 0  # Initialize number of atomic orbitals
            ao_type = m.group(1).lower()  # angular momentum
            pnum = int(m.group(2))  # Number of primatives

            for l in ao_type:
                qc.ao_spec.append({
                    'atom': at_num,
                    'type': l,
                    'pnum': -pnum if by_orca else pnum,
                    'coeffs': numpy.zeros((pnum, 2))
                })
                if not l in angular:
                    angular.append(l)
            continue

        m = regex_primitive.match(line)
        if m:
            # split line as regex only captures the first two floats, and there may be more
            coeffs = numpy.array(line.lower().replace('d', 'e').split(),
                                 dtype=numpy.float64)
            for i_ao in range(len(ao_type)):
                qc.ao_spec[-len(ao_type) + i_ao]['coeffs'][ao_num, :] = [
                    coeffs[0], coeffs[1 + i_ao]
                ]
            ao_num += 1
            continue

        if '[mo]' in line.lower():
            break

    ### checks for cartesion/spherical basis

    # check for mixed spherical/cartesian basis functions
    max_l = max(lquant[l] for l in angular)
    if max_l >= 2:
        # remove flags for unused angular momentum
        l = orbit[2:max_l + 1]
        sph = [f for f in spherical_basis if f[-1] in l]
        cart = [f for f in cartesian_basis if f[-1] in l]
        if sph and cart:
            raise IOError(
                '''The input file {} contains mixed spherical and Cartesian function ({}).
                  ORBKIT does not support these basis functions yet.
                  Pleas contact us, if you need this feature!'''.format(
                    fname, ', '.join(sph + cart)))

        # check for ambiguous spherical/cartesian flags
        sph = [l[-1] for l in sph]
        cart = [l[-1] for l in cart]
        if set(sph) & set(cart):
            raise IOError(
                'The input file {} contains ambiguous flags for spherical and cartesian basis functions: {}'
                .format(fname, ', '.join(spherical_basis + cartesian_basis)))

        cartesian = not bool(sph)

    else:
        cartesian = True  # does not matter for s and p orbitals

    # count number of basis functions
    basis_count = 0
    for AO in qc.ao_spec:
        l = AO['type']
        # TODO: check for mixed sph/cart basis
        basis_count += l_deg(lquant[l], cartesian_basis=cartesian)

    ### parse [MO] section (mo_info)
    newMO = False
    MO_sym = None
    MO_spin = None
    MO_energy = None
    MO_occ = None
    sym = defaultdict(int)  # counter for MOs per IRREP

    for line in molden[iline:]:

        m = regex_coeff.match(line)
        if m:

            if newMO:

                # infer incomplete data
                MO_spin = MO_spin or 'alpha'
                m2 = re.search(r'\d+', MO_sym)
                if m2:
                    a = m2.group()
                    if MO_sym == a:
                        MO_sym = '{:s}.1'.format(a)
                    elif MO_sym.startswith(a):
                        MO_sym.replace(a, '{:s}.'.format(a), 1)
                    else:
                        sym[a] += 1
                        MO_sym = '{:d}.{:s}'.format(sym[a], MO_sym)
                MO_sym = MO_sym or '%d.1' % (len(qc.mo_spec) + 1)

                # create a new MO entry
                qc.mo_spec.append({
                    'coeffs': numpy.zeros(basis_count),
                    'sym': MO_sym,
                    'energy': MO_energy,
                    'occ_num': MO_occ,
                    'spin': MO_spin,
                })

                # reset variables
                newMO = False
                MO_sym = None
                MO_spin = None
                MO_energy = None
                MO_occ = None

            # parse and store current coefficient
            iMO = int(m.group(1)) - 1
            coeff = float(m.group(2))
            if numpy.isnan(coeff):
                display(
                    'Warning: coefficient {:d} of MO {:s} is NaN! Using zero instead'
                    .format(iMO, qc.mo_spec[-1]['sym']))
            else:
                qc.mo_spec[-1]['coeffs'][iMO] = coeff
            continue

        newMO = True
        m = regex_sym.match(line)
        if m:
            MO_sym = m.group(1)
            continue

        m = regex_energy.match(line)
        if m:
            MO_energy = m.group(1)
            continue

        m = regex_spin.match(line)
        if m:
            MO_spin = m.group(1).lower()
            has_alpha = has_alpha or MO_spin == 'alpha'
            has_beta = has_beta or MO_spin == 'beta'
            continue

        m = regex_occu.match(line)
        if m:
            MO_occ = float(m.group(1))
            restricted = restricted or (MO_occ > 1.0001)
            continue

    ### post checks and clean up

    if spin is not None:
        if restricted:
            raise IOError(
                'The keyword `spin` is only supported for unrestricted calculations.'
            )
        if spin != 'alpha' and spin != 'beta':
            raise IOError('`spin=%s` is not a valid option' % spin)
        elif spin == 'alpha' and has_alpha:
            display('Reading only molecular orbitals of spin alpha.')
        elif spin == 'beta' and has_beta:
            display('Reading only molecular orbitals of spin beta.')
        elif (not has_alpha) and (not has_beta):
            raise IOError(
                'Molecular orbitals in `molden` file do not contain `Spin=` keyword'
            )
        elif ((spin == 'alpha' and not has_alpha)
              or (spin == 'beta' and not has_beta)):
            raise IOError(
                'You requested `%s` orbitals, but None of them are present.' %
                spin)

    # Spherical basis?
    if spherical_basis:
        qc.ao_spec.set_lm_dict(p=[1, 0])

    # Are all MOs requested for the calculation?
    if not all_mo:
        for i in range(len(qc.mo_spec))[::-1]:
            if qc.mo_spec[i]['occ_num'] < 0.0000001:
                del qc.mo_spec[i]

    # Only molecular orbitals of one spin requested?
    if spin is not None:
        for i in range(len(qc.mo_spec))[::-1]:
            if qc.mo_spec[i]['spin'] != spin:
                del qc.mo_spec[i]

    if restricted:
        # Closed shell calculation
        for mo in qc.mo_spec:
            del mo['spin']
    else:
        # Rename MOs according to spin
        for mo in qc.mo_spec:
            mo['sym'] += '_%s' % mo['spin'][0]

    # Orca uses for all molecular orbitals the same name
    sym = [i['sym'] for i in qc.mo_spec]
    if sym[1:] == sym[:-1]:
        sym = sym[0].split('.')[-1]
        for i in range(len(qc.mo_spec)):
            qc.mo_spec[i]['sym'] = '%d.%s' % (i + 1, sym)

    # Convert geo_info and geo_spec to numpy.ndarrays
    qc.format_geo(is_angstrom=angstrom)

    # Check the normalization
    from orbkit.analytical_integrals import get_ao_overlap
    spher_tmp = qc.ao_spec.spherical
    qc.ao_spec.spherical = False
    norm = numpy.diagonal(get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec))
    qc.ao_spec.spherical = spher_tmp
    if max(numpy.abs(norm - 1.)) > 1e-5:
        display(
            'The atomic orbitals are not normalized correctly, renormalizing...\n'
        )
        if not by_orca:
            j = 0
            for i in range(len(qc.ao_spec)):
                qc.ao_spec[i]['coeffs'][:, 1] /= numpy.sqrt(norm[j])
                for n in range(
                        l_deg(lquant[qc.ao_spec[i]['type']],
                              cartesian_basis=True)):
                    j += 1
        else:
            qc.ao_spec[0]['N'] = 1 / numpy.sqrt(norm[:, numpy.newaxis])

        if cartesian_basis:
            from orbkit.cy_overlap import ommited_cca_norm
            cca = ommited_cca_norm(qc.ao_spec.get_lxlylz())
            for mo in qc.mo_spec:
                mo['coeffs'] *= cca

    qc.mo_spec.update()
    qc.ao_spec.update()
    return qc
コード例 #13
0
import numpy
import os, inspect

from orbkit import read
from orbkit import analytical_integrals as ai
from orbkit import options

from orbkit.test.tools import equal

options.quiet = True

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

ao_overlap_matrix = ai.get_ao_overlap(qc.geo_spec,
                                      qc.geo_spec,
                                      qc.ao_spec,
                                      ao_spherical=qc.ao_spherical)

moom = ai.get_mo_overlap_matrix(qc.mo_spec,
                                qc.mo_spec,
                                ao_overlap_matrix,
                                numproc=options.numproc)

equal(moom, numpy.eye(len(moom)))
コード例 #14
0
ファイル: molden.py プロジェクト: marsoner/orbkit
def read_molden(fname,
                all_mo=False,
                spin=None,
                i_md=-1,
                interactive=True,
                **kwargs):
    '''Reads all information desired from a molden file.
  
  **Parameters:**
  
    fname: str, file descriptor
      Specifies the filename for the input file.
      fname can also be used with a file descriptor instad of a filename.
    all_mo : bool, optional
      If True, all molecular orbitals are returned.
    spin : {None, 'alpha', or 'beta'}, optional
      If not None, returns exclusively 'alpha' or 'beta' molecular orbitals.
    i_md : int, default=-1
      Selects the `[Molden Format]` section of the output file.
    interactive : bool
      If True, the user is asked to select the different sets.
  
  **Returns:**
  
    qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot :
        See :ref:`Central Variables` for details.
  '''

    molden_regex = re.compile(r"\[[ ]{,}[Mm]olden[ ]+[Ff]ormat[ ]{,}\]")

    if isinstance(fname, str):
        filename = fname
        fname = descriptor_from_file(filename, index=0)
    else:
        filename = fname.name

    flines = fname.readlines()  # Read the WHOLE file into RAM
    if isinstance(fname, str):
        fname.close()  # Leave existing file descriptors alive

    def check_sel(count, i, interactive=False):
        if count == 0:
            raise IndexError
        elif count == 1:
            return 0
        message = '\tPlease give an integer from 0 to {0}: '.format(count - 1)

        try:
            if interactive:
                i = int(raw_input(message))
            i = range(count)[i]
        except (IndexError, ValueError):
            raise IOError(message.replace(':', '!'))
        else:
            display('\tSelecting the %s' %
                    ('last element.' if
                     (i == count - 1) else 'element %d.' % i))
        return i

    has_alpha = []
    has_beta = []
    restricted = []
    cartesian_basis = []
    mixed_warning = []
    by_orca = []
    count = 0
    # Go through the file line by line
    for il in range(len(flines)):
        line = flines[il]  # The current line as string
        # Check the file for keywords
        if molden_regex.search(line):
            count += 1
            has_alpha.append(False)
            has_beta.append(False)
            restricted.append(False)
            cartesian_basis.append(True)
            mixed_warning.append(False)
            by_orca.append(False)
        if 'orca' in line.lower():
            by_orca[-1] = True
        if '[5d]' in line.lower() or '[5d7f]' in line.lower():
            cartesian_basis[-1] = False
        if '[5d10f]' in line.lower():
            mixed_warning[-1] = '5D, 10F'
            cartesian_basis[-1] = False
        if '[7f]' in line.lower():
            mixed_warning[-1] = '6D, 7F'
            cartesian_basis[-1] = True
        if 'Spin' in line and 'alpha' in line.lower():
            has_alpha[-1] = True
        if 'Spin' in line and 'beta' in line.lower():
            has_beta[-1] = True
        if 'Occup' in line:
            restricted[-1] = restricted[-1] or (float(line.split('=')[1]) >
                                                1. + 1e-4)

    if count == 0:
        raise IOError('The input file %s is no valid molden file!\n\nIt does' %
                      filename + ' not contain the keyword: [Molden Format]\n')
    else:
        if count > 1:
            display('\nContent of the molden file:')
            display('\tFound %d [Molden Format] keywords, i.e., ' % count +
                    'this file contains %d molden files.' % count)
        i_md = check_sel(count, i_md, interactive=interactive)

    if spin is not None:
        if restricted[i_md]:
            raise IOError(
                'The keyword `spin` is only supported for unrestricted calculations.'
            )
        if spin != 'alpha' and spin != 'beta':
            raise IOError('`spin=%s` is not a valid option' % spin)
        elif spin == 'alpha' and has_alpha[i_md]:
            display('Reading only molecular orbitals of spin alpha.')
        elif spin == 'beta' and has_beta[i_md]:
            display('Reading only molecular orbitals of spin beta.')
        elif (not has_alpha[i_md]) and (not has_beta[i_md]):
            raise IOError(
                'Molecular orbitals in `molden` file do not contain `Spin=` keyword'
            )
        elif ((spin == 'alpha' and not has_alpha[i_md])
              or (spin == 'beta' and not has_beta[i_md])):
            raise IOError(
                'You requested `%s` orbitals, but None of them are present.' %
                spin)

    # Set a counter for the AOs
    basis_count = 0
    sym = {}

    # Declare synonyms for molden keywords
    synonyms = {
        'Sym': 'sym',
        'Ene': 'energy',
        'Occup': 'occ_num',
        'Spin': 'spin'
    }
    MO_keys = synonyms.keys()

    count = 0
    max_l = 0
    start_reading = False
    # Go through the file line by line
    for il in range(len(flines)):
        line = flines[il]  # The current line as string
        thisline = line.split()  # The current line split into segments

        # Check the file for keywords
        if '[molden format]' in line.lower():
            # A new file begins
            # Initialize the variables
            if i_md == count:
                qc = QCinfo()
                sec_flag = False  # A Flag specifying the current section
                start_reading = True  # Found the selected section
            else:
                start_reading = False
            count += 1
            continue
        if start_reading:
            if '_ENERGY=' in line:
                try:
                    qc.etot = float(thisline[1])
                except IndexError:
                    pass
            elif '[atoms]' in line.lower():
                # The section containing information about
                # the molecular geometry begins
                sec_flag = 'geo_info'
                if 'Angs' in line:
                    # The length are given in Angstroem
                    # and have to be converted to Bohr radii --
                    aa_to_au = 1 / 0.52917720859
                else:
                    # The length are given in Bohr radii
                    aa_to_au = 1.0
            elif '[gto]' in line.lower():
                # The section containing information about
                # the atomic orbitals begins
                sec_flag = 'ao_info'
                bNew = True  # Indication for start of new AO section
            elif '[mo]' in line.lower():
                # The section containing information about
                # the molecular orbitals begins
                sec_flag = 'mo_info'
                bNew = True  # Indication for start of new MO section
            elif '[sto]' in line.lower():
                # The orbkit does not support Slater type orbitals
                raise IOError('orbkit does not work for STOs!\nEXIT\n')
            elif '[' in line:
                sec_flag = None
            else:
                # Check if we are in a specific section
                if sec_flag == 'geo_info' and thisline != []:
                    # Geometry section
                    qc.geo_info.append(thisline[0:3])
                    qc.geo_spec.append(
                        [float(ii) * aa_to_au for ii in thisline[3:]])
                if sec_flag == 'ao_info':
                    # Atomic orbital section
                    def check_int(i):
                        try:
                            int(i)
                            return True
                        except ValueError:
                            return False

                    if thisline == []:
                        # There is a blank line after every AO
                        bNew = True
                    elif bNew:
                        # The following AOs are for which atom?
                        bNew = False
                        at_num = int(thisline[0]) - 1
                        ao_num = 0
                    elif len(thisline) == 3 and check_int(thisline[1]):
                        # AO information section
                        # Initialize a new dict for this AO
                        ao_num = 0  # Initialize number of atomic orbiatls
                        ao_type = thisline[
                            0]  # Which type of atomic orbital do we have
                        pnum = int(thisline[1])  # Number of primatives
                        # Calculate the degeneracy of this AO and increase basis_count
                        for i_ao in ao_type:
                            # Calculate the degeneracy of this AO and increase basis_count
                            basis_count += l_deg(
                                lquant[i_ao],
                                cartesian_basis=cartesian_basis[i_md])
                            max_l = max(max_l, lquant[i_ao])
                            qc.ao_spec.append({
                                'atom':
                                at_num,
                                'type':
                                i_ao,
                                'pnum':
                                -pnum if by_orca[i_md] else pnum,
                                'coeffs':
                                numpy.zeros((pnum, 2))
                            })
                    else:
                        # Append the AO coefficients
                        coeffs = numpy.array(line.replace('D', 'e').split(),
                                             dtype=numpy.float64)
                        for i_ao in range(len(ao_type)):
                            qc.ao_spec[-len(ao_type) +
                                       i_ao]['coeffs'][ao_num, :] = [
                                           coeffs[0], coeffs[1 + i_ao]
                                       ]
                        ao_num += 1
                if sec_flag == 'mo_info':
                    # Molecular orbital section
                    if '=' in line:
                        # MO information section
                        if bNew:
                            # Create a numpy array for the MO coefficients and
                            # for backward compability create a simple counter for 'sym'
                            qc.mo_spec.append({
                                'coeffs':
                                numpy.zeros(basis_count),
                                'sym':
                                '%d.1' % (len(qc.mo_spec) + 1)
                            })
                            bNew = False
                        # Append information to dict of this MO
                        info = line.replace('\n', '').replace(' ', '')
                        info = info.split('=')
                        if info[0] in MO_keys:
                            if info[0] == 'Spin':
                                info[1] = info[1].lower()
                            elif info[0] != 'Sym':
                                info[1] = float(info[1])
                            elif not '.' in info[1]:
                                from re import search
                                try:
                                    a = search(r'\d+', info[1]).group()
                                    if a == info[1]:
                                        info[1] = '%s.1' % a
                                    elif info[1].startswith(a):
                                        info[1] = info[1].replace(
                                            a, '%s.' % a, 1)
                                    else:
                                        raise AttributeError
                                except AttributeError:
                                    if info[1] not in sym.keys():
                                        sym[info[1]] = 1
                                    else:
                                        sym[info[1]] += 1
                                    info[1] = '%d.%s' % (sym[info[1]], info[1])
                            qc.mo_spec[-1][synonyms[info[0]]] = info[1]
                    else:
                        if ('[' or ']') in line:
                            # start of another section that is not (yet) read
                            sec_flag = None
                        else:
                            # Append the MO coefficients
                            bNew = True  # Reset bNew
                            index = int(thisline[0]) - 1
                            try:
                                # Try to convert coefficient to float
                                qc.mo_spec[-1]['coeffs'][index] = float(
                                    thisline[1])
                            except ValueError:
                                # If it cannot be converted print error message
                                raise ValueError(
                                    'Error in coefficient %d of MO %s!' %
                                    (index, qc.mo_spec[-1]['sym']) +
                                    '\nSetting this coefficient to zero...')

    # Spherical basis?
    if not cartesian_basis[i_md]:
        qc.ao_spherical = get_ao_spherical(qc.ao_spec, p=[1, 0])
    if max_l > 2 and mixed_warning[i_md]:
        raise IOError('The input file %s contains ' % filename +
                      'mixed spherical and Cartesian function (%s).' %
                      mixed_warning[i_md] +
                      'ORBKIT does not support these basis functions yet. ' +
                      'Pleas contact us, if you need this feature!')
    # Are all MOs requested for the calculation?
    if not all_mo:
        for i in range(len(qc.mo_spec))[::-1]:
            if qc.mo_spec[i]['occ_num'] < 0.0000001:
                del qc.mo_spec[i]

    # Only molecular orbitals of one spin requested?
    if spin is not None:
        for i in range(len(qc.mo_spec))[::-1]:
            if qc.mo_spec[i]['spin'] != spin:
                del qc.mo_spec[i]

    if restricted[i_md]:
        # Closed shell calculation
        for mo in qc.mo_spec:
            del mo['spin']
    else:
        # Rename MOs according to spin
        for mo in qc.mo_spec:
            mo['sym'] += '_%s' % mo['spin'][0]

    # Orca uses for all molecular orbitals the same name
    sym = [i['sym'] for i in qc.mo_spec]
    if sym[1:] == sym[:-1]:
        sym = sym[0].split('.')[-1]
        for i in range(len(qc.mo_spec)):
            qc.mo_spec[i]['sym'] = '%d.%s' % (i + 1, sym)

    # Convert geo_info and geo_spec to numpy.ndarrays
    qc.format_geo()

    # Check the normalization
    from orbkit.analytical_integrals import get_ao_overlap, get_lxlylz
    norm = numpy.diagonal(get_ao_overlap(qc.geo_spec, qc.geo_spec, qc.ao_spec))

    if sum(numpy.abs(norm - 1.)) > 1e-8:
        display(
            'The atomic orbitals are not normalized correctly, renormalizing...\n'
        )
        if not by_orca[i_md]:
            j = 0
            for i in range(len(qc.ao_spec)):
                qc.ao_spec[i]['coeffs'][:, 1] /= numpy.sqrt(norm[j])
                for n in range(
                        l_deg(lquant[qc.ao_spec[i]['type']],
                              cartesian_basis=True)):
                    j += 1
        else:
            qc.ao_spec[0]['N'] = 1 / numpy.sqrt(norm[:, numpy.newaxis])

        if cartesian_basis[i_md]:
            from orbkit.cy_overlap import ommited_cca_norm
            cca = ommited_cca_norm(get_lxlylz(qc.ao_spec))
            for mo in qc.mo_spec:
                mo['coeffs'] *= cca

    return qc