Density fitted range-separated exchange

Hi all,

Thanks for all your awesome work on the Python API. Makes development of new approaches (relatively) so easy.

I did, however, notice one missing feature in the API. It is possible to compute density-fitted ERIs by evaluating:

W_df = ao_eri(NO_BASIS,DF_BASIS,ORB_BASIS,ORB_BASIS)
S_df = ao_eri(NO_BASIS,DF_BASIS,NO_BASIS,DF_BASIS)

But it is not possible to call the range-separated version, ao_erf_eri() from the Python interface. This means many modern approaches can’t be reproduced efficiently at the Python level.

Is there any move to allow access to ao_erf_eri(), in the same way as ao_eri()?

All the best,

Tim

MintsHelper.ao_erf_eri is already accessible in Python, and it has been since 1.2. While the function signature isn’t the same (rather than supply the basis sets to the function itself, you supply those to an integral factory object and then pass that to the function), the functionality is already there.

Thanks for your help. So would it be fair to assume the implicit answer to my question is ‘no’?

I figured there was likely to be a workaround. But I can’t seem to work out exactly how the process you describe works. When I try to pass an IntegralFactory to MintsHelper.ao_eri I get errors:

import psi4
import numpy as np

psi4.set_options({
    'basis':'def2-tzvp',
    'reference':'rohf',
})

psi4.geometry("""
1 1
B

symmetry c1
""")

E, wfn = psi4.energy('scf', return_wfn=True)

Basis = wfn.basisset()
DF_Basis = psi4.core.BasisSet.build\
           (wfn.molecule(),
            "DF_BASIS_SCF", "",
            "JKFIT", Basis.name())
Zero_Basis = psi4.core.BasisSet.zero_ao_basis_set()

IntFac = psi4.core.IntegralFactory\
         (Zero_Basis, DF_Basis, Basis, Basis,)
IntFac_DF = psi4.core.IntegralFactory\
            (Zero_Basis, DF_Basis, Zero_Basis, DF_Basis)

print(IntFac)

Mints = psi4.core.MintsHelper

SApq = np.squeeze(Mints.ao_eri(IntFac))
SAB = Mints.ao_eri(IntFac_DF.eri())
SAB.power(-0.5,1e-14)
WApq = np.tensordot(SAB, SApq, axes=((1,),(0,)))

yields (same with erf_eri)

<psi4.core.IntegralFactory object at 0x7f17d473bed8>
Traceback (most recent call last):
  File "erf_eri.py", line 34, in <module>
    SApq = np.squeeze(Mints.ao_eri(IntFac))
TypeError: ao_eri(): incompatible function arguments. The following argument types are supported:
    1. (self: psi4.core.MintsHelper, factory: psi4.core.IntegralFactory=None) -> psi4.core.Matrix
    2. (self: psi4.core.MintsHelper, bs1: psi::BasisSet, bs2: psi::BasisSet, bs3: psi::BasisSet, bs4: psi::BasisSet) -> psi4.core.Matrix

Invoked with: <psi4.core.IntegralFactory object at 0x7f17d473bed8>

So how would I generate the equivalent matrices?

Your original question isn’t well-formed enough to have a yes or no answer. I can read “Is there any move to allow access to ao_erf_eri(), in the same way as ao_eri()?” in two different ways.

  1. “in the same way” means with the same function signature. Then the answer is “no,” and also your implciit assumption that “this function exists somewhere in Psi4” is wrong.
  2. “in the same way” means from the Python layer, even if the function signature is different. Then the answer is “yes,” and also your stated assumption that “ao_erf_eri function doesn’t exist in Python” is wrong.

While there’s a more helpful way to word this error message, the error message is completely correct. psi4.core.MintsHelper is a class. Without a concrete instance of the class, you are not passing the self argument to the function. Try instantiating the class and then using its method.

Thanks you for you detailed explanation of the shortcomings of my original message.

Unfortunately, this does not address the shortcomings of either your first reply or your follow up - specifically the lack of detailed explanation of how I can use the target functionality from the Python API. Talking about signatures and instantiation is not terrible helpful when the classes are under-documented (which isn’t a criticism - I’d rather have more access than have less access with more docs).

I may be the first person who has struggled on this particular inconsistency in the API but I suspect I won’t be the last. So, for the record, would someone be able to answer the question a little more usefully, ideally with some of the missing code.

All the best,

Tim

You’re assuming that the code snippet you posted doesn’t work because I haven’t told you how to use the IntegralFactory based methods. That isn’t true. Your code isn’t working because you never created, i.e., instantiated, a MintsHelper object. Try print(type(Mints)) and you’ll see that Mints is the entire class, not a MintsHelper object. See Psi4Numpy tutorial if you need guidance on constructing a MintsHelper object. Fix that, and the rest should be fine.

The one technical caveat is that in more recent versions of Psi4, you may get a fatal error coming from Libint2TwoElectronInt. If that happens, consult other Psi4Numpy tutorial. Due to some backend changes, Psi4 now expects the zero basis sets in different positions when using density fitting. Yes, I know, it’s annoying.

Excellent. Thank you. Problem solved.

I did indeed forget to instantiate Mints. For anyone following at home, the below works:

import psi4
import numpy as np

psi4.set_options({
    'basis':'def2-tzvp',
    'reference':'rohf',
})

psi4.geometry("""
1 1
B

symmetry c1
""")

E, wfn = psi4.energy('scf', return_wfn=True)

Basis = wfn.basisset()
DF_Basis = psi4.core.BasisSet.build\
           (wfn.molecule(),
            "DF_BASIS_SCF", "",
            "JKFIT", Basis.name())
Zero_Basis = psi4.core.BasisSet.zero_ao_basis_set()

IntFac = psi4.core.IntegralFactory\
         (Zero_Basis, DF_Basis, Basis, Basis,)
IntFac_DF = psi4.core.IntegralFactory\
            (Zero_Basis, DF_Basis, Zero_Basis, DF_Basis)

Mints = psi4.core.MintsHelper(wfn.basisset())

SApq = np.squeeze(Mints.ao_erf_eri(0.3,IntFac))
SAB = Mints.ao_erf_eri(0.3,IntFac_DF)
SAB.power(-0.5,1e-14)
SAB = np.squeeze(SAB)
WApq = np.tensordot(SAB, SApq, axes=((1,),(0,)))