Skip to content

Conversation

@msricher
Copy link
Collaborator

@msricher msricher commented Nov 6, 2023

Steps

  • [ ✓ ] Write a good description of what the PR does.
  • [ ✓ ] Add tests for each unit of code added (e.g. function, class)
  • [ ✓ ] Update documentation
  • Squash commits that can be grouped together
  • Rebase onto master

Description

This is a draft pull request for adding a C interface (to Libcint) to GBasis.

Libcint (and most other C(++) codes) work by having a list of atoms, and a list of basis shells, where the atom to which a shell belongs is specified with an index (see Libcint programmer's manual). In GBasis (and IOData), I noticed that this concept is not followed, and is combined into one List[GeneralizedContractionShell] structure. This is fine, but there are some problems:

1

The Attributes section of the GeneralizedContractionShell documentation indicates that it should have a charge attribute, but this seems to be unused (it doesn't exist).

2

The IOData Shell class has this attribute:

 icenter
        An integer index specifying the row in the atcoords array of IOData object.

@leila-pujal and I have worked on exposing icenter in the GeneralizedContractionShell object, but I might need more help with that since I'm not sure where it's supposed to have been assigned, when running the test I wrote.

(Note: this has been fixed. There was confusion about whether certain quantities (atomic {numbers,coordinates}) were accessible through GBasis objects or passed as arguments to the integral functions.)

Remaining tasks

  • (DONE) Figure out how to give to my bindings the icenter and charge attributes of each atom/shell it needs.
  • Test and fix the bindings.
  • Include some more robust testing for all C-binded integrals.
  • Finalize the interface by which the C bindings are accessed instead of the Python functions.
  • Squash all the commits, rebase PR.

Can anyone give me some advice on this? (Also it's my first time making a PR, so I hope I followed the guidelines well enough.)

Type of Changes

Type
🐛 Bug fix
✨ New feature
🔨 Refactoring
📜 Docs

Related Issue

@FarnazH
Copy link
Member

FarnazH commented Nov 17, 2023

@msricher, PR #138 will fix your issue. I hope it will be merged soon.

@msricher
Copy link
Collaborator Author

@msricher, PR #138 will fix your issue. I hope it will be merged soon.

Thanks, I've rebased the fix into this branch.

@msricher
Copy link
Collaborator Author

msricher commented Nov 20, 2023

Some progress notes:

For non-segmented contractions, I can evaluate all basic integrals (overlap, nuclear-attraction, kinetic-energy, electron-repulsion) correctly. For multiple atomic centers, I don't get them in the right order, though, and I'm looking into this.

Libcint also uses chemist notation by default, so I'll need to add a way to translate to physicist notation.

Finally, segmented contractions don't work and cause libcint to segfault, so I will fix that once I've got the orderings all figured out.

@PaulWAyers also mentioned other functionality from libcint he wanted me to bind. Can get I get those written down? (See the manual.)

@msricher
Copy link
Collaborator Author

msricher commented Nov 27, 2023

One issue I still have (I think...) is the ordering of the spherical integrals.

Libcint gives component spherical ordering as in page 5 of its Programmer's Manual. For example, the ordering of the d orbitals in Libcint is xy, yz, z^2, xz, x^2-y^2. GBasis gives the spherical component ordering in the Notes in terms of m and l, with strings of "c{n}" and "s{n}".

I'm not sure how to translate between the two notations here. I've also read the IOData page, but I don't understand well enough what to do. I've left room for putting in this reordering [1], [2].

@PaulWAyers
Copy link
Member

PaulWAyers commented Nov 28, 2023

The direct Cartesian notation is sometimes used instead of the more instructive notation in terms of solid harmonics. One has to use Eq. (6) in the notes to construct it. One can work through the math, as done in Eq. (2.56) of my notes on 1-electron atoms

The easiest thing to do, probably, is to run the hydrogen atom in a huge basis set (ccpv8z should suffice; Ne with ccpv9z would go even further) with a program whose conventions are known and a program whose conventions are not known, then compute the overlap. This can be used to deduce the sign convention for the "unknown" program. This would be a useful utility to have, though it's not failsafe (one may need to put a constellation of point charges around the atom to break the symmetry and resolve the degeneracy satisfactorially.)

The general convention, though, is:

  • the number of factors of $z$ is $l - |m|$. I.e., $z^2 \leftrightarrow C_{2,m=0}$
  • if the power of x is greater than y, then one has a cosine form. Otherwise one has a sine form. I.e., $xz \leftrightarrow C_{2,m=1}$ and $yz \leftrightarrow S_{2,m=1}$.
  • if there are no factors of z, then odd functions (e.g., $xy$) are sine-like and even functions (e.g., $x^2 - y^2$) are cosine-like.

This isn't quite enough to specify the sign convention for the orbital basis, however.

According to the PySCF documentation they use the Condon-Shortley convention, which is the same thing we use in gbasis as I recall (but we should document our choice better too).

@msricher
Copy link
Collaborator Author

msricher commented Nov 29, 2023

The latest commit fixes ordering conventions for spherical and cartesian orbitals. I did, however, add this note to the code:

# NOTE: This might not capture the correct ordering of d orbitals according to the
# Libcint Programmer's Reference. It's hard to tell since they describe their
# spherical subshells in terms of {x,y,z}. Will test once ordering works.
SPH_CONVENTIONS = tuple(tuple(chain(range(2 * i, i, -1), range(0, i + 1))) for i in range(7))

This can easily be verified and fixed up if needed, once we fix problem (1.) below.

What remains is:

  1. To fix the normalization constants. I have normalized the primitive basis functions as per Libcint's reference manual, which works for the simplest cases. It doesn't match gbasis' conventions though, and so I need to figure out how to fix this.

  2. To fix generalized contractions. When I use basis sets like cc-pVDZ and ANO-RCC, the C library crashes. I think we might have to do segmented contractions individually, which is fine; I can adapt it to work, once I fix the normalization constants (to be clear on what exactly the problem is, the other problem should be solved first).

@msricher
Copy link
Collaborator Author

msricher commented Dec 1, 2023

I fixed the ordering conventions now. Libcint uses (S{l,l-1} S{l,1} ... C_{l,0} ... C_{l,l}), EXCEPT for l=1, in which case it goes (X Y Z), or (C_{1,1} S_{1,1} C_{1,0}). I forced the Libcint build to use (Y Z X).

@msricher
Copy link
Collaborator Author

msricher commented Dec 3, 2023

@PaulWAyers @FarnazH

I fixed the crash with generalized contractions! I also added proper normalization for spherical basis sets, and I believe those are correct now. We can then compare numbers: things look good, but there are some differences between GBasis' answer and Libcint's answers...
compare_cc-pVDZ.txt
These small differences mean my test won't pass, and I'm not sure why these exist. I'll try comparing against PySCF later, to see if they have the same problem (they are using Libcint, so I hope so).

I will add in the more complicated Cartesian normalization constants soon. I'm wondering if I can use shell.norm_prim_cart and shell.norm_cont to speed this up, but we'll see. I failed at writing it from scratch once.

Paul and Farnaz, if you would like to add more integrals and gradients, please see this section of the Libcint README (and the script, for examples), and list the functions you would like me to add.

@PaulWAyers
Copy link
Member

We use different recursions from libcint and so it doesn't surprise me, especially as we did not try to optimize the numerical stability of the recursions. Probably we should loosen the criteria for the tests.

If you've linked to the integrals that are currently supported in gbasis, then supporting additional integrals is low priority for now. The next ones I would imagine supporting are the 3- and 4-center overlap integrals:

We would like to be able to support analytical gradients too. This means the integrals that appear in PySCF for this would be needed.

To me, it seems like the key terms are

In the longer run, even analytic Hessians would be interesting, requiring the additional terms here.

Not all of these integrals would be required (certainly not for now, as some of them are relevant for PySCF functionality that I doubt we'll ever support). So I'd suggest making a new issue for the analytic gradient/Hessian integrals @msricher

@msricher
Copy link
Collaborator Author

msricher commented Dec 4, 2023

@PaulWAyers OK, I might need some help with identifying which integrals are which, though.

Using https://github.com/sunqm/libcint/tree/master#generating-integrals you can see what the autocode symbols mean.

Here's the autocode, which gives the names with the symbolic expressions: https://github.com/sunqm/libcint/blob/master/scripts/auto_intor.cl

And the header file which lists all the included integrals:
https://github.com/sunqm/libcint/blob/master/include/cint_funcs.h

The integrals are not given English names, and so I have a hard time knowing which is, for example, the angular momentum integral...

@msricher
Copy link
Collaborator Author

msricher commented Dec 4, 2023

@PaulWAyers I just added the functionality for Gradients and Hessians. I'm not sure what I'll test them against... probably PySCF. I still need some help with interpreting which Libcint functions we want, so could we schedule a meeting soon maybe, or something else?

@PaulWAyers
Copy link
Member

My interpretation is that the first 4 moments (powers of x,y,z) are generated by int1e_r,int1e_rr,int1e_rrr, and ``int1e_rrrr`.

The point-charge integral is, I think int1e_rinv.

The derivative integrals we support in gbasis are only supported in combinations (e.g., dot and cross products of momentum operators) in libcint. To generate up to 4th order, I think the formulas would be
( \| ip\| )) ( | ip ip| ))
( \| ip ip ip\| )) ( | ip ip ip ip | ))
which should return tensorx of 3, 3x3, 3x3x3, and 3x3x3x3 components.

The angular momentum and momentum integral (for order = 1) is I think:
'("int1e_giao_irjxp" (#C(0 1) | r cross p))`
but I'm not sure, as I don't understand the #C(0,1) notation.

@msricher
Copy link
Collaborator Author

msricher commented Dec 5, 2023

The point-charge integral is, I think int1e_rinv.

OK, great! I will add this one.

My interpretation is that the first 4 moments (powers of x,y,z) are generated by int1e_r,int1e_rr,int1e_rrr, and int1e_rrrr.

The derivative integrals we support in gbasis are only supported in combinations (e.g., dot and cross products of momentum operators) in libcint. To generate up to 4th order, I think the formulas would be ( \| ip\| )) ( | ip ip| )) ( \| ip ip ip\| )) ( | ip ip ip ip | )) which should return tensorx of 3, 3x3, 3x3x3, and 3x3x3x3 components.

We'll need to discuss how I will name these, but I have the machinery for this implemented.

The angular momentum and momentum integral (for order = 1) is I think: '("int1e_giao_irjxp" (#C(0 1) | r cross p))` but I'm not sure, as I don't understand the #C(0,1) notation.

It's the notation for complex numbers in Common Lisp. #C(X, Y) = X + iY.

@msricher
Copy link
Collaborator Author

@FarnazH @PaulWAyers

My bindings are complete now. I just have a few issues.

  1. The GBasis documentation is incomplete, so I haven't been able to figure out your exact implementations for momentum integrals, moments, etc. I got point charge integrals working, though. So let's take that as an example. Your point charge integral sums over a list of coordinates and charges, while libcint just takes one coordinate at a time and assumes a charge of 1. It was easy enough to put together a wrapper over the libcint function so that it works like yours does. As for the others, I'm having trouble. And they're all complex, which makes it difficult with my next issue...

  2. I don't think I'm slicing the arrays up in the right order when I'm casting back to np.complex from the C convention of having a double-length float double array of [Re Im Re Im Re Im...]. Again, it's hard to tell. I'm sure it's an easy fix, but I need something I can test against.

  3. I'm not sure how you want the nuclear gradients to appear. I've bound the raw libcint functions, though, and they should be working fine. We just need to settle on a more sophisticated wrapper.

  4. I just can't get the Cartesian normalization of the basis set coefficients to work.

Apart from this, everything is in good shape. I just added in all of the libcint optimizers to make the functions faster, it's easy to add functions on the Python side, and my libcint build script allows for transparent generation of arbitrary integrals using their auto-code feature.

@PaulWAyers
Copy link
Member

We should figure out the Cartesian normalization. I think it is in the (PDF) notes; admittedly the code is not (yet) documented the way it should be. Where you notice lapses in documentation, please fix it.

Where is a complex number appearing? I was not expecting complex results anywhere.

@msricher
Copy link
Collaborator Author

The GBasis momentum, angular_momentum, and moment functions all return complex arrays. Same for Libcint.

In GBasis, there's also already norm_prim_cart and norm_cont. I'm just not sure how to put them together.

If I try to do it myself, then I get lost in the notes. Going from page 2:

  • exps has shape (K,). K is the number of primitive functions.

  • a has shape (L, 3). a_{ij} = [ℓ_ix, ℓ_iy, iℓ_iz]. L is the number of Cartesian contracted functions for the given angular momentum.

  • coeffs has shape (K, M). M is the number of segmented contractions.

  • N = N1(exps, ℓ) N2(a_i).

I'm not even sure how to get the dimensions right. Where does M come in, in the above expression?

@msricher
Copy link
Collaborator Author

Oh, I think I figured it out. The ordering is just wrong now...

@msricher
Copy link
Collaborator Author

Some functions with Cartesian basis still fail. It's the cc-pVDZ/ANO-RCC ones, i.e. the ones where there are D orbitals. I'm not sure why, since it appears it's not just an ordering issue there.

@PaulWAyers
Copy link
Member

Is it true for all of the basis sets with d orbitals? Does 6-31G(d,p) fail too, for example?

@msricher
Copy link
Collaborator Author

6-31G(d,p) also fails.

So in Libcint, it says Cartesian GTOs are un-normalized. I'm only applying the radial part of the normalization to get the simpler things working. But it seems this isn't enough, going to these other basis sets.

@msricher
Copy link
Collaborator Author

I think I need to apply this second part:

    n = np.power(
        np.prod(factorial2(2 * shell.angmom_components_cart - 1), axis=1) / \
        factorial2(2 * shell.angmom - 1),
        0.5,
    )

But it has shape (L,), and I'm not sure how to apply it to the coefficients of shape (K, M)

@msricher
Copy link
Collaborator Author

I have no idea what's happening here.

tester.py:

import numpy as np

from pyscf import gto

from gbasis.parsers import make_contractions, parse_nwchem
from gbasis.integrals.libcint import CBasis
from gbasis.integrals.overlap import overlap_integral

# Disable basis normalization otherwise the basis contraction
# coefficients are scaled to meet basis normalization
gto.mole.NORMALIZE_GTO = False
ps_basis = gto.M(atom="C 0 0 0", unit="Bohr", basis="ccpvdz")
ps_int = ps_basis.intor("int1e_ovlp_cart")

atcoords = np.asarray([[0., 0., 0.]])
atsyms = ["C"]
gb_basis = make_contractions(parse_nwchem("tests/data_ccpvdz.nwchem"), atsyms, atcoords)
gb_int = overlap_integral(gb_basis, coord_type="cartesian")

gc_basis = CBasis(gb_basis, atsyms, atcoords, coord_type="cartesian")
gc_int = gc_basis.olp()

print("GBASIS")
for row in gb_int:
    print(", ".join(map("{:12.5e}".format, row)))
print("CBASIS")
for row in gc_int:
    print(", ".join(map("{:12.5e}".format, row)))
print("PYSCF")
for row in ps_int:
    print(", ".join(map("{:12.5e}".format, row)))

python ./tester.py:

[cint_new]-[michelle@t14s-g4]-[~/Git/gbasis]-% PYTHONPATH=. python tester.py
GBASIS
 1.00000e+00,  1.14697e-06,  1.87064e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  5.55459e-02,  0.00000e+00,  0.00000e+00,  5.55459e-02,  0.00000e+00,  5.55459e-02
 1.14697e-06,  1.00000e+00,  9.38107e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  6.99022e-01,  0.00000e+00,  0.00000e+00,  6.99022e-01,  0.00000e+00,  6.99022e-01
 1.87064e-01,  9.38107e-01,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  6.82951e-01,  0.00000e+00,  0.00000e+00,  6.82951e-01,  0.00000e+00,  6.82951e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 5.55459e-02,  6.99022e-01,  6.82951e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  3.33333e-01,  0.00000e+00,  3.33333e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 5.55459e-02,  6.99022e-01,  6.82951e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  3.33333e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  3.33333e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00
 5.55459e-02,  6.99022e-01,  6.82951e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  3.33333e-01,  0.00000e+00,  0.00000e+00,  3.33333e-01,  0.00000e+00,  1.00000e+00
CBASIS
 9.99999e-01,  1.14697e-06,  1.87064e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.80586e-02,  0.00000e+00,  0.00000e+00,  8.80586e-02,  0.00000e+00,  8.80586e-02
 1.14697e-06,  9.99999e-01,  9.38107e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.10818e+00,  0.00000e+00,  0.00000e+00,  1.10818e+00,  0.00000e+00,  1.10818e+00
 1.87064e-01,  9.38107e-01,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.08270e+00,  0.00000e+00,  0.00000e+00,  1.08270e+00,  0.00000e+00,  1.08270e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  9.99999e-01,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  9.99999e-01,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  9.99999e-01,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.23826e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 8.80586e-02,  1.10818e+00,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  2.51327e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  8.37758e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00
 8.80586e-02,  1.10818e+00,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  2.51327e+00,  0.00000e+00,  8.37758e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00
 8.80586e-02,  1.10818e+00,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  2.51327e+00
PYSCF
 1.00120e+00, -1.07447e-01,  1.90255e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  9.15135e-02,  0.00000e+00,  0.00000e+00,  9.15135e-02,  0.00000e+00,  9.15135e-02
-1.07447e-01,  2.47840e-01,  3.57611e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.000
00e+00,  4.79676e-01,  0.00000e+00,  0.00000e+00,  4.79676e-01,  0.00000e+00,  4.79676e-01
 1.90255e-01,  3.57611e-01,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  1.08270e+00,  0.00000e+00,  0.00000e+00,  1.08270e+00,  0.00000e+00,  1.08270e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  4.47323e-01,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  4.47323e-01,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  4.47323e-01,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  3.54984e-01,  0.00000e+00,  0.00000e+00,  1.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 9.15135e-02,  4.79676e-01,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  2.51327e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  8.37758e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  0.00000e+00
 9.15135e-02,  4.79676e-01,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  2.51327e+00,  0.00000e+00,  8.37758e-01
 0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00
 9.15135e-02,  4.79676e-01,  1.08270e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  0.00000e+00,  8.37758e-01,  0.00000e+00,  2.51327e+00

(G|C)Basis both use PY PZ PX convention, while PySCF uses PX PY PZ, but otherwise the conventions are the same. These matrices are just not the same.

@PaulWAyers
Copy link
Member

So I am a big confused.

  1. It works for s's and p's right?
  2. It doesn't work for Cartesian d's?
  3. Are Cartesian f's (and higher) also problematic, or is it specific to d's?

@msricher
Copy link
Collaborator Author

It works for S and P, not for D and F.

@msricher
Copy link
Collaborator Author

msricher commented Dec 13, 2023

D and F not working makes sense because it's where N_2(a) (from equation 2 in the notes) starts to differ from 1.
I thought libcint only wanted the radial part of the cartesian primitives (N_1(α, ℓ)) normalized, but this might not be the case. I'm just having trouble with how to apply N_2(a) to the coefficient matrix. As per my previous comment:


I think I need to apply this second part:

    n = np.power(
        np.prod(factorial2(2 * shell.angmom_components_cart - 1), axis=1),
        -0.5,
    )

But it has shape (L,), and I'm not sure how to apply it to the coefficients of shape (K, M)

Originally posted by @msricher in #137 (comment)

@PaulWAyers
Copy link
Member

Does Eq. (4) help? I would have assumed we used the normalization from this document.

@msricher
Copy link
Collaborator Author

I'll try that. I didn't have this document.

@msricher
Copy link
Collaborator Author

msricher commented Dec 14, 2023

So, (2 a_x - 1)!! (2 a_y - 1)!! (2 a_z - 1)!! = (2L - 1)!!.
Then, from the GBasis notes, Eq. (10) is equal to 1, and the spherical primitive normalization is equal to the Cartesian primitive normalization. This is what I had, and it works for S and P orbitals. That's also equivalent to Eqs. (4--5) in your notes on Google docs.

I looked at Libcint, and it says to leave the CGBFs unnormalized, but there's a flag to normalize them too. I tried a few contraction normalizations to no success.

I also can't figure out what is happening here.... none of these are the same. The only different convention is we have PY PX PZ while PySCF has PX PY PZ.

@msricher
Copy link
Collaborator Author

msricher commented Dec 14, 2023

I looked around a bit more, and saw this issue (linked here to a specific comment). This is what it means for the Cartesian integrals to not be normalized in Libcint... not that you don't need to normalize (just) the radial part, but that the result itself is unnormalized due to how Libcint works. This is fine though, since the SCF will still work and you can normalize the coefficients later using the S matrix. This is how PySCF operates.

This weirdness is due to Libcint going from sphericals to Cartesian, almost the opposite of how GBasis works, I guess. Is this fine to leave it be?

I would recommend testing the Cartesian integrals with the mean-field repo, once that's ready.

@PaulWAyers
Copy link
Member

If you talk to Shuoyang and Marco you can use the mean-field repository as we have it right now. I think it works. I'll add you to it. Right now it only has QC-SCF I think.

@leila-pujal leila-pujal self-requested a review January 15, 2024 18:56
leila-pujal
leila-pujal previously approved these changes Jan 15, 2024
Copy link
Collaborator

@leila-pujal leila-pujal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msricher and I have rebased the PR into master including all the changes that were introduced to some functions when #140 and #111 were merged. I have reviewed the code and checked that all the tests pass (except for the angular momentum ones). @FarnazH, on my side, I approve the changes. Let me know if you would like to wait for @marco-2023 and @Ali-Tehrani reviews or if you would be good to merge this into master with only mine.

@msricher
Copy link
Collaborator Author

@leila-pujal One more concern... The Github actions do not compile the C library before running the tests (and it seems it fails before even getting to Pytest). Do we want the C library and my tests to be run by Github Actions? Or is it OK as-is?

@leila-pujal
Copy link
Collaborator

you are right @msricher. I think we can still merge the PR because you added the scripts to build the libcint library so the functionality can be used once you clone the repo, install it and execute the scripts. We should include github actions to build the library but maybe that would be easier when all the PR related to github actions are merged, like #151. @Ali-Tehrani, feel free to comment on this.

@Ali-Tehrani
Copy link
Contributor

Ali-Tehrani commented Jan 16, 2024

It's better for this to be merged before and then I can add testing it with GIthub actions within that pull-request #151. It also makes it easier for me to fix the merge conflicts.

I'm assuming that libcint is optional and if so, I'll have to figure out how to exclude it's test in that case.

@msricher
Copy link
Collaborator Author

Yes, building Libcint is only required for gbasis.integrals.libcint and the tests in tests/test_libcint.py.

@msricher
Copy link
Collaborator Author

btw @Ali-Tehrani @leila-pujal, the pyproject.toml (which doesn't seem to work yet?) must ensure that the gbasis/integrals/lib/libcint.so* files are included with the gbasis library when it is installed via pip (or via anything else). I put in the relevant lines in pyproject.toml, but couldn't test it. Can we keep this in mind for when we finish the pyproject.toml?

@PaulWAyers
Copy link
Member

For the angular momentum, the right values are:

$$ \begin{align} -i \braket{y|x \partial_y - y \partial_x|x} &= +i \\ -i \braket{x|x \partial_y - y \partial_x|y} &= -i \\ +i \braket{x|z \partial_x - x \partial_z|z} &= -i \\ +i \braket{z|z \partial_x - x \partial_z|x} &= +i \\ -i \braket{z|y \partial_z - z \partial_y|y} &= +i \\ -i \braket{y|y \partial_z - z \partial_y|z} &= -i \end{align} $$

@msricher can you say which states are which in the data you are printing? I presume that the three columns are Lx, Ly, Lz, but I'm not sure the order of elements in the rows.

@msricher
Copy link
Collaborator Author

msricher commented Jan 17, 2024 via email

@msricher
Copy link
Collaborator Author

As per Paul's comment in #149, maybe we should just leave out the angular momentum function for now? I will push a commit adding a NotImplementedError onto that function, and then it should be ready to merge if the reviews are ok.

@msricher
Copy link
Collaborator Author

@leila-pujal @Ali-Tehrani @marco-2023 can this be merged? I could start a new PR for the nuclear gradients once it's been merged.

@leila-pujal
Copy link
Collaborator

I am good with this. If no one has an objection to it I will merge this at the end of today. @Ali-Tehrani, @marco-2023, @FarnazH, @PaulWAyers.

@leila-pujal leila-pujal self-requested a review January 23, 2024 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants