Follow-up: If a print out the parameters for each of the acceptor and donor pairs, I get the following:
Code: Select all
3_donor_2_acceptor
num acceptors: 12
Acceptor parameters (a1,a2,a3,params):
[0, 1, -1, (115.0, 0.2)]
[1, 2, -1, (115.0, 0.2)]
[2, 3, -1, (115.0, 0.2)]
[3, 4, -1, (115.0, 0.2)]
[4, 5, -1, (115.0, 0.2)]
[5, 0, -1, (115.0, 0.2)]
[12, 13, -1, (115.0, 0.2)]
[13, 14, -1, (115.0, 0.2)]
[14, 15, -1, (115.0, 0.2)]
[15, 16, -1, (115.0, 0.2)]
[16, 17, -1, (115.0, 0.2)]
[17, 12, -1, (115.0, 0.2)]
num donors: 24
Acceptor parameters (d1,d2,d3,params):
[0, 1, 7, (2.1,)]
[0, 5, 11, (2.1,)]
[1, 0, 6, (2.1,)]
[1, 2, 8, (2.1,)]
[2, 1, 7, (2.1,)]
[2, 3, 9, (2.1,)]
[3, 2, 8, (2.1,)]
[3, 4, 10, (2.1,)]
[4, 3, 9, (2.1,)]
[4, 5, 11, (2.1,)]
[5, 0, 6, (2.1,)]
[5, 4, 10, (2.1,)]
[12, 13, 19, (2.1,)]
[12, 17, 23, (2.1,)]
[13, 12, 18, (2.1,)]
[13, 14, 20, (2.1,)]
[14, 13, 19, (2.1,)]
[14, 15, 21, (2.1,)]
[15, 14, 20, (2.1,)]
[15, 16, 22, (2.1,)]
[16, 15, 21, (2.1,)]
[16, 17, 23, (2.1,)]
[17, 12, 18, (2.1,)]
[17, 16, 22, (2.1,)]
num exclusions: 144
energy expression: scale*k*(distance(a1,d1)-r0)^2*(angle(a1,d1,d2)-theta0)^2
<simtk.openmm.openmm.CustomHbondForce; proxy of <Swig Object of type 'OpenMM::CustomHbondForce *' at 0x7ffc35ee5930> > 12479.5535467 kJ/mol
<simtk.openmm.openmm.CMMotionRemover; proxy of <Swig Object of type 'OpenMM::CMMotionRemover *' at 0x7ffc35ee5960> > 0.0 kJ/mol
----
3_donor_3_acceptor
num acceptors: 12
Acceptor parameters (a1,a2,a3,params):
[0, 1, 2, (115.0, 0.2)]
[0, 5, 4, (115.0, 0.2)]
[1, 0, 5, (115.0, 0.2)]
[1, 2, 3, (115.0, 0.2)]
[2, 3, 4, (115.0, 0.2)]
[3, 4, 5, (115.0, 0.2)]
[12, 13, 14, (115.0, 0.2)]
[12, 17, 16, (115.0, 0.2)]
[13, 12, 17, (115.0, 0.2)]
[13, 14, 15, (115.0, 0.2)]
[14, 15, 16, (115.0, 0.2)]
[15, 16, 17, (115.0, 0.2)]
num donors: 24
Acceptor parameters (d1,d2,d3,params):
[0, 1, 7, (2.1,)]
[0, 5, 11, (2.1,)]
[1, 0, 6, (2.1,)]
[1, 2, 8, (2.1,)]
[2, 1, 7, (2.1,)]
[2, 3, 9, (2.1,)]
[3, 2, 8, (2.1,)]
[3, 4, 10, (2.1,)]
[4, 3, 9, (2.1,)]
[4, 5, 11, (2.1,)]
[5, 0, 6, (2.1,)]
[5, 4, 10, (2.1,)]
[12, 13, 19, (2.1,)]
[12, 17, 23, (2.1,)]
[13, 12, 18, (2.1,)]
[13, 14, 20, (2.1,)]
[14, 13, 19, (2.1,)]
[14, 15, 21, (2.1,)]
[15, 14, 20, (2.1,)]
[15, 16, 22, (2.1,)]
[16, 15, 21, (2.1,)]
[16, 17, 23, (2.1,)]
[17, 12, 18, (2.1,)]
[17, 16, 22, (2.1,)]
num exclusions: 144
energy expression: scale*k*(distance(a1,d1)-r0)^2*(angle(a1,d1,d2)-theta0)^2
<simtk.openmm.openmm.CustomHbondForce; proxy of <Swig Object of type 'OpenMM::CustomHbondForce *' at 0x7f6aed512930> > 12200.575102 kJ/mol
<simtk.openmm.openmm.CMMotionRemover; proxy of <Swig Object of type 'OpenMM::CMMotionRemover *' at 0x7f6aed512960> > 0.0 kJ/mol
----
3_donor_3_acceptor_switch_labels
num acceptors: 12
Acceptor parameters (a1,a2,a3,params):
[0, 1, 2, (115.0, 0.2)]
[0, 5, 4, (115.0, 0.2)]
[1, 0, 5, (115.0, 0.2)]
[1, 2, 3, (115.0, 0.2)]
[2, 3, 4, (115.0, 0.2)]
[3, 4, 5, (115.0, 0.2)]
[12, 13, 14, (115.0, 0.2)]
[12, 17, 16, (115.0, 0.2)]
[13, 12, 17, (115.0, 0.2)]
[13, 14, 15, (115.0, 0.2)]
[14, 15, 16, (115.0, 0.2)]
[15, 16, 17, (115.0, 0.2)]
num donors: 24
Acceptor parameters (d1,d2,d3,params):
[0, 1, 7, (2.1,)]
[0, 5, 11, (2.1,)]
[1, 0, 6, (2.1,)]
[1, 2, 8, (2.1,)]
[2, 1, 7, (2.1,)]
[2, 3, 9, (2.1,)]
[3, 2, 8, (2.1,)]
[3, 4, 10, (2.1,)]
[4, 3, 9, (2.1,)]
[4, 5, 11, (2.1,)]
[5, 0, 6, (2.1,)]
[5, 4, 10, (2.1,)]
[12, 13, 19, (2.1,)]
[12, 17, 23, (2.1,)]
[13, 12, 18, (2.1,)]
[13, 14, 20, (2.1,)]
[14, 13, 19, (2.1,)]
[14, 15, 21, (2.1,)]
[15, 14, 20, (2.1,)]
[15, 16, 22, (2.1,)]
[16, 15, 21, (2.1,)]
[16, 17, 23, (2.1,)]
[17, 12, 18, (2.1,)]
[17, 16, 22, (2.1,)]
num exclusions: 144
energy expression: scale*k*(distance(a2,d1)-r0)^2*(angle(a2,d1,d2)-theta0)^2
<simtk.openmm.openmm.CustomHbondForce; proxy of <Swig Object of type 'OpenMM::CustomHbondForce *' at 0x7faec108b930> > 12479.5535467 kJ/mol
<simtk.openmm.openmm.CMMotionRemover; proxy of <Swig Object of type 'OpenMM::CMMotionRemover *' at 0x7faec108b960> > 0.0 kJ/mol
----
Thus the difference between the various test cases lay in the way the acceptor/donor groups were defined. In practical application, and in contrast to the current test system, the energy expression should be uniquely defined with respect to the different choices that OpenMM could make when assigning atom indices to a1,a2, and a3. In my case, having different particlesPerAcceptor led to forcefield.py picking different (but valid) indices for a1/a2/a3, which led to different energies.
To summarize, I don't think there's a bug that needs fixing, and you can probably merge the changes to CustomHbondForce, but the 'non-unique index' issue is certainly something users should be careful of.