1#!/usr/bin/env python
2# Copyright 2014-2020 The PySCF Developers. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16# Author: Qiming Sun <osirpt.sun@gmail.com>
17#
18
19'''
20Parsers for basis set in Gaussian program format
21'''
22
23__all__ = ['parse', 'load']
24
25try:
26    from pyscf.gto.basis.parse_nwchem import optimize_contraction
27    from pyscf.gto.basis.parse_nwchem import remove_zero
28except ImportError:
29    optimize_contraction = lambda basis: basis
30    remove_zero = lambda basis: basis
31
32MAXL = 12
33SPDF = 'SPDFGHIJKLMN'
34MAPSPDF = {key: l for l, key in enumerate(SPDF)}
35
36DELIMETER = '****'
37
38def parse(string, optimize=True):
39    '''Parse the basis text which is in NWChem format, return an internal
40    basis format which can be assigned to :attr:`Mole.basis`
41    Lines started with # are ignored.
42    '''
43    raw_basis = []
44    for dat in string.splitlines():
45        x = dat.split('!', 1)[0].strip()
46        if x and x != DELIMETER:
47            raw_basis.append(x)
48    return _parse(raw_basis, optimize)
49
50def load(basisfile, symb, optimize=True):
51    raw_basis = search_seg(basisfile, symb)
52    #if not raw_basis:
53    #    raise BasisNotFoundError('Basis not found for  %s  in  %s' % (symb, basisfile))
54    return _parse(raw_basis, optimize)
55
56def search_seg(basisfile, symb):
57    with open(basisfile, 'r') as fin:
58
59        def _seek(test_str):
60            raw_basis = []
61            dat = fin.readline()
62            while dat:
63                if test_str in dat:
64                    return True, raw_basis
65                elif dat.strip():  # Skip empty lines
66                    raw_basis.append(dat)
67                dat = fin.readline()
68            return False, raw_basis
69
70        has_delimeter, raw_basis = _seek(DELIMETER)
71        if has_delimeter:
72            dat = fin.readline()
73            while dat:
74                if dat.strip().split(' ', 1)[0].upper() == symb.upper():
75                    raw_basis = _seek(DELIMETER)[1]
76                    break
77                else:
78                    _seek(DELIMETER)
79                dat = fin.readline()
80    return raw_basis
81
82def _parse(raw_basis, optimize=True):
83    basis_add = []
84    for line in raw_basis:
85        dat = line.strip()
86        if dat.startswith('!'):
87            continue
88        elif dat[0].isalpha():
89            key = dat.split()
90            if len(key) == 2:
91                # skip the line which has only two items. It's the line for
92                # element symbol
93                continue
94            elif key[0] == 'SP':
95                basis_add.append([0])
96                basis_add.append([1])
97            elif len(key[0])>2 and key[0][:2] in ['l=', 'L=']:
98                # Angular momentum defined explicitly
99                basis_add.append([int(key[0][2:])])
100            else:
101                basis_add.append([MAPSPDF[key[0]]])
102        else:
103            line = [float(x) for x in dat.replace('D','e').split()]
104            if key[0] == 'SP':
105                basis_add[-2].append([line[0], line[1]])
106                basis_add[-1].append([line[0], line[2]])
107            else:
108                basis_add[-1].append(line)
109    basis_sorted = []
110    for l in range(MAXL):
111        basis_sorted.extend([b for b in basis_add if b[0] == l])
112
113    if optimize:
114        basis_sorted = optimize_contraction(basis_sorted)
115
116    basis_sorted = remove_zero(basis_sorted)
117    return basis_sorted
118
119if __name__ == '__main__':
120    print(load('def2-qzvp-jkfit.gbs', 'C'))
121