-
Notifications
You must be signed in to change notification settings - Fork 475
SAPT(DFT) auto compute GRAC #3232
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
|
Rebase when #3256 is merged in (there will be a merge conflict), and then ping me for review. Apologies for not reviewing this earlier. |
Hello @JonathonMisiewicz, since #3256 is now merged into master, I thought that I would notify you. This PR should likely be merged before my SAPT(DFT) External Potential #3257. Please let me know if there are any necessary changes or concerns. Thanks for your help! |
JonathonMisiewicz
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.
I was looking at your PRs out of order. My mistake.
tests/pytests/test_saptdft.py
Outdated
| compare_values( | ||
| # STO-3G target | ||
| 0.19807358, | ||
| # aug-cc-pvdz target, 0.1307 (using experimental IP from CCCBDB) |
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 don't understand this comment. Are the aug-dz and quasi-experimential numbers both provided here? Please elaborate so it's comprehensible to non-specialists.
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 a good point. I have included docstrings for both grac tests to clarify these values.
@pytest.mark.saptdft
def test_saptdft_auto_grac_iterative():
"""
For SAPT(DFT), one must compute a GRAC shift for each monomer. Ideally,
this GRAC shift should be close to the experimental Ionization Potential
(IP) of the monomer. While the present test targets STO-3G, the IP for
water is 0.1307. Note that using aug-cc-pVDZ, the computed GRAC shift is
0.13063798506967816, which is close to the experimental value.
"""
psi4/src/read_options.cc
Outdated
| options.add_double("SAPT_DFT_GRAC_SHIFT_B", 0.0); | ||
| /*- SAPT_DFT_GRAC_CONVERGENCE_TIER will specify how hard psi4 should | ||
| try to converge the cation for a GRAC shift before failing the | ||
| calculation completely -*/ |
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.
Describe single and iterative... Also, it may be worth updating the SAPT(DFT) section of the documentation to describe this.
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 have updated the description to be:
/*- SAPT_DFT_GRAC_CONVERGENCE_TIER will specify how Psi4 should
try to converge the cation for a GRAC shift before failing the
calculation completely. "SINGLE" will try only once to converge
the cation for computing a GRAC shift. "ITERATIVE" will set adjust
local Psi4 options ("LEVEL_SHIFT", "LEVEL_SHIFT_CUTOFF") to attempt
to converge the neutral/cation calculations. "ITERATIVE" will
try 3 times to converge the cation before failing the SAPT(DFT)
computation. -*/
| sapt_dimer = ref_wfn.molecule() | ||
|
|
||
| if do_mon_grac_shift_A or do_mon_grac_shift_B: | ||
| monA = sapt_dimer.extract_subsets(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.
Why do both monA and monomerA exist? I suspect that one of them needs to be renamed.
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 split these into two different molecules because monomerA sets monomerB as ghosts; however, I want monA to not have ghost atoms to correctly compute the GRAC shift independent of the dimer. I can see how this is confusing, so perhaps I name it monA_grac?
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.
That tells us what function uses it but not what it is. monomerA_all_bf, perhaps?
|
|
||
| def compute_GRAC_shift( | ||
| molecule, sapt_dft_grac_convergence_tier="SINGLE", label="Monomer A" | ||
| ): |
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.
Are you sure you formatted this properly? Splitting parentheses across different lines so often is jarring.
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 am using ruff's formatting defaults, but I will put all arguments on a single line if this is more preferable.
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.
We have an (inactive?) PR to add Ruff formatting, #3234. The default Ruff formatting here is against the usual Psi4 style. I'm opposed to this, but a second opinion from another developer is good on style questions.
Including the Ruff formatting also made your PR harder to read, because now I need to separate out your code changes from your formatting changes.
| mon_b_shift=None, | ||
| do_delta_hf="N/A", | ||
| jk_alg="N/A"): | ||
| def sapt_dft_grac_convergence_tier_options(): |
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.
Why have a function for this? This should be a module-level variable, no?
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 agree that making it a module-level variable makes more sense.
| print(f"{grac_options = }") | ||
| for options in grac_options: | ||
| for key, val in options.items(): | ||
| core.set_local_option("SCF", key, val) |
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.
How are you restoring these options to default later? Looking at the code, I can't see how you do 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.
I was under the impression that optstash.restore() performs the resetting of options to the defaults; however, I did not all options that should be stored at the top of the function. Thank you for pointing this out.
Co-authored-by: Jonathon Misiewicz <[email protected]>
tests/pytests/test_saptdft.py
Outdated
|
|
||
|
|
||
| @pytest.mark.saptdft | ||
| def test_saptdft_auto_grac(): |
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.
These two tests are duplicates. Change them into one parameterized test.
psi4/src/read_options.cc
Outdated
| /*- SUBSECTION SAPT(DFT) -*/ | ||
|
|
||
| /*- Monomer A GRAC shift in Hartree -*/ | ||
| /*- Monomer A GRAC shift in Hartree. Set to -99 to automatically |
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 don't like having -99 as a magic number. I'm open to other opinions, but perhaps "DFT_GRAC_CONVERGENCE_TIER" should be renamed to "DFT_GRAC_COMPUTE" and take a "USER" value to specify that Psi should read these options.
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, I also disliked a magical number; however, it seemed like a compromise for functionality of computing a grac shift for monomer A but not requiring it for monomer B and vice versa. I wouldn't want to force a user to compute a GRAC shift if they already have a shift for one of the monomers.
Perhaps this could be fixed by making SAPT_DFT_GRAC_SHIFT_A's default value of 0.0 enable "SAPT_DFT_GRAC_CONVERGENCE_TIER" (or the renamed form of "DFT_GRAC_COMPUTE") to "SINGLE" and enabling auto grac for A? Same logic would apply for monomer B.
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.
That's a good idea, though I'd adjust the details slightly. If SAPT_DFT_GRAC_SHIFT_A is set (there's a special options method for that), we trust the user-provided value. Otherwise, we use the algorithm in SAPT_DFT_GRAC_CONVERGENCE_TEST. As you said, same logic applies for monomer B.
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.
Oh, I was not aware of this special option... I just made a commit that checks to make sure the user has set the now "SAPT_DFT_GRAC_COMPUTE" variable to "SINGLE" or "ITERATIVE" from the default "NONE" in combination with SAPT_DFT_GRAC_SHIFT_A to 0.0. This might be similar to what you just recommended in functionality by ensuring that the user MUST request automatic GRAC shifts. The older error message of grac shifts being 0.0 and performing DFT has been updated to tell the user how to call the automatic GRAC shift computation.
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.
It's best to query core.has_option_changed in a case like this... That way, we don't have to worry about how close is close enough, or what if the user set it to 0 manually.
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, I agree that the "how close is close enough" is unsettling to use in practice; however, does this core.has_option_changed approach block users from running multiple SAPT(DFT) calculations in a row from one python script? For instance, compute_GRAC_shift() has to set "SAPT_DFT_GRAC_SHIFT_A" for later usage in the code. If I understand correctly, core.has_option_changed would now be triggered, effectively blocking the next SAPT(DFT) calculation from also automatically computing GRAC shifts. Is there a clean way to allow multiple auto GRAC SAPT(DFT) calls in a single python script to work correctly?
I largely ask because my high-throughput workflow would encounter this issue.
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.
optstash.restore will restore the has_changed state from stash time.
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.
Oh excellent, I have made this change to agree with the has_changed format. Thank you for your patience and quick responses on this issue!
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.
That's what happens on a day when I'm waiting on cluster jobs to finish. By all means, test that your workflow still works after this change.
|
|
||
| def compute_GRAC_shift( | ||
| molecule, sapt_dft_grac_convergence_tier="SINGLE", label="Monomer A" | ||
| ): |
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.
We have an (inactive?) PR to add Ruff formatting, #3234. The default Ruff formatting here is against the usual Psi4 style. I'm opposed to this, but a second opinion from another developer is good on style questions.
Including the Ruff formatting also made your PR harder to read, because now I need to separate out your code changes from your formatting changes.
| sapt_dimer = ref_wfn.molecule() | ||
|
|
||
| if do_mon_grac_shift_A or do_mon_grac_shift_B: | ||
| monA = sapt_dimer.extract_subsets(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.
That tells us what function uses it but not what it is. monomerA_all_bf, perhaps?
Co-authored-by: Jonathon Misiewicz <[email protected]>
Co-authored-by: Jonathon Misiewicz <[email protected]>
loriab
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.
Looking good
Co-authored-by: Lori A. Burns <[email protected]>
Co-authored-by: Lori A. Burns <[email protected]>
loriab
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.
Hopefully the last pass. :-) Maybe add that violin plot of the neutral vs. given charge schemes to the PR discussion so it gets preserved.
| }, | ||
| { | ||
| "LEVEL_SHIFT": 0.01, | ||
| "LEVEL_SHIFT_CUTOFF": 0.01, |
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.
Having level_shift and its cutoff at the same value is unusual (grep of tests below). Should this be revised?
tests/scf-level-shift-cuhf/input.dat:set level_shift 0.5
tests/scf-level-shift-cuhf/input.dat:set level_shift_cutoff 1e-3
tests/scf-level-shift-rks/input.dat:set level_shift 5.0
tests/scf-level-shift-rohf/input.dat:set level_shift 0.7
tests/scf-level-shift-rohf/input.dat:set level_shift_cutoff 1e-4
tests/scf-level-shift-uhf/input.dat:set level_shift 0.5
tests/scf-level-shift-uhf/input.dat:set level_shift_cutoff 1e-5
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 a fair point. I will adjust these variables and run through some harder systems to converge to see how they perform. I ran about 4500 dimers with computing GRAC shifts with various level_shift and level_shift_cutoff values that will inform these updates. I am going to test using new values on a dataset before finalizing this response.
| ) | ||
|
|
||
| core.set_variable("SAPT DFT GRAC SHIFT A", mon_a_shift) # P::e SAPT | ||
| core.set_variable("SAPT DFT GRAC SHIFT B", mon_b_shift) # P::e SAPT |
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.
don't forget the glossary.rst entries
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.
Would this be |sapt__sapt_dft_grac_shift_a| to |sapt__sapt dft grac shift a|?
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, those two vars, but they'll look like the below. And put them somewhere in the SAPT area since the file doesn't alphabetize.
.. psivar:: SAPT DFT GRAC SHIFT A
SAPT DFT GRAC SHIFT B
The gradient-corrected ... [E_h] ...
Co-authored-by: Lori A. Burns <[email protected]>
|
Next commit make this change to fix the Eco (W) lane, https://github.com/psi4/psi4/pull/3302/files#diff-9886b1fe077112c3a9952964ed992dc3cd38b48d0a506a6b7a00241e4669d2b1R192 . Will watch the dftgrac error on Azure to see if it repeats. |
loriab
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.
Few little tweaks that can be incorporated after other review, but lgtm. Thanks!
Co-authored-by: Lori A. Burns <[email protected]>
Co-authored-by: Lori A. Burns <[email protected]>
JonathonMisiewicz
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.
At risk of curmudgeonliness, please do format passes as a separate PR, for the sake of the reviewers.
I have a minor suggestion to clarify the docs but LGTM otherwise.
Co-authored-by: Jonathon Misiewicz <[email protected]>
Description
I have added an option to compute the necessary GRAC shifts for SAPT(DFT) automatically. I added a little extra logic to "try harder" at converging cations to hopefully fail less often if this option is specified. These changes will enable more users to call SAPT(DFT) more routinely in their workflows without having to consider acquiring GRAC shifts externally through their own logic or tabulated sources.
User API & Changelog headlines
Dev notes & details
Questions
Checklist
Status