-
Notifications
You must be signed in to change notification settings - Fork 26
Handle NAGLCharges #1206
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
Handle NAGLCharges #1206
Changes from 44 commits
0df511b
482128c
d7aa607
d8f7070
b27d68d
e592850
da7686f
6856153
d0c522d
272092a
6655de5
d0f52a4
18e7abc
2f14578
39f61ef
8abbd36
f869775
450f851
2ecb940
151e876
52d4bbd
3e2982c
3493599
93a4468
cf5e60d
cfa85d2
f1e9aa2
953798b
a76880e
75632bb
798c247
cc97617
f99a10e
f8da57e
71cbd11
d203cf3
20f7a12
c9e7599
48f5521
45ae561
cca4c67
b45e135
3625f3e
f69c249
2af90cf
1a8a4d1
1a1beda
7944479
518b8b0
9ec2ff7
4fca8fd
5676133
e60656c
d4fb4e9
3c9ff5c
281c1a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -53,7 +53,7 @@ def sage_with_bond_charge(sage): | |||||||||
| type="BondCharge", | ||||||||||
| match="all_permutations", | ||||||||||
| distance="0.8 * angstrom ** 1", | ||||||||||
| charge_increment1="0.0 * elementary_charge ** 1", | ||||||||||
| charge_increment1="0.123 * elementary_charge ** 1", | ||||||||||
| charge_increment2="0.0 * elementary_charge ** 1", | ||||||||||
| ), | ||||||||||
| ) | ||||||||||
|
|
@@ -187,6 +187,18 @@ def sage_with_off_center_hydrogen(sage): | |||||||||
| return sage | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @pytest.fixture | ||||||||||
| def sage_with_nagl_charges(sage): | ||||||||||
| sage.get_parameter_handler( | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
(blocking) this fixture should drop AM1-BCC from Sage
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, great catch. Implementing now.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented |
||||||||||
| "NAGLCharges", | ||||||||||
| { | ||||||||||
| "model_file": "openff-gnn-am1bcc-0.1.0-rc.3.pt", | ||||||||||
| "version": "0.3", | ||||||||||
| }, | ||||||||||
| ) | ||||||||||
| return sage | ||||||||||
|
|
||||||||||
|
|
||||||||||
| @pytest.fixture | ||||||||||
| def _simple_force_field(): | ||||||||||
| # TODO: Create a minimal force field for faster tests | ||||||||||
|
|
@@ -590,7 +602,6 @@ def hydrogen_cyanide_reversed(): | |||||||||
| def hexane_diol(): | ||||||||||
| molecule = Molecule.from_smiles("OCCCCCCO") | ||||||||||
| molecule.assign_partial_charges(partial_charge_method="gasteiger") | ||||||||||
| molecule.partial_charges.m | ||||||||||
| return molecule | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,12 @@ | |
|
|
||
| """ | ||
| Hierarchy is | ||
| 1. Match molceules with preset charges | ||
| 1. Match molecules with preset charges | ||
| 2. Match chemical environment against library charges | ||
| 3. Match chemical environment against charge increments | ||
| 4. Run AM1-BCC (or a variant) on remaining molecules | ||
| 3. Run NAGLCharges (if present in the FF) | ||
| 3. Run charge method in ChargeIncrementModel section (if present in the FF) and then | ||
| match chemical environment against charge increments | ||
| 4. Run AM1-BCC (or a variant) on remaining molecules (if present in the FF) | ||
|
|
||
| Test cases | ||
| ---------- | ||
|
|
@@ -86,6 +88,19 @@ | |
| * Ions get library charges | ||
| * Ligand gets charge increments | ||
|
|
||
| 11. Sage with NAGL and ligand in vacuum | ||
| * Ligand gets NAGL charges | ||
|
|
||
| 12. Sage with NAGL and water molecules (library precedence) | ||
| * Water gets library charges (precedence over NAGL) | ||
|
|
||
| 13. Sage with NAGL mixed topology (ligand and water) | ||
| * Ligand gets NAGL charges | ||
| * Water gets library charges | ||
|
|
||
| 14. Sage with NAGL and preset charges on ligand | ||
| * Ligand gets preset charges (precedence over NAGL) | ||
|
|
||
| Other details | ||
| * Specifics of charge method (AM1-BCC, AM1-BCC-ELF10, AM1-BCC via NAGL) | ||
| * Molecules with preset charges can be similar but not exact enough | ||
|
|
@@ -118,6 +133,9 @@ def map_methods_to_atom_indices(caplog: pytest.LogCaptureFixture) -> dict[str, l | |
| elif message.startswith("Charge section ToolkitAM1BCC"): | ||
| info[message.split(", ")[1].split(" ")[-1]].append(int(message.split("atom index ")[-1])) | ||
|
|
||
| elif message.startswith("Charge section NAGLCharges"): | ||
| info["NAGLChargesHandler"].append(int(message.split("atom index ")[-1])) | ||
|
|
||
| # without also pulling the virtual site - particle mapping (which is different for each engine) | ||
| # it's hard to store more information than the orientation atoms that are affected by each | ||
| # virtual site's charges | ||
|
|
@@ -149,7 +167,7 @@ def map_methods_to_atom_indices(caplog: pytest.LogCaptureFixture) -> dict[str, l | |
|
|
||
|
|
||
| @pytest.fixture | ||
| def sage_with_nagl(sage): | ||
| def sage_with_nagl_chargeincrements(sage): | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to reviewer: I changed this to disambiguate between NAGL called via ChargeIncrementModelHandler (where it tests some SMIRKS-based chargeincrement stuff as well) vs NAGLChargesHandler |
||
| from openff.toolkit.typing.engines.smirnoff.parameters import ChargeIncrementModelHandler, ChargeIncrementType | ||
|
|
||
| sage.register_parameter_handler( | ||
|
|
@@ -241,6 +259,10 @@ def ligand_and_water_and_ions(ligand, water_and_ions) -> Topology: | |
| 8.xSage with preset charges on water | ||
| 9.xSage with (ligand) virtual site parameters | ||
| 10.xAM1-with-custom-BCCs Sage with ligand and ions water | ||
| 11.xSage with NAGL and ligand in vacuum | ||
| 12.xSage with NAGL and water molecules (library precedence) | ||
| 13.xSage with NAGL mixed topology (ligand and water) | ||
| 14.xSage with NAGL and preset charges on ligand | ||
| """ | ||
|
|
||
|
|
||
|
|
@@ -416,7 +438,7 @@ def test_case9(caplog, sage_with_bond_charge): | |
| assert info["orientation"] == [0, 1] | ||
|
|
||
|
|
||
| def test_case10(caplog, sage_with_nagl, ligand): | ||
| def test_case10(caplog, sage_with_nagl_chargeincrements, ligand): | ||
| from openff.toolkit.utils.nagl_wrapper import NAGLToolkitWrapper | ||
| from openff.toolkit.utils.rdkit_wrapper import RDKitToolkitWrapper | ||
| from openff.toolkit.utils.toolkit_registry import ToolkitRegistry, toolkit_registry_manager | ||
|
|
@@ -430,7 +452,7 @@ def test_case10(caplog, sage_with_nagl, ligand): | |
| toolkit_precedence=[NAGLToolkitWrapper, RDKitToolkitWrapper], | ||
| ), | ||
| ): | ||
| sage_with_nagl.create_interchange(ligand.to_topology()) | ||
| sage_with_nagl_chargeincrements.create_interchange(ligand.to_topology()) | ||
|
|
||
| info = map_methods_to_atom_indices(caplog) | ||
|
|
||
|
|
@@ -445,3 +467,70 @@ def test_case10(caplog, sage_with_nagl, ligand): | |
|
|
||
| # the standard AM1-BCC should not have ran | ||
| assert AM1BCC_KEY not in info | ||
|
|
||
|
|
||
| def test_case11(caplog, sage_with_nagl_charges, ligand): | ||
| """Test that NAGL charge assignment is properly logged.""" | ||
| pytest.importorskip("openff.nagl") | ||
|
|
||
| with caplog.at_level(logging.INFO): | ||
| sage_with_nagl_charges.create_interchange(ligand.to_topology()) | ||
|
|
||
| info = map_methods_to_atom_indices(caplog) | ||
|
|
||
| # Should log NAGL charges for all atoms | ||
| assert "NAGLChargesHandler" in info | ||
| assert info["NAGLChargesHandler"] == [*range(0, ligand.n_atoms)] | ||
|
|
||
|
|
||
| def test_case12(caplog, sage_with_nagl_charges, water): | ||
| """Test logging when LibraryCharges takes precedence over NAGL.""" | ||
| pytest.importorskip("openff.nagl") | ||
|
|
||
| topology = Topology.from_molecules([water, water]) | ||
|
|
||
| with caplog.at_level(logging.INFO): | ||
| sage_with_nagl_charges.create_interchange(topology) | ||
|
|
||
| info = map_methods_to_atom_indices(caplog) | ||
|
|
||
| # Water should get library charges, not NAGL | ||
| assert info["library"] == [*range(0, 6)] # 2 water molecules, 3 atoms each | ||
| assert "NAGLChargesHandler" not in info | ||
|
|
||
|
|
||
| def test_case13(caplog, sage_with_nagl_charges, ligand, water): | ||
| """Test logging with mixed molecule types (some library, some NAGL).""" | ||
| pytest.importorskip("openff.nagl") | ||
|
|
||
| topology = Topology.from_molecules([ligand, water]) | ||
|
|
||
| with caplog.at_level(logging.INFO): | ||
| sage_with_nagl_charges.create_interchange(topology) | ||
|
|
||
| info = map_methods_to_atom_indices(caplog) | ||
|
|
||
| # Ligand should get NAGL charges | ||
| assert info["NAGLChargesHandler"] == [*range(0, ligand.n_atoms)] | ||
|
|
||
| # Water should get library charges | ||
| assert info["library"] == [*range(ligand.n_atoms, ligand.n_atoms + water.n_atoms)] | ||
|
|
||
|
|
||
| def test_case14(caplog, sage_with_nagl_charges, ligand): | ||
| """Test logging when preset charges are used instead of NAGL.""" | ||
| pytest.importorskip("openff.nagl") | ||
|
|
||
| ligand.assign_partial_charges("gasteiger") | ||
|
|
||
| with caplog.at_level(logging.INFO): | ||
| sage_with_nagl_charges.create_interchange( | ||
| ligand.to_topology(), | ||
| charge_from_molecules=[ligand], | ||
| ) | ||
|
|
||
| info = map_methods_to_atom_indices(caplog) | ||
|
|
||
| # Should use preset charges, not NAGL | ||
| assert info["preset"] == [*range(0, ligand.n_atoms)] | ||
| assert "NAGLChargesHandler" not in info | ||
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 needed to be a nonzero value for a nagl test, happy to make a separate fixture or put this in the test directly to avoid possible cross contamination.