Skip to content
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

Better support virtual sites plugins with vdW interactions #71

Merged
merged 16 commits into from
Jul 8, 2024

Conversation

mattwthompson
Copy link
Member

Based off of #69 and meant to coordinate with openforcefield/openff-toolkit#1837

@codecov-commenter
Copy link

codecov-commenter commented Mar 14, 2024

Codecov Report

Attention: Patch coverage is 93.24324% with 5 lines in your changes missing coverage. Please review.

Project coverage is 85.34%. Comparing base (bbc1341) to head (60f491f).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
smirnoff_plugins/collections/vsites.py 91.37% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #71      +/-   ##
==========================================
+ Coverage   84.28%   85.34%   +1.05%     
==========================================
  Files           4        6       +2     
  Lines         541      614      +73     
==========================================
+ Hits          456      524      +68     
- Misses         85       90       +5     
Flag Coverage Δ
unittests 85.34% <93.24%> (+1.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@mattwthompson
Copy link
Member Author

@jthorton could you possibly share some scripts you've used to test what you were working on? I think I'd be guessing both what kinds of virtual sites you want to test (maybe as simple as water?) but more importantly I'd probably guess the wrong numerical parameters, or pull something from the release force field

@jthorton
Copy link
Contributor

Thanks for coordinating all of this multi-branch fun Matt! I haven't managed to do any fits with these sites yet so I don't have any real values yet but I planned to use our evaluate water at distances test and move the oxygen parameters onto a v-site and check the energies are the same. Do we need to test the v-site exceptions again now they are handled by a plugin?

@mattwthompson
Copy link
Member Author

Hmm, okay, that seems simple enough. Doesn't need to be optimized - just have a 4-site water model with the vdW interactions moved to the virtual site.

What charges would you use for this models? It'd be useful, if only for testing purposes, to have something like a TIP4P variant with the charge moved onto the virtual site.

Do we need to test the v-site exceptions again now they are handled by a plugin?

Yes - the number of corner cases this sort of thing brings out means any test we can think of should be added. It wasn't that long ago I thought virtual sites would be tractable because "oh well, at least it's just the geometry and charges" 🤣

@jthorton
Copy link
Contributor

What charges would you use for this models? It'd be useful, if only for testing purposes, to have something like a TIP4P variant with the charge moved onto the virtual site.

You could use the water model from the dexp force field it has a vsite with charge.

@mattwthompson
Copy link
Member Author

An upcoming 0.16.0 should include upstream changes that make this easier!

@mattwthompson
Copy link
Member Author

This'll take a bit more work, right now the virtual sites aren't getting passed through to the Interchange collections and/or created as extra particles in OpenMM. I'll update later if I need to pass this off

@mattwthompson
Copy link
Member Author

Okay, I was doing some goofy stuff, here's a better (if artificial) water with the double exponential interaction shifted to the virtual site, overly golfed. The actual double exponential parameters aren't correctly set (somewhere in the OpenMM code) but I think the internal storage is okay. IIRC the 12-6 parameters are stored in a vdW handler, so this is consistent behavior.

In [35]: y = ForceField(
    ...:     "smirnoff_plugins/_tests/data/de-vs-1.0.1.offxml", load_plugins=True
    ...: ).create_interchange(Molecule.from_smiles("O").to_topology())

In [36]: y = ForceField(
    ...:     "smirnoff_plugins/_tests/data/de-vs-1.0.1.offxml",
    ...:     load_plugins=True,
    ...: ).create_interchange(Molecule.from_smiles("O").to_topology())

In [37]: y["DoubleExponential"].dict()
Out[37]:
{'type': 'DoubleExponential',
 'is_plugin': True,
 'expression': 'CombinedEpsilon*RepulsionFactor*RepulsionExp-CombinedEpsilon*AttractionFactor*AttractionExp;CombinedEpsilon=epsilon1*epsilon2;RepulsionExp=exp(-alpha*ExpDistance);AttractionExp=exp(-beta*ExpDistance);ExpDistance=r/CombinedR;CombinedR=r_min1+r_min2;',
 'key_map': {TopologyKey with atom indices (0,): {'id': '[#1]-[#8X2H2+0:1]-[#1]',
   'mult': None,
   'associated_handler': 'DoubleExponential',
   'bond_order': None,
   'virtual_site_type': None,
   'cosmetic_attributes': {}},
  TopologyKey with atom indices (1,): {'id': '[#1:1]-[#8X2H2+0]-[#1]',
   'mult': None,
   'associated_handler': 'DoubleExponential',
   'bond_order': None,
   'virtual_site_type': None,
   'cosmetic_attributes': {}},
  TopologyKey with atom indices (2,): {'id': '[#1:1]-[#8X2H2+0]-[#1]',
   'mult': None,
   'associated_handler': 'DoubleExponential',
   'bond_order': None,
   'virtual_site_type': None,
   'cosmetic_attributes': {}},
  VirtualSiteKey with atom indices None: {'id': '[#1:2]-[#8X2H2+0:1]-[#1:3] EP once',
   'mult': None,
   'associated_handler': 'vdw',
   'bond_order': None,
   'virtual_site_type': None,
   'cosmetic_attributes': {}}},
 'potentials': {PotentialKey associated with handler 'DoubleExponential' with id '[#1]-[#8X2H2+0:1]-[#1]': {'parameters': {'r_min': 1 <Unit('angstrom')>,
    'epsilon': 0.0 <Unit('kilocalorie / mole')>},
   'map_key': None},
  PotentialKey associated with handler 'DoubleExponential' with id '[#1:1]-[#8X2H2+0]-[#1]': {'parameters': {'r_min': 1 <Unit('angstrom')>,
    'epsilon': 0.0 <Unit('kilocalorie / mole')>},
   'map_key': None},
  PotentialKey associated with handler 'vdw' with id '[#1:2]-[#8X2H2+0:1]-[#1:3] EP once': {'parameters': {'r_min': 3.538259263094 <Unit('angstrom')>,
    'epsilon': 0.2130260271865 <Unit('kilocalorie / mole')>},
   'map_key': None}},
 'cutoff': 9.0 <Unit('angstrom')>,
 'scale_12': 0.0,
 'scale_13': 0.0,
 'scale_14': 0.5,
 'scale_15': 1.0,
 'acts_as': 'vdW',
 'periodic_method': 'cutoff',
 'nonperiodic_method': 'no-cutoff',
 'mixing_rule': '',
 'switch_width': 1.0 <Unit('angstrom')>,
 'alpha': 16.76632136164 <Unit('dimensionless')>,
 'beta': 4.426755081718 <Unit('dimensionless')>}

In [38]: y["VirtualSites"].dict()
Out[38]:
{'type': 'VirtualSites',
 'is_plugin': True,
 'expression': '',
 'key_map': {VirtualSiteKey with atom indices None: {'id': '[#1:2]-[#8X2H2+0:1]-[#1:3] EP once',
   'mult': None,
   'associated_handler': 'VirtualSites',
   'bond_order': None,
   'virtual_site_type': 'DivalentLonePair',
   'cosmetic_attributes': {}}},
 'potentials': {PotentialKey associated with handler 'VirtualSites' with id '[#1:2]-[#8X2H2+0:1]-[#1:3] EP once': {'parameters': {'distance': -0.010743 <Unit('nanometer')>,
    'outOfPlaneAngle': 0.0 <Unit('degree')>,
    'inPlaneAngle': None},
   'map_key': None}},
 'virtual_site_key_topology_index_map': {VirtualSiteKey with atom indices None: 3},
 'exclusion_policy': 'parents',
 'acts_as': 'VirtualSites'}

@mattwthompson
Copy link
Member Author

I think this is another representation of the same problem; most stuff is in place, but I don't think the virtual site is actually getting its interaction(s) set

<?xml version="1.0" ?>
<System openmmVersion="8.1.1" type="System" version="1">
	<PeriodicBoxVectors>
		<A x="2" y="0" z="0"/>
		<B x="0" y="2" z="0"/>
		<C x="0" y="0" z="2"/>
	</PeriodicBoxVectors>
	<Particles>
		<Particle mass="15.99943"/>
		<Particle mass="1.007947"/>
		<Particle mass="1.007947"/>
		<Particle mass="0">
			<LocalCoordinatesSite p1="0" p2="1" p3="2" pos1=".010743" pos2="0" pos3="-0" wo1="1" wo2="0" wo3="0" wx1="-1" wx2=".5" wx3=".5" wy1="-1" wy2="1" wy3="0"/>
		</Particle>
	</Particles>
	<Constraints>
		<Constraint d=".09572" p1="0" p2="1"/>
		<Constraint d=".09572" p1="0" p2="2"/>
		<Constraint d=".15139006545247014" p1="1" p2="2"/>
	</Constraints>
	<Forces>
		<Force cutoff=".9" energy="CombinedEpsilon*RepulsionFactor*RepulsionExp-CombinedEpsilon*AttractionFactor*AttractionExp;CombinedEpsilon=epsilon1*epsilon2;RepulsionExp=exp(-alpha*ExpDistance);AttractionExp=exp(-beta*ExpDistance);ExpDistance=r/CombinedR;CombinedR=r_min1+r_min2;" forceGroup="0" method="2" name="vdW force" switchingDistance=".8" type="CustomNonbondedForce" useLongRangeCorrection="1" useSwitchingFunction="1" version="3">
			<PerParticleParameters>
				<Parameter name="r_min"/>
				<Parameter name="epsilon"/>
			</PerParticleParameters>
			<GlobalParameters>
				<Parameter default="16.76632136164" name="alpha"/>
				<Parameter default="4.426755081718" name="beta"/>
				<Parameter default="12.339566279922" name="AlphaMinBeta"/>
				<Parameter default="6859720.941101965" name="RepulsionFactor"/>
				<Parameter default="113.67192003281576" name="AttractionFactor"/>
			</GlobalParameters>
			<ComputedValues/>
			<EnergyParameterDerivatives/>
			<Particles>
				<Particle param1=".049999999999999996" param2="0"/>
				<Particle param1=".049999999999999996" param2="0"/>
				<Particle param1=".049999999999999996" param2="0"/>
				<Particle param1="1" param2="0"/>
			</Particles>
			<Exclusions>
				<Exclusion p1="0" p2="1"/>
				<Exclusion p1="0" p2="2"/>
				<Exclusion p1="1" p2="2"/>
				<Exclusion p1="3" p2="1"/>
				<Exclusion p1="3" p2="2"/>
				<Exclusion p1="0" p2="3"/>
			</Exclusions>
			<Functions/>
			<InteractionGroups/>
		</Force>
		<Force alpha="0" cutoff=".9" dispersionCorrection="1" ewaldTolerance=".0001" exceptionsUsePeriodic="0" forceGroup="0" includeDirectSpace="1" ljAlpha="0" ljnx="0" ljny="0" ljnz="0" method="4" name="Electrostatics force" nx="0" ny="0" nz="0" recipForceGroup="-1" rfDielectric="78.3" switchingDistance="-1" type="NonbondedForce" useSwitchingFunction="0" version="4">
			<GlobalParameters/>
			<ParticleOffsets/>
			<ExceptionOffsets/>
			<Particles>
				<Particle eps="0" q="0" sig="0"/>
				<Particle eps="0" q=".53254" sig="0"/>
				<Particle eps="0" q=".53254" sig="0"/>
				<Particle eps="0" q="-1.06508" sig="0"/>
			</Particles>
			<Exceptions>
				<Exception eps="0" p1="0" p2="1" q="0" sig="0"/>
				<Exception eps="0" p1="0" p2="2" q="0" sig="0"/>
				<Exception eps="0" p1="1" p2="2" q="0" sig="0"/>
				<Exception eps="0" p1="3" p2="1" q="0" sig="0"/>
				<Exception eps="0" p1="3" p2="2" q="0" sig="0"/>
				<Exception eps="0" p1="0" p2="3" q="0" sig="0"/>
			</Exceptions>
		</Force>
		<Force energy="(CombinedEpsilon*RepulsionFactor*RepulsionExp-CombinedEpsilon*AttractionFactor*AttractionExp)*scale14;CombinedEpsilon=epsilon1*epsilon2;RepulsionExp=exp(-alpha*ExpDistance);AttractionExp=exp(-beta*ExpDistance);ExpDistance=r/CombinedR;CombinedR=r_min1+r_min2;" forceGroup="0" name="vdW 1-4 force" type="CustomBondForce" usesPeriodic="1" version="3">
			<PerBondParameters>
				<Parameter name="r_min1"/>
				<Parameter name="epsilon1"/>
				<Parameter name="r_min2"/>
				<Parameter name="epsilon2"/>
			</PerBondParameters>
			<GlobalParameters>
				<Parameter default=".5" name="scale14"/>
				<Parameter default="16.76632136164" name="alpha"/>
				<Parameter default="4.426755081718" name="beta"/>
				<Parameter default="12.339566279922" name="AlphaMinBeta"/>
				<Parameter default="6859720.941101965" name="RepulsionFactor"/>
				<Parameter default="113.67192003281576" name="AttractionFactor"/>
			</GlobalParameters>
			<EnergyParameterDerivatives/>
			<Bonds/>
		</Force>
		<Force forceGroup="0" name="PeriodicTorsionForce" type="PeriodicTorsionForce" usesPeriodic="0" version="2">
			<Torsions/>
		</Force>
		<Force forceGroup="0" name="HarmonicAngleForce" type="HarmonicAngleForce" usesPeriodic="0" version="2">
			<Angles/>
		</Force>
		<Force forceGroup="0" name="HarmonicBondForce" type="HarmonicBondForce" usesPeriodic="0" version="2">
			<Bonds/>
		</Force>
	</Forces>
</System>

@mattwthompson
Copy link
Member Author

I ought to fix this upstream first, since it's broken with or without plugins, and since fixing that should make this more straightforward: openforcefield/openff-interchange#982

@mattwthompson
Copy link
Member Author

But the example simulation starts okay looking okay (in my funky local setup):

$ cat simulation-output/data.csv                                                                                              16:17:24  ☁  base-virtual-site-type ☀
#"Step","Potential Energy (kJ/mole)","Temperature (K)","Density (g/mL)"
100,-10906.014172919473,155.37781173528475,0.8039652972777547
200,-10860.688925333205,157.04146225413606,0.809785097022985
300,-10838.49523455686,161.85410462840224,0.826788451238588
400,-10912.78376910655,189.15765928835054,0.8523825416558002
500,-10901.857441174536,198.49949300638082,0.8670032001985805
600,-10908.193866955786,206.80982010936728,0.8670032001985805
700,-10898.201851992766,214.46044370318788,0.8798556570915267
800,-10819.440363871967,203.28662489583445,0.8743064315519652
900,-10856.775256464141,212.2222783601981,0.8863845101126261
1000,-10858.09595890803,212.4440275434168,0.8937790380361453
1100,-10875.291847179455,231.42752021023406,0.8938831192406327
1200,-10889.645297451003,239.8427971003958,0.8946806067794855
1300,-10929.458118747585,251.71894964544245,0.9030271625041959
1400,-10926.600661991572,256.9277271591675,0.9099958622069644
1500,-10810.740276260622,248.19173614397172,0.9097745830518966
1600,-10861.258460740093,264.0589193131133,0.9213804590893634
1700,-10789.460166619829,257.47909100193795,0.9248263395808287
1800,-10812.948491074145,262.5282409785957,0.9277760334366735
1900,-10777.054788171023,261.3625464900893,0.923046483595719
2000,-10777.102919505996,267.97710726841945,0.9256233160489798

Comment on lines +1024 to +1025
if len(failures) > 0:
pytest.fail(f"failures at indices {failures} with energies {reported_energies}")
Copy link
Member Author

Choose a reason for hiding this comment

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

Getting this in CI:

E           Failed: failures at indices [0, 1, 2] with energies [12694.954895019531, -35.317028284072876, -23.049033522605896]

I can't wrap my head around why these should be different with the interaction on the virtual site - do these reference values need to be re-computed or is something being set incorrectly here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Any idea what's going on here @jthorton?

@mattwthompson mattwthompson reopened this Jul 8, 2024
@mattwthompson mattwthompson marked this pull request as ready for review July 8, 2024 17:22
@mattwthompson mattwthompson merged commit 559503a into main Jul 8, 2024
8 checks passed
@jthorton jthorton mentioned this pull request Jul 16, 2024
3 tasks
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.

3 participants