예제 #1
0
def get_atom2mo(qc):
  '''Assigns atom indices to molecular orbital coefficients.
  
  **Parameters:**
  
  qc.ao_spec :
      See :ref:`Central Variables` for details.
  
  **Returns:**
  
  atom2mo : numpy.ndarray, shape = (NAO,)
    Contains indices of atoms assigned to the molecular orbital coefficients.
  '''
  atom2mo = []
  a2mo_type = []
  b = 0  
  for sel_ao in range(len(qc.ao_spec)):
    a = qc.ao_spec[sel_ao]['atom']
    if 'exp_list' in qc.ao_spec[sel_ao].keys():
      l = len(qc.ao_spec[sel_ao]['exp_list'])
    else:
      l = l_deg(l=qc.ao_spec[sel_ao]['type'].lower(),
              cartesian_basis=(qc.ao_spherical is None or qc.ao_spherical == []))
    for i in range(l):
      atom2mo.append(a)
      b += 1
  
  return numpy.array(atom2mo,dtype=int)
예제 #2
0
def get_ao_dipole_matrix(qc, component='x'):
    '''Computes the expectation value of the dipole moment operator between 
  all atomic orbitals.
  
  **Parameters:**
  
  qc : class
    QCinfo class. (See :ref:`Central Variables` for details.)
  component : int or string, {'x','y', 'z'}
    Specifies the compontent of the dipole moment operator which shall be applied.
  
  **Returns:**
  
  ao_dipole_matrix : numpy.ndarray, shape=(NAO,NAO)
    Contains the expectation value matrix.
  '''

    if isinstance(component, list):
        aoom = []
        for ii_d in component:
            aoom.append(get_ao_dipole_matrix(qc, component=ii_d))
        return aoom
    if not isinstance(component, int):
        component = 'xyz'.find(component)
    if component == -1:  # Was the selection valid?
        raise ValueError("The selection of the component was not valid!" +
                         " (component = 'x' or 'y' or 'z')")

    # Get the the exponents lx, ly, lz for the primitive Cartesian Gaussians of
    # the `Ket` basis set, and increase lz by one.
    lxlylz_b = get_lxlylz(qc.ao_spec)
    lxlylz_b[:, component] += 1

    ao_part_1 = get_ao_overlap(qc.geo_spec,
                               qc.geo_spec,
                               qc.ao_spec,
                               lxlylz_b=lxlylz_b,
                               ao_spherical=qc.ao_spherical)

    # Compute the second part of the expectation value:
    ao_part_2 = get_ao_overlap(qc.geo_spec,
                               qc.geo_spec,
                               qc.ao_spec,
                               ao_spherical=qc.ao_spherical)

    i = 0
    for sel_ao in range(len(qc.ao_spec)):
        if 'exp_list' in qc.ao_spec[sel_ao].keys():
            l = len(qc.ao_spec[sel_ao]['exp_list'])
        else:
            l = l_deg(l=qc.ao_spec[sel_ao]['type'].lower(),
                      cartesian_basis=(qc.ao_spherical is None
                                       or qc.ao_spherical == []))
        for ll in range(l):
            ao_part_2[:, i] *= qc.geo_spec[qc.ao_spec[sel_ao]['atom'],
                                           component]
            i += 1

    # the atomic orbital overlap matrix
    return (ao_part_1 + ao_part_2)
예제 #3
0
def read_gaussian_log(fname,
                      all_mo=False,
                      spin=None,
                      orientation='standard',
                      i_link=-1,
                      i_geo=-1,
                      i_ao=-1,
                      i_mo=-1,
                      interactive=True,
                      **kwargs):
    '''Reads all information desired from a Gaussian .log 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.
    orientation : string, choices={'input', 'standard'}, optional
      Specifies orientation of the molecule in Gaussian nomenclature. [#first]_ 
    i_link : int, default=-1
      Selects the file for linked Gaussian jobs.
    i_geo : int, default=-1
      Selects the geometry section of the output file.
    i_ao : int, default=-1
      Selects the atomic orbital section of the output file.
    i_mo : int, default=-1
      Selects the molecular orbital 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, ao_spherical, mo_spec, etot :
        See :ref:`Central Variables` for details.

.. [#first] Attention: The MOs in the output are only valid for the standard orientation!

  '''

    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

    # Search the file the specific sections
    count = {
        'link': 0,
        'geometry': 0,
        'geometry_input': 0,
        'atomic orbitals': 0,
        'molecular orbitals': [],
        'state': []
    }

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

        try:
            if interactive:
                i = raw_input(message)
                i = default if i == '' else int(i)
            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

    # 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 ' Entering Link 1' in line:
            count['link'] += 1

    try:
        display('\tFound %d linked GAUSSIAN files.' % count['link'])
        i_link = check_sel(count['link'], i_link, interactive=interactive)
    except IndexError:
        raise IOError('Found no `Entering Link 1` keyword!')

    cartesian_basis = True
    c_link = 0
    # 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 ' Entering Link 1' in line:
            c_link += 1
        if i_link == (c_link - 1):
            if ' orientation:' in line:
                if '%s orientation:' % orientation in line.lower():
                    count['geometry'] += 1
                if 'input orientation:' in line.lower():
                    count['geometry_input'] += 1
            elif 'Standard basis:' in line or 'General basis read from cards:' in line:
                # Check if a cartesian basis has been applied
                if '(5D, 7F)' in line:
                    cartesian_basis = False
                elif '(6D, 10F)' not in line:
                    raise IOError(
                        'Please apply a Spherical Harmonics (5D, 7F) or ' +
                        'a Cartesian Gaussian Basis Set (6D, 10F)!')
            elif 'AO basis set' in line:
                count['atomic orbitals'] += 1
            elif 'The electronic state is ' in line:
                count['state'].append(thisline[-1][:-1])
            elif 'Orbital Coefficients:' in line:
                mo_type = thisline[0]
                if mo_type != 'Beta':
                    count['molecular orbitals'].append(mo_type)
                else:
                    count['molecular orbitals'][-1] = 'Alpha&Beta'

    display('\nContent of the GAUSSIAN .log file:')
    display('\tFound %d geometry section(s). (%s orientation)' %
            (count['geometry'], orientation))
    try:
        i_geo = check_sel(count['geometry'], i_geo, interactive=interactive)
    except IndexError:
        count['geometry'] = count['geometry_input']
        orientation = 'input'
        display('\Looking for "Input orientation": \n' +
                '\tFound %d geometry section(s). (%s orientation)' %
                (count['geometry'], orientation))
        try:
            i_geo = check_sel(count['geometry'],
                              i_geo,
                              interactive=interactive)
        except IndexError:
            raise IOError('Found no geometry section!' +
                          ' Are you sure this is a GAUSSIAN .log file?')

    try:
        display('\tFound %d atomic orbitals section(s) %s.' %
                (count['atomic orbitals'],
                 '(6D, 10F)' if cartesian_basis else '(5D, 7F)'))
        i_ao = check_sel(count['atomic orbitals'],
                         i_ao,
                         interactive=interactive)
    except IndexError:
        raise IOError('Write GFINPUT in your GAUSSIAN route section to print' +
                      ' the basis set information!')

    try:
        display('\tFound the following %d molecular orbitals section(s):' %
                len(count['molecular orbitals']))
    except IndexError:
        raise IOError(
            'Write IOP(6/7=3) in your GAUSSIAN route section to print\n' +
            ' all molecular orbitals!')
    for i, j in enumerate(count['molecular orbitals']):
        string = '\t\tSection %d: %s Orbitals' % (i, j)
        try:
            string += ' (electronic state: %s)' % count['state'][i]
        except IndexError:
            pass
        display(string)
    i_mo = check_sel(len(count['molecular orbitals']),
                     i_mo,
                     interactive=interactive)

    if spin is not None:
        if spin != 'alpha' and spin != 'beta':
            raise IOError('`spin=%s` is not a valid option' % spin)
        else:
            display('Reading only molecular orbitals of spin %s.' % spin)

    # Set a counter for the AOs
    basis_count = 0

    # Initialize some variables
    sec_flag = None
    skip = 0
    c_link = 0
    c_geo = 0
    c_ao = 0
    c_mo = 0
    c_sao = 0
    old_ao = -1
    orb_sym = []
    qc = QCinfo()
    index = []

    # 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 ' Entering Link 1' in line:
            c_link += 1
        if i_link == (c_link - 1):
            if '%s orientation:' % orientation in line.lower():
                # The section containing information about
                # the molecular geometry begins
                if i_geo == c_geo:
                    qc.geo_info = []
                    qc.geo_spec = []
                    sec_flag = 'geo_info'
                c_geo += 1
                skip = 4
            elif 'Standard basis:' in line or 'General basis read from cards:' in line:
                # Check if a cartesian basis has been applied
                if '(5D, 7F)' in line:
                    cartesian_basis = False
                elif '(6D, 10F)' not in line:
                    raise IOError(
                        'Please apply a Spherical Harmonics (5D, 7F) or ' +
                        'a Cartesian Gaussian Basis Sets (6D, 10F)!')
            elif 'AO basis set' in line:
                # The section containing information about
                # the atomic orbitals begins
                if i_ao == c_ao:
                    qc.ao_spec = []
                    if not cartesian_basis:
                        qc.ao_spherical = []
                    sec_flag = 'ao_info'
                c_ao += 1
                basis_count = 0
                bNew = True  # Indication for start of new AO section
            elif 'Orbital symmetries:' in line:
                sec_flag = 'mo_sym'
                add = ''
                orb_sym = []
            elif 'Orbital Coefficients:' in line:
                # The section containing information about
                # the molecular orbitals begins
                if (i_mo == c_mo):
                    sec_flag = 'mo_info'
                    mo_type = count['molecular orbitals'][i_mo]
                    qc.mo_spec = []
                    offset = 0
                    add = ''
                    orb_spin = []
                    if orb_sym == []:
                        if 'Alpha' in mo_type:
                            add = '_a'
                            orb_spin = ['alpha'] * basis_count
                        orb_sym = ['A1' + add] * basis_count
                        if 'Beta' in mo_type:
                            add = '_b'
                            orb_spin += ['beta'] * basis_count
                            orb_sym += ['A1' + add] * basis_count
                    for i in range(len(orb_sym)):
                        # for numpy version < 1.6
                        c = ((numpy.array(orb_sym[:i + 1]) == orb_sym[i]) !=
                             0).sum()
                        # for numpy version >= 1.6 this could be used:
                        #c = numpy.count_nonzero(numpy.array(orb_sym[:i+1]) == orb_sym[i])
                        qc.mo_spec.append({
                            'coeffs': numpy.zeros(basis_count),
                            'energy': 0.,
                            'sym': '%d.%s' % (c, orb_sym[i])
                        })
                        if orb_spin != []:
                            qc.mo_spec[-1]['spin'] = orb_spin[i]
                if mo_type != 'Beta':
                    c_mo += 1
                bNew = True  # Indication for start of new MO section
            elif 'E(' in line:
                qc.etot = float(line.split('=')[1].split()[0])
            else:
                # Check if we are in a specific section
                if sec_flag == 'geo_info':
                    if not skip:
                        qc.geo_info.append(
                            [thisline[1], thisline[0], thisline[1]])
                        qc.geo_spec.append([float(ij) for ij in thisline[3:]])
                        if '-----------' in flines[il + 1]:
                            sec_flag = None
                    else:
                        skip -= 1
                if sec_flag == 'ao_info':
                    # Atomic orbital section
                    if ' ****' in line:
                        # There is a line with stars after every AO
                        bNew = True
                        # If there is an additional blank line, the AO section is complete
                        if flines[il + 1].split() == []:
                            sec_flag = None
                    elif bNew:
                        # The following AOs are for which atom?
                        bNew = False
                        at_num = int(thisline[0]) - 1
                        ao_num = 0
                    elif len(thisline) == 4:
                        # AO information section
                        # Initialize a new dict for this AO
                        ao_num = 0  # Initialize number of atomic orbiatls
                        ao_type = thisline[0].lower()  # Type of atomic orbital
                        pnum = int(thisline[1])  # Number of primatives
                        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)
                            qc.ao_spec.append({
                                'atom': at_num,
                                'type': i_ao,
                                'pnum': 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_sym':
                    if 'electronic state' in line:
                        sec_flag = None
                    else:
                        info = line[18:].replace('(', '').replace(')',
                                                                  '').split()
                        if 'Alpha' in line:
                            add = '_a'
                        elif 'Beta' in line:
                            add = '_b'
                        for i in info:
                            orb_sym.append(i + add)
                if sec_flag == 'mo_info':
                    # Molecular orbital section
                    info = line[:21].split()
                    if info == []:
                        coeffs = line[21:].split()
                        if bNew:
                            index = [offset + i for i in range(len(coeffs))]
                            bNew = False
                        else:
                            for i, j in enumerate(index):
                                qc.mo_spec[j]['occ_num'] = int(
                                    'O' in coeffs[i])
                                if mo_type not in 'Alpha&Beta':
                                    qc.mo_spec[j]['occ_num'] *= 2
                    elif 'Eigenvalues' in info:
                        coeffs = line[21:].replace('-', ' -').split()
                        if mo_type == 'Natural':
                            key = 'occ_num'
                        else:
                            key = 'energy'
                        for i, j in enumerate(index):
                            qc.mo_spec[j][key] = float(coeffs[i])
                    else:
                        coeffs = line[21:].replace('-', ' -').split()
                        if not cartesian_basis and offset == 0:
                            if old_ao != line[:14].split()[-1] or len(
                                    line[:14].split()) == 4:
                                old_ao = line[:14].split()[-1]
                                c_sao += 1
                            i = c_sao - 1
                            l = lquant[line[13].lower()]
                            m = line[14:21].replace(' ', '').lower()
                            p = 'yzx'.find(m) if len(m) == 1 else -1
                            if p != -1:
                                m = p - 1
                            elif m == '':
                                m = 0
                            else:
                                m = int(m)
                            qc.ao_spherical.append([i, (l, m)])
                        for i, j in enumerate(index):
                            qc.mo_spec[j]['coeffs'][int(info[0]) - 1] = float(
                                coeffs[i])
                        if int(info[0]) == basis_count:
                            bNew = True
                            offset = index[-1] + 1
                            if index[-1] + 1 == len(orb_sym):
                                sec_flag = None
                                orb_sym = []

    # 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]

    if spin is not None:
        if orb_spin == []:
            raise IOError(
                'You requested `%s` orbitals, but None of them are present.' %
                spin)
        else:
            for i in range(len(qc.mo_spec))[::-1]:
                if qc.mo_spec[i]['spin'] != spin:
                    del qc.mo_spec[i]

    # Convert geo_info and geo_spec to numpy.ndarrays
    qc.format_geo(is_angstrom=True)
    return qc
예제 #4
0
def gross_atomic_density(atom,
                         qc,
                         bReturnmo=False,
                         ao_list=None,
                         mo_list=None,
                         drv=None):
    r'''Computes the gross atomic density with respect to the selected atoms.
  
  .. math::
  
    \rho^a = \sum_i^{N_{\rm MO}} {\rm occ}_i \cdot \varphi_i^a \cdot \varphi_i
  
  
  **Parameters:**
  
    atom : 'all' or int or list of int
      Specifies the atoms (counting from one) for which the gross atomic density
      will be computed.  
      If (atom == 'all') or (atom == -1), computes the gross atomic density  
      for all atoms.
    qc.geo_spec, qc.geo_info, qc.ao_spec, qc.mo_spec :
      See :ref:`Central Variables` for details.
    bReturnmo : bool, optional
      If True, the gross atomic molecular orbitals are additionally returned.

  **Returns:**
  
    rho_atom : list of numpy.ndarrays, shape=(len(atoms,) + N)
      Contains the atom gross atomic density on a grid.
    mo_atom : list of numpy.ndarrays, shape=(len(atoms,NMO) + N)
      Contains the NMO=len(mo_spec) gross atomic molecular orbitals on a grid. 
  '''

    if (atom == 'all' or atom == -1):
        atom = range(1, len(qc.geo_info) + 1)

    atom, index = atom2index(atom, geo_info=qc.geo_info)

    display('Computing the gross atomic density with respect to ' +
            'the atom(s) (internal numbering)')
    outp = '\t['
    for i, a in enumerate(atom):
        if not i % 10 and i != 0:
            outp += '\n\t'
        outp += '%d,\t' % a
    display('%s]\n' % outp[:-2])

    display('\tCalculating ao_list & mo_list')
    if ao_list is None:
        ao_list = core.ao_creator(qc.geo_spec, qc.ao_spec, drv=drv)
    if mo_list is None:
        mo_list = core.mo_creator(ao_list, qc.mo_spec)

    display('\tCalculating the gross atomic density')
    N = mo_list.shape[1:]
    if bReturnmo: mo_atom = [[] for a in index]
    rho_atom = [numpy.zeros(N) for a in index]
    for i, a in enumerate(index):
        display('\t\tFinished %d of %d' % (i + 1, len(index)))
        ao_index = []
        ao = []
        ll = 0
        for ii in qc.ao_spec:
            for l in range(core.l_deg(l=ii['type'])):
                if ii['atom'] == a:
                    ao_index.append(ll)
                    ao.append(ao_list[ll])
                ll += 1

        for ii_mo, spec in enumerate(qc.mo_spec):
            mo_info = numpy.zeros(N)
            for jj in range(len(ao_index)):
                mo_info += spec['coeffs'][ao_index[jj]] * ao[jj]
            rho_atom[i] += spec['occ_num'] * mo_list[ii_mo] * mo_info
            if bReturnmo: mo_atom[i].append(mo_info)

    string = 'Returning the gross atomic density'
    if bReturnmo:
        display(string + ' and\n\tthe gross atomic molecular orbitals')
        return rho_atom, mo_atom
    else:
        display(string)
        return rho_atom
예제 #5
0
    ao_part_1 = get_ao_overlap(qc.geo_spec,
                               qc.geo_spec,
                               qc.ao_spec,
                               lxlylz_b=lxlylz_b,
                               ao_spherical=qc.ao_spherical)

    # Compute the second part of the expectation value:
    ao_part_2 = get_ao_overlap(qc.geo_spec,
                               qc.geo_spec,
                               qc.ao_spec,
                               ao_spherical=qc.ao_spherical)

    i = 0
    for sel_ao in range(len(qc.ao_spec)):
        l = l_deg(l=qc.ao_spec[sel_ao]['type'].lower(),
                  cartesian_basis=(qc.ao_spherical is None))
        for ll in range(l):
            ao_part_2[:, i] *= qc.geo_spec[qc.ao_spec[sel_ao]['atom'],
                                           component]
            i += 1

    ao_dipole_matrix = (ao_part_1 + ao_part_2)

    # Print the atomic orbital dipole matrix
    if 0:
        print2D(ao_dipole_matrix)

    # Compute the electronic part of the dipole moment
    dm = 0.
    for i, i_mo in enumerate(qc.mo_spec):
        dm -= i_mo['occ_num'] * get_mo_overlap(i_mo['coeffs'], i_mo['coeffs'],
예제 #6
0
def convert_json(jData, all_mo=False, spin=None):
  '''Converts a scanlog JSON data instance to an instance of
  orbkit's QCinfo class.

  **Parameters:**
  
    jData : class
      Contains the input JSON data.
    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.


  **Returns:**

    qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot :
          See :ref:`Central Variables` for details.
  '''
  aa_to_au = 1/0.52917720859
  # Initialize the variables 
  qc = QCinfo()
  
  # Converting all information concerning atoms and geometry
  qc.geo_spec = numpy.array(jData['results']['geometry']['elements_3D_coords_converged']).reshape((-1, 3)) * aa_to_au
  for ii in range(jData["molecule"]['nb_atoms']):
    symbol = get_atom_symbol(atom=jData["molecule"]['atoms_Z'][ii])
    qc.geo_info.append([symbol,str(ii+1),str(jData["molecule"]['atoms_Z'][ii])])
  
  # Convert geo_info and geo_spec to numpy.ndarrays
  qc.format_geo()
  
  # Converting all information about atomic basis set
  from pickle import loads
  gbasis = loads(bytes(jData['comp_details']['general']['basis_set'], 'utf-8'))
  for ii in range(jData["molecule"]['nb_atoms']):
    for jj in range(len(gbasis[ii])):
      pnum = len(gbasis[ii][jj][1])
      qc.ao_spec.append({'atom': ii,
                  'type': str(gbasis[ii][jj][0]).lower(),
                  'pnum':  pnum,
                  'coeffs': numpy.zeros((pnum, 2))
                  })
      for kk in range(pnum):
        qc.ao_spec[-1]['coeffs'][kk][0] = gbasis[ii][jj][1][kk][0]
        qc.ao_spec[-1]['coeffs'][kk][1] = gbasis[ii][jj][1][kk][1]

  if "ao_names" in jData['comp_details']['general']:
    # Reconstruct exponents list for ao_spec
    aonames = jData['comp_details']['general']['ao_names']
    cartesian_basis = True
    for i in aonames:
      if '+' in i or '-' in i:
        cartesian_basis = False
# There is a problem here with the 6D 7F basis sets, that are a mixture of cartesian and spherical basis sets.
    if not cartesian_basis:
        qc.ao_spherical = []
    
    count = 0
    for i,ao in enumerate(qc.ao_spec):
      l = l_deg(lquant[ao['type']],cartesian_basis=cartesian_basis)
      if cartesian_basis:
        ao['exp_list'] = []
        
      for ll in range(l):
        if cartesian_basis:
          ao['exp_list'].append((aonames[count].lower().count('x'),
                                 aonames[count].lower().count('y'),
                                 aonames[count].lower().count('z')))
        else:
          m = aonames[count].lower().split('_')[-1]
          m = m.replace('+',' +').replace('-',' -').replace('s','s 0').split(' ') 
          p = 'yzx'.find(m[0][-1])
          if p != -1:
            m = p - 1
          else:
            m = int(m[-1])
          qc.ao_spherical.append([i,(lquant[ao['type']],m)])
        count += 1
  
  # Converting all information about molecular orbitals
  ele_num = numpy.sum(jData["molecule"]['atoms_Z']) - numpy.sum(jData['comp_details']['general']['core_electrons_per_atoms']) - jData['molecule']['charge']
  ue = (jData['molecule']['multiplicity']-1)
  
  # Check for natural orbitals and occupation numbers
  is_natorb = False
  #if hasattr(ccData,'nocoeffs'):
  #  if not hasattr(ccData,'nooccnos'):
  #    raise IOError('There are natural orbital coefficients (`nocoeffs`) in the cclib' + 
  #                  ' ccData, but no natural occupation numbers (`nooccnos`)!')
  #  is_natorb = True
  
  restricted = (len(jData['results']['wavefunction']['MO_energies']) == 1)
  if spin is not None:
    if spin != 'alpha' and spin != 'beta':
      raise IOError('`spin=%s` is not a valid option' % spin)
    elif restricted:
      raise IOError('The keyword `spin` is only supported for unrestricted calculations.')
    else:
      display('Converting only molecular orbitals of spin %s.' % spin)
  
  import scipy.sparse
  sym = {}
  shape = (jData['results']['wavefunction']['MO_number_kept'], jData['comp_details']['general']['basis_set_size'])
  pre_mocoeffs = jData['results']["wavefunction"]["MO_coefs"]
  if restricted:
    add = ['']
    orb_sym = [None]
    mocoeffs = [numpy.asarray(scipy.sparse.csr_matrix(tuple([numpy.asarray(d) for d in pre_mocoeffs[0]]), shape=shape).todense())]
  else:
    add = ['_a','_b']      
    orb_sym = ['alpha','beta']
    mocoeffs = [numpy.asarray(scipy.sparse.csr_matrix(tuple([numpy.asarray(d) for d in pre_mocoeffs[0]]), shape=shape).todense()),
                numpy.asarray(scipy.sparse.csr_matrix(tuple([numpy.asarray(d) for d in pre_mocoeffs[1]]), shape=shape).todense())]

  nmo = jData['results']['wavefunction']['MO_number'] if "nmo" in jData['results']['wavefunction'] else len(mocoeffs[0])
  for ii in range(nmo):
    for i,j in enumerate(add):
      a = '%s%s' % (jData['results']['wavefunction']['MO_sym'][i][ii],j)
      if a not in sym.keys(): sym[a] = 1
      else: sym[a] += 1
      #if is_natorb:
      #  occ_num = ccData.nooccnos[ii]
      if not restricted:
        occ_num = 1.0 if ii <= jData['results']['wavefunction']['homo_indexes'][i] else 0.0
      elif ele_num > ue:
        occ_num = 2.0
        ele_num -= 2.0
      elif ele_num > 0.0 and ele_num <= ue: 
        occ_num = 1.0
        ele_num -= 1.0
        ue -= 1.0
      else:
        occ_num = 0.0
      qc.mo_spec.append({'coeffs': mocoeffs[i][ii],
              'energy': jData['results']['wavefunction']['MO_energies'][i][ii],
              'occ_num': occ_num,
              'sym': '%d.%s' %(sym[a],a)
              })
      if orb_sym[i] is not None:
        qc.mo_spec[-1]['spin'] = orb_sym[i]
        if spin is not None and spin != orb_sym[i]:
          del qc.mo_spec[-1]
  
  # Use default order for atomic basis functions if aonames is not present
  if 'ao_names' not in jData['comp_details']['general']:
    display('The attribute `aonames` is not present in the parsed data.')
    display('Using the default order of basis functions.')
    
    # Check which basis functions have been used
    c_cart = sum([l_deg(l=ao['type'], cartesian_basis=True) for ao in qc.ao_spec])
    c_sph = sum([l_deg(l=ao['type'], cartesian_basis=False) for ao in qc.ao_spec])
    
    c = create_mo_coeff(qc.mo_spec,'').shape[-1]
    if c != c_cart and c == c_sph: # Spherical basis
      qc.ao_spherical = get_ao_spherical(qc.ao_spec,p=[0,1])
    elif c != c_cart:
      display('Warning: The basis set type does not match with pure spherical ' +
              'or pure Cartesian basis!') 
      display('Please specify qc.mo_spec["exp_list"] and/or qc.ao_spherical by your self.')
  
  # 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]

  return qc
예제 #7
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
예제 #8
0
def read_aomix(fname,
               all_mo=False,
               spin=None,
               i_md=-1,
               interactive=True,
               created_by_tmol=True,
               **kwargs):
    '''Reads all information desired from a aomix 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 `[AOMix Format]` section of the output file.
    interactive : bool
      If True, the user is asked to select the different sets.
    created_by_tmol : bool
      If True and if Cartesian basis set is found, the molecular orbital 
      coefficients will be converted.
  
  **Returns:**
  
    qc (class QCinfo) with attributes geo_spec, geo_info, ao_spec, mo_spec, etot :
        See :ref:`Central Variables` for details.
  '''

    aomix_regex = re.compile(r"\[[ ]{,}[Aa][Oo][Mm]ix[ ]+[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

    # Is this really a aomix file?
    if not '[AOMix Format]\n' in flines:
        raise IOError('The input file %s is no valid aomix file!\n\nIt does' %
                      filename + ' not contain the keyword: [AOMix Format]\n')

    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 %d: ' % (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 = []
    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 aomix_regex.search(line):
            count += 1
            has_alpha.append(False)
            has_beta.append(False)
            restricted.append(False)
        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 aomix file!\n\nIt does' %
                      filename + ' not contain the keyword: [AOMix Format]\n')
    else:
        if count > 1:
            display('\nContent of the aomix file:')
            display('\tFound %d [AOMix Format] keywords, i.e., ' % count +
                    'this file contains %d aomix files.' % count)
        i_md = check_sel(count, i_md, interactive=interactive)

    spin_check(spin, restricted[i_md], has_alpha[i_md], has_beta[i_md])

    # Set a counter for the AOs
    basis_count = 0

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

    exp_list = []
    count = 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 '[aomix 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 '[SCF Energy / Hartree]' in line:
                try:
                    qc.etot = float(flines[il + 1].split()[0])
                except IndexError:
                    pass
            elif '[atoms]' in line.lower():
                # The section containing information about
                # the molecular geometry begins
                sec_flag = 'geo_info'
                angstrom = 'Angs' in line
            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')
            else:
                # Check if we are in a specific section
                if sec_flag == 'geo_info':
                    # Geometry section
                    qc.geo_info.append(thisline[0:3])
                    qc.geo_spec.append([float(ii) 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])
                            qc.ao_spec.append({
                                'atom': at_num,
                                'type': i_ao,
                                'pnum': 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
                                a = search(r'\d+', info[1]).group()
                                if a == info[1]:
                                    info[1] = '%s.1' % a
                                else:
                                    info[1] = info[1].replace(a, '%s.' % a, 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])
                                if len(qc.mo_spec) == 1:
                                    exp_list.append(thisline[-2])
                            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...')

    # Check usage of same atomic basis sets
    for ii in range(len(exp_list)):
        s = exp_list[ii]
        exp = [0, 0, 0]
        c_last = None
        for jj in s[1:]:
            try:
                c = int(jj)
                exp[c_last] += (c - 1)
            except ValueError:
                for kk, ll in enumerate('xyz'):
                    if jj == ll:
                        exp[kk] += 1
                        c_last = kk
        exp_list[ii] = exp

    count = 0
    for i, j in enumerate(qc.ao_spec):
        l = l_deg(lquant[j['type']])
        j['exp_list'] = []
        for i in range(l):
            j['exp_list'].append(
                (exp_list[count][0], exp_list[count][1], exp_list[count][2]))
            count += 1
        j['exp_list'] = numpy.array(j['exp_list'], dtype=numpy.int64)

    # For Cartesian basis sets in Turbomole, the molecular orbital coefficients
    # have to be converted.
    is_tmol_cart = not (len(qc.mo_spec) % len(qc.mo_spec[0]['coeffs']))

    # 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]

    # Modify qc.mo_spec to support spin
    qc.select_spin(restricted[i_md], spin=spin)

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

    if is_tmol_cart and created_by_tmol:
        display('\nFound a Cartesian basis set in the AOMix file.')
        display('We assume that this file has been created by Turbomole.')
        display(
            'Applying a conversion to the molecular orbital coefficients, ')
        display('in order to get normalized orbitals.')

        # Convert MO coefficients
        from orbkit.analytical_integrals import create_mo_coeff, get_lxlylz

        def dfact(n):
            if n <= 0:
                return 1
            else:
                return n * dfact(n - 2)

        mo = create_mo_coeff(qc.mo_spec)
        for i, j in enumerate(get_lxlylz(qc.ao_spec)):
            norm = (dfact(2 * j[0] - 1) * dfact(2 * j[1] - 1) *
                    dfact(2 * j[2] - 1))
            j = sum(j)
            if j > 1:
                mo[:, i] *= numpy.sqrt(norm)
        for ii in range(len(qc.mo_spec)):
            qc.mo_spec[ii]['coeffs'] = mo[ii]

    return qc