-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite read-in of SAD guess #345
Comments
This script will generate basis+density in JSON file for all the elements known to a given basis set: import argparse
import json
from pathlib import Path
import basis_set_exchange as bse
import numpy as np
import psi4
# build custom basis
def define_custom_basis(name: str, basis: str, molecule, role: str):
molecule.set_basis_all_atoms(name, role=role)
return {
name: basis,
}
def generate_guess(basis_name):
# loop over all elements in basis set and run an atomic calculation
for el, bas in bse.get_basis(basis_name, elements=[8])["elements"].items():
symbol = bse.lut.element_sym_from_Z(el, normalize=True)
print(f"==> Running atomic calculation for {symbol}")
psi4.core.set_output_file(f"sad_{symbol}.out")
mol = psi4.geometry(
f"""
{symbol} 0.0 0.0 0.0
symmetry c1
noreorient
no_com
"""
)
psi4.core.set_active_molecule(mol)
# get basis in Psi4 format
custom_name = f"{basis_name}_BSE"
p4b = bse.get_basis(basis_name, elements=[el], fmt="psi4")
psi4.qcdb.libmintsbasisset.basishorde[
custom_name
] = lambda m, r: define_custom_basis(basis_name, p4b, m, r)
psi4.set_options(
{
"SCF_TYPE": "PK",
"D_CONVERGENCE": 1e-10,
"REFERENCE": "UHF",
"BASIS": custom_name,
}
)
try:
e, w = psi4.energy("SCF", return_wfn=True)
except:
print(f" !!! Calculation for {symbol} did not converge!")
continue
# density as NumPy array
D = w.Da().to_array() + w.Db().to_array()
# set elements smaller than 1e-13 in absolute value to zero
zeroes = np.abs(D) <= 1e-13
D[zeroes] = 0.0
output = Path(f"{symbol}.json")
with output.open("w") as f:
json.dump(
{
"basis": bas,
"density": [x for _ in D.tolist() for x in _],
},
f,
indent=4,
)
psi4.core.clean_options()
psi4.core.clean()
if __name__ == "__main__":
cli = argparse.ArgumentParser()
cli.add_argument("basis", help="name of the basis set")
args = cli.parse_args()
print(f"Using basis set {args.basis}")
generate_guess(args.basis) can be used as:
|
FWIW I'm planning a modular atomic solver library compatible with the BSE, which can be integrated in any QM codes for on-the-fly SAD, for instance. |
btw what is the "hydrogenic basis" used with the SAD guess? |
That sounds great @susilehtola, we'll definitely be looking into that. We need to increase the level of sophistication of our initial guess solver (see next point).
These are literally the eigenfunctions of the hydrogen atom. Our SAD procedure is the following:
|
OK. Hydrogenic functions are a very bad basis set; you might look into using e.g. my HGBS Gaussian basis sets instead which are available for the whole periodic table and are obtained from simple physical arguments. I would not use a correlation functional for the SAD guess, since we looked into this question in J. Chem. Phys. 152, 144105 (2020) and found out that exchange-only calculations yield essentially the same - if not better - result. It sounds like you might also be very interested in another key feature of the atomic solver: getting numerical AOs for the atom. |
Another useful feature would be the ability to read in formatted checkpoint files, since they can be produced by a variety of quantum chemistry programs. What would it take to make this happen? |
Yes, up to this point we have only been concerned with getting somewhere in the vicinity of the solution with our guess, so that our SCF is able to find the correct solution (not always the case, still). We have not bothered yet with optimizing the guess for performance in terms of reducing the number of SCF iterations. Numerical AOs would be great, combined with SAD or SAP. Will these AOs come in the form of a 1D numerical radial function combined with standard spherical harmonics, or fully 3D numerical? Is the code to generate these available already, and how would the interface look? Can we directly get callable C++ objects that can be evaluated in arbitrary 3D grid points, or would we need some interpretation on our side, like interpolation on radial grid values etc? |
Reading checkpoint files could be useful, I agree |
The more I have thought about this, the more it looks like I should just use what I have in HelFEM already, since it appears the design decisions I made early on about the fully flexible LCAO approach is something that is of interest for future efforts as holes in the valence shell will also polarize the core orbitals. I need to refactor the code to make it more general by removing assumptions about the radial basis set; I'll also want Gaussians and Slater-type orbitals and support for ECPs. For initial guess purposes, the AOs will indeed be of the form psi_{nlm} (r) = R_{nl) (r) Y_{lm} (r), where the radial functions are evaluated within the module. The code will also be able to evaluate the SAP potential Vsap(r) and the electron density n(r) without the need for extra interpolation. I don't yet know what would be the best strategy to implement SAD; should it be in the library itself or be left outside. The Coulomb matrix is the same in both SAP and SAD and can be easily evaluated by summing the atomic radial potentials. The only difference between the two is the exchange potential, which is linear in SAP (sum of atomic radial potentials) whereas in SAD it's given by the potential of the atom-summed densities at each grid point. Maybe SAD does need to be left to downstream codes, since the grids will be different in each code... However, being able to evaluate the atomic orbitals will still be important, since you need those to construct the numerical minimal basis in many approaches. HelFEM is in C++ but uses Armadillo; I recently started considering porting it to Eigen3. In order to facilitate the new modular code's inclusion in quantum chemistry packages, it needs to have minimal dependencies (Eigen3 and libxc and/or possibly xcfun), and be callable from C and Fortran at minimum; a Python interface would also be really useful. |
Here's a script that uses spherically averaged spin-restricted Hartree-Fock in PySCF with the correct ground-state occupations from finite-element calculations I published a few years ago.
The issue here is that you need to make sure that the basis functions are normalized in the same way and ordered in the same way. This may not be the same in every program. However, the code above uses full spherical averaging, so the densities are correctly spherically symmetric. I think PySCF needed some hacks to get the heaviest atoms to converge; I needed to make a multi-step algorithm to converge the NRSRHF calculations with the hydrogenic Gaussian basis sets I published a few years ago. |
... but I assume the bigger problem at the moment may be the use of the hydrogenic atomic orbitals which are a very incomplete basis set... |
Also, the discussion on read-in SCF guesses already turned into a larger question of interoperability between quantum chemistry codes, see the discussion I started on the computational chemistry list. MRChem could be a prime candidate for early adoption, no? |
Absolutely, I would be very interested in this. An alternative approach for us could be to implement the SAD solver in Python using our MRCPP interface [VAMPyR]](https://github.com/MRChemSoft/vampyr), in combination with some GTO library to get proper AO functionality which is currently missing (or sloppily implemented, at best) in MRChem. |
... but that would require extra development effort. As an easier alternative, how about implementing SAP in MRChem? I have tabulated LDA potentials in https://github.com/susilehtola/HelFEM/blob/master/src/general/sap.cpp. You should be able to use these in the Helmholtz solver to get decent guess orbitals... |
Currently the SAD guess is read from 2 files:
O.bas
O.dens
The two can be unified into a single JSON file
O.json
that contains both the basis and the corresponding atomic density. The basis can be taken directly from the Basis Set Exchange (BSE), see here for 3-21G of oxygen. The density can be computed with any code. The JSON would have to keys:In the C++ code one needs to:
from_json
to theAOBasis
class to parse the basis as copy-pasted from the BSE.project_density
such that it reads thedensity
field of the JSON file.The advantages of this approach are that:
On top of the C++ changes there should be machinery to generate the SAD guesses in JSON format. This can be nicely achieved with Psi4 and the BSE Python library. Note that I haven't tested the following script:
The text was updated successfully, but these errors were encountered: