-
Notifications
You must be signed in to change notification settings - Fork 475
Arbitrary-order multipole integrals (and gradients) with McMurchie-Davidson #2496
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
Conversation
1c897f3 to
36b2171
Compare
|
Why do we have |
I don't know. There's also |
|
Back in the early days, we didn't have a generic multipole integral code. Things were just coded up as they were needed. It was quick to code up DipoleInt to get the job done. Going with @maxscheurer option (c) sounds good to me as long as it can provide both the regular and traceless variants. |
|
That's what I figured, thanks @jturney!
Generalizing the traceless version for higher-order moments is really tedious IMHO, and I don't see an immediate use case in Psi4 currently. Not even the |
|
This PR will be useful for my CFMM code :) |
I know 😄 |
Also looks like I do not need to change any of my multipole integral calls in my CFMM code too. Double bonus :) |
zachglick
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fantastic Max! I really like the generalized MultipoleInt class. I'm good with options (b) and (c). I think that DipoleInt and QuadrupoleInt classes which function as light wrappers around MultipoleInt are more user-friendly than requiring users to pluck the appropriate integrals out of the MultipoleInt return.
Have you done any performance comparisons between the new MD code and the old OS code? I don't know if one is expected to be faster than the other. It would be good to do some simple timings (maybe one low angmom system and one high angmom system?) before completely ditching the OS code.
psi4/src/psi4/libmints/mintshelper.h
Outdated
| /// Vector AO Traceless Quadrupole Integrals | ||
| std::vector<SharedMatrix> ao_traceless_quadrupole(); | ||
| /// Vector AO Multipole Integrals up to given order | ||
| std::vector<SharedMatrix> ao_multipoles(const std::vector<double>& origin = {0., 0., 0.}, int order = 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this general ao_multipoles function a lot! Could we get a comment here explaining the order that the multipoles are returned in? Would it be [x, y, z, xx, xy, xz, yy, yz, zz, xxx, ...]? You might've already written that comment somewhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the general function, too. However, order shouldn't have a default value; the caller should explicitly specify it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! But then, origin won't have a default value either if I leave the order of function arguments unchanged. Should we go for non-default values in both cases? I think this would be the most clean solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I'd switch the order. More than likely the caller will want to run it at that default origin.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about that, I wanted to keep the order as in similar mintshelper functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that sounds good @JonathonMisiewicz .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so we change the order for the multipole function already here, rest comes later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I just created an issue to change the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does having a default origin make sense, for arbitrary order multipoles? The moments are origin dependent from n+1, upwards, where n is the order of the first nonzero moment. So, e.g., the dipole is center-dependent in charged molecules but not in neutral molecules. If we're talking about allowing high orders in this function, the majority of them are going to be origin-dependent. Max already mentioned external potentials, but for things like CFMM one must also specify the expansion center (before then translating that using fancy operators). That's all a verbose way of me trying to say that I don't think either the origin or the expansion order should be given default arguments here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm all for no default values for the generalized functions (should be changed to ao_multipole_potential, too, I can do that when I add M-D for these integrals). If one is not aware that the moments are indeed origin-dependent, better throw an error than returning a probably unintended result IMHO.
For the specialized functions that are exposed via MintsHelper there is not even the possibility to change the origin, but this is fine for now I guess.
|
Hmm, I thought I had added the traceless quadrupole for @lothian years ago. If I'm completely wrong, he can certainly correct me. 😄 |
You're right, I overlooked |
|
Yes, we use the traceless quadrupole integrals for calculations of ROA spectra in ccresponse. |
@maxscheurer If you want, I can test CFMM with your new code to see if the multipole calculations are indeed faster. Just let me know. |
It's okay, I already have a script to benchmark the old code vs. the new one -- will report some of the benchmarks soon 👍 |
|
Regarding the general case |
|
The conversion to traceless form is very similar to the Cartesian->Spherical transform process and should be applied after the fact, in my opinion. We only really care about the quadrupoles for now so we can stick with that. I have some code somewhere that makes coefficients for the general case, but it's a little bit overkill to implement that, IMHO. |
That's not correct, the multipole moments start at dipole (to keep the behavior consistent with the previous OS impl). |
Ooops. I should probably have known that, given that I wrote that code in the first place! |
|
I think now that we've gathered some opinions on the |
|
I'll approve this when Zach's comments are addressed. Otherwise, this looks great! Thanks a lot for the tests. |
865bbab to
6d4a111
Compare
Small benchmarkThe following timings were obtained for H2O from 3 "takes", where in each take, the The code snippet from my benchmark script looks sth like: takes = 3
repeat = 15
for b in bas:
for m in [1, 4, 8, 16, 24, 36]:
basis = psi4.core.BasisSet.build(mol, 'orbital', b)
mints = psi4.core.MintsHelper(basis)
key = f"{b}/m = {m}"
keys.append(key)
print(key)
for _ in tqdm(range(takes)):
with timer.record(key):
for i in range(repeat):
M = mints.ao_multipoles(order=m, origin=[1.0, 2.0, 3.0])
for k in keys:
best = timer.best(k) / repeat
print(f"{k:<15} | {best * 1000:8.2f} ms")Results
|
|
Seems to me like there is no reason to keep the old OS code. The only case where it is faster is smaller basis sets in high orders, where it is unstable anyway :) |
zachglick
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the very thorough benchmark Max, LGTM!
andysim
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outstanding effort! Thanks for fixing my bug in the M recursion limit. It's really great that this PR deletes code, while adding more stable, faster integrals with derivatives and better testing. LGTM!
|
Heads-up, @edeprince3. You will need these derivative integrals. |
…vidson (psi4#2496) * multipole integrals with M-D * fix M matrix * multipole derivatives * fdiff test and some cleanup * more eq numbers * reviews * cleanup, no default origin + full tests gotcha
…vidson (psi4#2496) * multipole integrals with M-D * fix M matrix * multipole derivatives * fdiff test and some cleanup * more eq numbers * reviews * cleanup, no default origin + full tests gotcha
Description
This is the second PR of the M-D series, this time replacing the OS code for arbitrary-order multipole integrals.
Some notable points:
ao_multipolesto the Py API to conveniently call those integrals.multipole_gradwhich computes first derivatives of arbitrary-order multipole integrals (new feature!).DipoleInt(which uses l2 for dipole ints, used OS86 for derivs) is removed.dipole_gradis hard-wired tomultipole_gradwith the appropriate arguments.ToDos
Questions
Checklist
Status