def orbitals(j, z): """[input] j: orbital type, z: atomic number, [outpout] coef: contraction coefficients, exp: contraction exponents""" #1: 1s, 2:2s, 3:2px, 4:2py, 5:2pz, 6:3s, 7:3px, 8:3py, 9:3pz if j == 1: #if j <= 2: exp = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][0]["exponents"] coef = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][0]["coefficients"][0] elif j > 1 and j <= 2: exp = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][1]["exponents"] coef = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][1]["coefficients"][0] elif j > 2 and j <= 5: exp = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][1]["exponents"] coef = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][1]["coefficients"][1] elif j > 5 and j <= 6: exp = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][2]["exponents"] coef = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][2]["coefficients"][0] elif j > 6 and j <= 9: exp = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][2]["exponents"] coef = bse.get_basis("sto-3g")["elements"][str( z)]["electron_shells"][2]["coefficients"][1] else: print("error: orbital number does not exist") return np.array(coef), np.array(exp)
def test_slow_get_basis_1(basis_name, fmt, unc_gen, unc_seg, unc_spdf, make_gen, opt_gen): """Tests getting all basis sets in all formats and with every combination of option Also tests memoization """ this_metadata = bs_metadata[basis_name] for ver in this_metadata['versions'].keys(): bs1 = bse.get_basis(basis_name, fmt=fmt, version=ver, uncontract_general=unc_gen, uncontract_segmented=unc_seg, uncontract_spdf=unc_spdf, make_general=make_gen, optimize_general=opt_gen, header=False) bs2 = bse.get_basis(basis_name, fmt=fmt, version=ver, uncontract_general=unc_gen, uncontract_segmented=unc_seg, uncontract_spdf=unc_spdf, make_general=make_gen, optimize_general=opt_gen, header=False) assert bs1 == bs2
def add_custom_basis_set(self, name, add_all_elements=False, return_string=False): """ Appends custom basis sets (from Basis Set Exchange) to ``self.footer``. Should be used in combination with the ``gen`` keyword. Args: name (str): name of basis set (look it up on Basis Set Exchange) add_all_elements (bool): whether the complete basis set should be added or just the elements of interest return_string (bool): if the basis set should be appended to the footer or returned as a string (no change to ``self``) Returns: nothing (if return_string is ``False``) string of basis set definition (if return string is ``True``) """ import basis_set_exchange as bse assert isinstance(name, str), "need basis set name to be a string, for starters" try: basis_definition = "" if add_all_elements: basis_definition = bse.get_basis(name, fmt="gaussian94", header=False) else: elements = list(np.unique(self.get_molecule().atomic_numbers.view(np.ndarray))) basis_definition = bse.get_basis(name, fmt="gaussian94", header=False, elements=elements) if self.footer is None: self.footer = basis_definition else: self.footer += basis_definition self.footer += "\n" except Exception as e: raise ValueError(f"adding basis set {name} from basis set exchange failed!\n{e}")
def test_get_basis_4_noecp(basis_name, fmt): """For a sample of basis sets, test getting different formats of the latest version Tests writers that are NOT capable of ECP """ bse.get_basis(basis_name, fmt=fmt)
def test_get_basis_fail_data_dir(tmp_path): """Test get_basis with bad data dir """ tmp_path = str(tmp_path) # Needed for python 3.5 with pytest.raises(FileNotFoundError, match=r'JSON file .* does not exist'): bse.get_basis('cc-pvdz', data_dir=tmp_path)
def test_get_basis_3(basis_name, bool_opts): """For a sample of basis sets, test different options """ bse.get_basis(basis_name, uncontract_general=bool_opts[0], uncontract_segmented=bool_opts[1], uncontract_spdf=bool_opts[2], make_general=bool_opts[3], optimize_general=bool_opts[4])
def test_get_basis_memo(basis_name): """For a sample of basis sets, test memoization """ bs1 = bse.get_basis(basis_name) bs2 = bse.get_basis(basis_name) # Should be equal, but not aliased assert bs1 == bs2 assert bs1['basis_set_elements'] is not bs2['basis_set_elements']
def test_duplicate_data(bs_name, bs_ver): ''' Test for any duplicate data in a basis set ''' bs_dict = bse.get_basis(bs_name, version=bs_ver) _test_duplicates(bs_dict, False)
def _format_basisset(nuclear_charges, basisset, superimposed=False): res = '' for atomid, nuclear_charge in enumerate(nuclear_charges): if superimposed: elements = set([ max(1, int(_(nuclear_charge))) for _ in (np.round, lambda _: np.round(_ + 1), lambda _: np.round(_ - 1)) ]) else: elements = set( [max(1, int(_(nuclear_charge))) for _ in (np.round, )]) output = bse.get_basis(basisset, elements=list(elements), fmt='gaussian94') res += '%d 0\n' % (atomid + 1) skipnext = False for line in output.split('\n'): if line.startswith('!'): skipnext = False continue if len(line.strip()) == 0 or line.strip() == '****': skipnext = True continue if skipnext: skipnext = False continue res += line + '\n' res += '****\n' return res.strip()
def add_basis(self, basis_name): if basis_name in basis_dict: basis_name = basis_dict[basis_name] elements = self.get_elements() atoms = [getattr(el, x) for x in elements] basis_set = bse.get_basis(basis_name, elements=elements, fmt='gamess_us', header=False) atoms.sort(key=lambda x: x.AtomicNumber) for i in range(len(atoms)): name1 = atoms[i].Name.upper() try: name2 = atoms[i + 1].Name.upper() except: name2 = '$END' a = basis_set.find(name1) + len(name1) b = basis_set.find(name2) atom_basis = basis_set[a:b] self.basis[atoms[i].Symbol] = atom_basis[1:].strip('\n') return
def _run_test_bundles(tmp_path, fmt, reffmt, ext, data_dir): '''Test functionality related to creating archive of basis set''' tmp_path = str(tmp_path) # Needed for python 3.5 bs_ext = bse.writers.get_format_extension(fmt) ref_ext = bse.refconverters.get_format_extension(reffmt) filename = "bundletest_" + fmt + "_" + reffmt + ext filepath = os.path.join(tmp_path, filename) bse.create_bundle(filepath, fmt, reffmt, None, data_dir) extract_dir = "extract_" + filename extract_path = os.path.join(tmp_path, extract_dir) _extract_all(filepath, extract_path) # Keep track of all the basis sets we have found # Start with all found in the data dir, and remove # each time we process one all_bs = [] for k, v in bse.get_metadata(data_dir).items(): for ver in v['versions'].keys(): all_bs.append((k, ver)) all_ref = all_bs.copy() for root, dirs, files in os.walk(extract_path): for basename in files: if basename == 'README.txt': continue fpath = os.path.join(root, basename) name, ver = basename.split('.')[:2] tr_name = bse.misc.basis_name_from_filename(name) if basename.endswith('.ref' + ref_ext): compare_data = bse.get_references(tr_name, fmt=reffmt, version=ver, data_dir=data_dir) all_ref.remove((name, ver)) elif basename.endswith(bs_ext): compare_data = bse.get_basis(name, fmt=fmt, version=ver, data_dir=data_dir) all_bs.remove((name, ver)) elif basename.endswith('.family_notes'): compare_data = bse.get_family_notes(name, data_dir) elif basename.endswith('.notes'): compare_data = bse.get_basis_notes(name, data_dir) else: raise RuntimeError("Unknown file found: " + fpath) with open(fpath, 'r', encoding='utf-8') as ftmp: assert compare_data == ftmp.read() assert len(all_bs) == 0 assert len(all_ref) == 0
def parse_basis(self): """Get the properties of all the orbitals in the molecule.""" # number of orbs self.norb = 0 # loop over all the atoms for at in self.atoms: at_num = element(at).atomic_number self.nshells.append(0) # import data data = json.loads(bse.get_basis( self.basis, elements=[at_num], fmt='JSON')) # loop over the electronic shells for ishell, shell in enumerate( data['elements'][str(at_num)]['electron_shells']): # get the primary number n = ishell # loop over the angular momentum for iangular, angular in enumerate( shell['angular_momentum']): # secondary qn and multiplicity l = angular mult = self.mult_bas[self.get_label[angular]] nbas = len(shell['exponents']) mvals = self.get_m[self.get_label[angular]] for imult in range(mult): self.norb += 1 # store coeffs and exps of the bas self.bas_exp += ( np.array( shell['exponents']).astype('float')).tolist() self.bas_coeffs += np.array( shell['coefficients'][iangular]).astype('float').tolist() # index of the contraction self.index_ctr += [self.norb - 1] * nbas # store the quantum numbers self.bas_n += [n] * nbas self.bas_l += [l] * nbas self.bas_m += [mvals[imult]] * nbas # number of shells self.nshells[-1] += mult * nbas
def basis(self, basis: str = "STO-3G"): # Obtain the basis set in nwchem format (as a string) atoms = self.atoms basis = bse.get_basis(basis, elements=atoms, fmt='nwchem') ob = "d*[spdf]" parsed_basis = re.findall( f"-> \\[(\\{ob},*\\{ob}*,*\\{ob}*)\\]\n(\\w+)", basis) assert len(atoms) == len(parsed_basis), \ f"Cannot parse basis: number of atoms does not match result: \ {basis}" return dict(zip(atoms, parsed_basis))
def test_get_basis_2(basis_name): """For all versions of basis sets, test a simple get_basis with different element selections """ this_metadata = bs_metadata[basis_name] latest = this_metadata['latest_version'] avail_elements = this_metadata['versions'][latest]['elements'] nelements = random.randint(1, len(avail_elements)) selected_elements = random.sample(avail_elements, nelements) # Change some selected elements to strings for idx in range(len(selected_elements)): if idx % 3 == 1: selected_elements[idx] = bse.lut.element_sym_from_Z(selected_elements[idx]) elif idx % 3 == 2: selected_elements[idx] = str(selected_elements[idx]) bs = bse.get_basis(basis_name, elements=selected_elements) assert len(bs['elements']) == len(selected_elements) # Try to get as an integer bs = bse.get_basis(basis_name, elements=int(selected_elements[0])) assert len(bs['elements']) == 1
def test_write_basis_file_noecp(bs_name, bs_fmt, as_bz2, tmp_path): '''Test writing a basis set to a file''' tmp_path = str(tmp_path) # Needed for python 3.5 bs_data = bse.get_basis(bs_name) out_file = bse.misc.basis_name_to_filename(bs_name) out_file += bse.writers.get_format_extension(bs_fmt) if as_bz2: out_file += '.bz2' outfile_path = os.path.join(tmp_path, out_file) bse.writers.write_formatted_basis_file(bs_data, outfile_path, bs_fmt)
def test_convert_slow(basis_name, fmt_from, fmt_to, tmp_path): tmp_path = str(tmp_path) # Needed for python 3.5 # First, get the basis set in the format we want to read from bs_data = bse.get_basis(basis_name) in_file = bse.misc.basis_name_to_filename(basis_name) in_file += '.{}{}'.format(fmt_from, bse.writers.get_format_extension(fmt_from)) in_file_path = os.path.join(tmp_path, in_file) bse.writers.write_formatted_basis_file(bs_data, in_file_path, fmt_from) # Now attempt the conversion out_file_path = in_file_path + '.{}{}'.format(fmt_to, bse.writers.get_format_extension(fmt_to)) convert.convert_formatted_basis_file(in_file_path, out_file_path, fmt_from, fmt_to)
def test_duplicate_slow(bs_name, bs_ver, unc_gen, unc_seg, unc_spdf, opt_gen, make_gen): ''' Test for any duplicate data in a basis set ''' bs_dict = bse.get_basis(bs_name, version=bs_ver, uncontract_general=unc_gen, uncontract_segmented=unc_seg, uncontract_spdf=unc_spdf, make_general=make_gen, optimize_general=opt_gen) _test_duplicates(bs_dict, False)
def get_basis(self): atom_types = set([i['label'] for i in self.geometry]) zs = [ATOMIC_NUMBER[i] for i in atom_types] bs = bse.get_basis(self.basis, elements=zs) self.bs = bs basis_set = dict() orbitals = [] for element in atom_types: basis_set[element] = [] bs_data = bs['elements'][str( ATOMIC_NUMBER[element])]['electron_shells'] for shell in bs_data: exps = list(map(np.float64, shell['exponents'])) for i, momentum in \ enumerate(shell['angular_momentum']): shells = [] if momentum == 0: shells.append((0, 0, 0)) elif momentum == 1: shells.append((1, 0, 0)) shells.append((0, 1, 0)) shells.append((0, 0, 1)) elif momentum == 2: shells.append((2, 0, 0)) shells.append((0, 2, 0)) shells.append((0, 0, 2)) shells.append((1, 1, 0)) shells.append((1, 0, 1)) shells.append((0, 1, 1)) coefs = list(map(np.float64, shell['coefficients'][i])) basis_set[element].append({ 'shells': shells, 'exps': exps, 'coefs': coefs, }) self.basis_set = basis_set
def _molecularInit(self): self.Int = { "overlap": None, "kinet": None, "nucAttr": None, "twoEle": None } self.AO = [] try: basisKind = self.molecular.basis except NotImplementedError: raise NotImplementedError("No basis defined for {}".format( self.molecular.mol_name)) for index, elem in enumerate(self.molecular.atom_name_list): _elem = ELEMENTS[elem] basis = bse.get_basis(basisKind, elem, header=False) n_Obital = {"s": 0, "p": 0, "d": 0, "f": 0, "g": 0} for ele_key, ele_value in basis['elements'].items( ): # travel all elements(actually one) # store numPrime of orbitals for shell_value in ele_value[ 'electron_shells']: # travel all electron shells for i, magOrbit in enumerate( shell_value['coefficients'] ): # travel all groups of coeff angul = shell_value['angular_momentum'][i] for indexlNum, lNum in enumerate( lListDict[angulName[angul]]): n_Obital[angulName[angul]] += 1 self.AO.append( AO(id="{}_{}{}{}".format( list(self.molecular.atom_geom_dict.keys()) [index], n_Obital["s"], angulName[angul], lListNameDict[ angulName[angul]][indexlNum]), z=_elem.number, r=list( self.molecular.atom_geom_dict.values()) [index], angum=angul, l=lNum, norm=np.array([1., 1., 1.]), coef=np.array([float(i) for i in magOrbit]), expon=np.array([ float(i) for i in shell_value['exponents'] ])))
def get_basis(basis_name, elements_identity, input_format='json', output_format="matrix"): ''' Get basis values from BSE(basis_set_exchange) database. :param basis_name: str Name of the basis, such as "6-31G", "6-31+g*". It is not case sensitive. Check `basis_set_exchange.api` for more information. :param elements_identity: str or list List of elements that you want the basis set for. :param input_format: str "json" for now. :param output_format: str "matrix" as default. This defines the Output basis set format in the return value of the dict. # TODO (@saltball) Maybe before 2020/03 : More formats as interfaces to be done. Maybe numpy.array, pytorch.Tensor and so on. :return: {"element_name":[`object_of_the_basis`],...} The value of the dict depends on the parameter `output_format`. ''' if input_format == "json": basis_json = bse.get_basis(basis_name, elements_identity, fmt='json', header=False) return _resolve_basis_from_json(basis_json, output_format)
def uncontract_dfunctions(basname='3-21g', atomic_symbol='He'): """Fetch 3-21G from basis set exchange and uncontract d-functions if present.""" # Fetch basis set in NWChem format from BSE. bas = bse.get_basis(name=basname, elements=[atomic_symbol], fmt='nwchem', header=True) atom = mendeleev.element(atomic_symbol) # No need to uncontract d-functions when there are none # Note: For polarized basis sets this will not work # (3-21G does not contain polarization functions) if atom.atomic_number < 21: return bas # Get the d function exponents # (not very pretty) lines = bas.splitlines() d_exp = [] for i, line in enumerate(lines): if line.strip().startswith(atomic_symbol) and line.split()[1] == 'D': for j, subline in enumerate(lines[i:]): if atomic_symbol in subline: continue elif 'END' in subline: break else: d_exp.append(float(subline.split()[0])) break # Build the custom basis set new = [ line for line in lines if 'D' not in line.split() and 'END' not in line ][:-len(d_exp)] for e in d_exp: new.append(f'{atomic_symbol} D') new.append(f'{" "*(len(atomic_symbol)+4)}{e:.10f} {1:.10f}') new.append('END') return '\n'.join(new)
def new_atom_grid_bse(radial_precision, min_num_angular_points, max_num_angular_points, proton_charge, basis_set): bse_json = basis_set_exchange.get_basis(basis_set, elements=[proton_charge], fmt='json', header=False) data = json.loads(bse_json) max_l_quantum_number = 0 alpha_max = -sys.float_info.max alpha_min_dict = defaultdict(lambda: sys.float_info.max) for shell in data['elements'][str(proton_charge)]['electron_shells']: l = shell['angular_momentum'][0] max_l_quantum_number = max(max_l_quantum_number, l) for exponent in shell['exponents']: alpha_max = max(alpha_max, float(exponent)) alpha_min_dict[l] = min(alpha_min_dict[l], float(exponent)) alpha_min = [alpha_min_dict[l] for l in range(0, max_l_quantum_number + 1)] return new_atom_grid(radial_precision, min_num_angular_points, max_num_angular_points, proton_charge, alpha_max, max_l_quantum_number, alpha_min)
def main(): d = {} for basisset_name, meta in basis_set_exchange.get_metadata().items(): basisset = {} elements = basis_set_exchange.get_basis( basisset_name)['basis_set_elements'] try: for Z in meta['versions'][meta['latest_version']]['elements']: element = basis_set_exchange.lut.element_data_from_Z( Z)[0].capitalize() shells = elements[Z].get('element_electron_shells') if shells is None: raise ValueError('no shells: {}/{}'.format( basisset_name, element)) basisset[element] = number_of_functions(shells) except ValueError as e: print(e, file=sys.stderr) else: d[basisset_name] = basisset json.dump(d, sys.stdout)
def get_element_nbasis_map(basis_set_name: str) -> Dict[str, int]: """Returns a map of element to number of basis functions for a given basis set""" basis = bse.get_basis(basis_set_name, uncontract_general=1, header=False) element_nbasis_map = {} for atomic_nr_str in basis["elements"]: atomic_nr = int(atomic_nr_str) element = qcelemental.periodictable.to_E(atomic_nr) shells = [] for shell in basis["elements"][atomic_nr_str]["electron_shells"]: shell.pop("region") ft = shell.pop("function_type") if ft in ["gto", "gto_spherical"]: shell["harmonic_type"] = "spherical" elif ft == "gto_cartesian": shell["harmonic_type"] = "cartesian" else: raise ValueError( f"Can't determine harmonic type from function type: {ft}") shells.append(qcelemental.models.basis.ElectronShell(**shell)) element_nbasis_map[element] = sum( [shell.nfunctions() for shell in shells]) return element_nbasis_map
def element_to_num_AO(symbol, basis_set): parsed_basis_set = basis_set if basis_set.lower() == "lacvps_ecp" or basis_set.lower() == "lacvp*_ecp": atomic_num = qcel.periodictable.to_atomic_number(symbol) if atomic_num <= 18: parsed_basis_set = "6-31g*" else: parsed_basis_set = "lanl2dz" basis_str = basis_set_exchange.get_basis(parsed_basis_set, elements=[symbol], fmt='turbomole', header=False) basis_lines = basis_str.split('\n') AO = 0 for line in basis_lines: mobj = re.search(r'\s+\d+\s+[a-z]+', line) if mobj: if line.split()[1] == "s": AO += 1 if line.split()[1] == "p": AO += 3 if line.split()[1] == "d": AO += 6 return AO
def test_get_basis_fail_version(version): """Test get_basis with bad versions """ with pytest.raises(KeyError, match=r'Version .* does not exist for basis'): bse.get_basis('cc-pvdz', version=version)
def test_get_basis_fail_fmt(fmt): """Test get_basis with bad formats """ with pytest.raises(RuntimeError, match=r'Unknown basis set format'): bse.get_basis('cc-pvdz', fmt=fmt)
def test_get_basis_fail_elements(elements): """Test get_basis with bad elements """ with pytest.raises(KeyError, match=r'Element.*not found in basis'): bse.get_basis('cc-pvdz', elements=elements)
def test_get_basis_fail_name(basis_name): """Test get_basis with bad names """ with pytest.raises(KeyError, match=r'Basis set.*does not exist'): bse.get_basis(basis_name)
"lanl08+" : "LANL08+", "lanl08d" : "LANL08(d)", "lanl08f" : "LANL08(f)", "m6-31g" : "m6-31G", "may-cc-pv_q+d_z" : "may-cc-pV(Q+d)Z", "may-cc-pv_t+d_z" : "may-cc-pV(T+d)Z", "midi_bang" : "MIDI!", "midi_huzinaga" : "MIDI", "mini" : "MINI", "pv6z" : "pV6Z", "pv7z" : "pV7Z", "pvdz_ahlrichs" : "Ahlrichs pVDZ", "sto-2g" : "STO-2G", "sto-3g" : "STO-3G", "sto-4g" : "STO-4G", "sto-5g" : "STO-5G", "sto-6g" : "STO-6G", "sto-3g_star" : "STO-3G*", } import basis_set_exchange as bse for filename in conversion.keys(): print(filename) data = bse.get_basis(conversion[filename], fmt='gamess_us',uncontract_general=True,uncontract_spdf=True) with open(filename,'w') as f: f.write(data)