-
Notifications
You must be signed in to change notification settings - Fork 23
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
Partial charge assignment using charge_from_molecules
on virtual sites / charge increments can be unexpected.
#1050
Comments
Pre-charged waters sounds like a strange use case; I don't have grounds to forbid it, but it'll really stress what's documented and easy to work with. Just documenting the quirks is a last resort, I'd like things to work more smoothly and in line with SMIRNOFF and user expectations if possible. Before getting to that, though, is your reproduction missing a from openff.toolkit import Molecule, ForceField
from openmm import NonbondedForce
water = Molecule.from_smiles("O")
water.assign_partial_charges(partial_charge_method="gasteiger")
print(
f"Partial charges on molecule: {[round(charge, 3) for charge in water.partial_charges]}"
)
# Partial charges on molecule: [<Quantity(-0.41, 'elementary_charge')>, <Quantity(0.205, 'elementary_charge')>, <Quantity(0.205, 'elementary_charge')>]
ff = ForceField("openff-2.2.0.offxml", "opc.offxml")
system = ff.create_interchange(water.to_topology()).to_openmm_system()
nonbond = [f for f in system.getForces() if isinstance(f, NonbondedForce)][0]
# Get the parameters for the first water oxygen
print(
f"Partial charge in system: {round(nonbond.getParticleParameters(0)[0]._value, 3)}"
)
# Partial charge in system: 0.0 |
Ah yeah sorry, I was playing around with and without and copied the wrong thing 😅 - I've edited the originall comment! |
The use case I have here is that I'm writing this thing where users can optionally define their solvent molecules.. and well in some cases the solvent can be water 😅 (see: https://github.com/IAlibay/pontibus/blob/develop/src/pontibus/utils/system_creation.py). You could say this is "intentionally" pushing things, because the intended users are.. well you folks. A question - is this really much different than how ligands with vsites will behave? I.e. would you expect users to more easily know how the offsite charge is being incremented? |
Upon some reflection ... this is quite a mess and I'm not totally sure how to proceed. At best, Interchange handles this poorly. At worst, SMIRNOFF doesn't handle it well. I'm looking to get #1048 done before this, which may help! Two things are referred to as "charge increments":
Looping back to the original case (preset water charges passed along with a 4-site water model), I'm not totally sure what should happen here. The current implementation sees a match in (preset charges)
(virtual sites)
Snipping out just the relevant bits of
I can think of only two possible expectations here:
(1) seems bad but is also confusing since the interaction between preset charges and virtual sites seems ambiguous/under-defined. I think you're expecting (2) here? |
From my likely poor understanding of the spec, yes. At least as a user I would expect the same behaviour you would expect with ligands. As far as I'm aware this is the behaviour that you get in practice, it just isn't immediately clear as a user that this is happening (or even that you have virtual sites for that unique molecule). |
Unfortunately, I'm in a position where I think this is underspecified and I need updates to the SMIRNOFF spec to proceed: openforcefield/standards#69 I originally hoped this was limited to your (IMO) esoteric case of passing water through to cc: @lilyminium @j-wags |
I commented on the SMIRNOFF spec with my opinion that I would also expect 2) in this scenario and that I think that's the best option.
Does the Something like:
|
Sure, it's sorta what I've been doing-ish, but from the docs it's really unclear that this is how you're meant to do things. I would suggest doing some kind of cookbook or userguide example maybe? (unless I'm being oblivious and missing one). |
Modifying charges after the fact is something that should be straightforward but probably only I am familiar with the sharp edges and we haven't really documented it well. I think it's a fair use case, but it's partially in tension with the design that a force field includes instructions on how to assign partial charges (and, by deduction, not whatever else is brought to the table). Tracked so I don't forget: #1071 |
Description
Related to #1048
When building a system with OPC water, if a user passed along a pre-charged water, they might end up with an unexpected set of partial charges in the resultant 4 point molecule due to charge increments.
The behaviour isn't incorrect according to the spec, but you then also have to expect users to a) know the charge assignment order in the spec, b) remember that there are charge increments affecting the molecule they passed charges for, c) do the charge increment math ahead of time to make sure they passed along the right charges.
I'm not 100% sure, but I think the ask would be something along the lines of:
charge_from_molecules
will ignore library charges, but b) charge increments will be applied (this is not clear from the existing docs).Reproduction
Output
partial charges
particle parameters for oxygen (in OPC this is a zero charged atom since all the charge is on the virtual site)
The text was updated successfully, but these errors were encountered: