Skip to content

Instantly share code, notes, and snippets.

@j-wags
Created October 16, 2020 22:48
Show Gist options
  • Save j-wags/f6b52b58e0b16cf91b45df4dab5a693a to your computer and use it in GitHub Desktop.
Save j-wags/f6b52b58e0b16cf91b45df4dab5a693a to your computer and use it in GitHub Desktop.
On slots

What are slots?

  • For the System object: A way to map between applied parameters in a System and the underlying graph molecule(s)
  • For ParameterHandlers: A way to look at a Topology and determine
    • how many parameters should be assigned
    • whether one SMIRKS parameter should clobber another, or both parameters should coexist
  • In formal math: An customizable language (algebra?) for describing how to take a graph where each node has a unique index and:
    • enumerate desired graph substructures
    • define an equivalence operator for graph substructures

Where do slots appear currently?

>>> from openforcefield.topology import Molecule
>>> from openforcefield.typing.engines.smirnoff import ForceField
>>> ff = ForceField('openff_unconstrained-1.2.0.offxml')
>>> labels = ff.label_molecules(Molecule.from_smiles('C(=O)O').to_topology())
>>> for key in labels[0]:
...     print(key)
...     for key2, value2 in labels[0][key].items():
...         print(key2, value2)
... 
Bonds
(0, 1) <BondType with smirks: [#6:1]=[#8X1+0,#8X2+1:2]  id: b20  length: 1.225108345696 A  k: 1216.657338681 kcal/(A**2 mol)  >
(0, 2) <BondType with smirks: [#6X3:1]-[#8X2H1:2]  id: b17  length: 1.369205578614 A  k: 775.7511246779 kcal/(A**2 mol)  >
(0, 3) <BondType with smirks: [#6X3:1]-[#1:2]  id: b84  length: 1.085503378387 A  k: 808.4160937 kcal/(A**2 mol)  >
(2, 4) <BondType with smirks: [#8:1]-[#1:2]  id: b87  length: 0.9738225805594 A  k: 1113.990711326 kcal/(A**2 mol)  >
Angles
(0, 2, 4) <AngleType with smirks: [*:1]-[#8:2]-[*:3]  angle: 110.9462337492 deg  k: 127.9119052761 kcal/(mol rad**2)  id: a27  >
(1, 0, 2) <AngleType with smirks: [#8X1:1]~[#6X3:2]~[#8:3]  angle: 129.0541431805 deg  k: 410.9822194847 kcal/(mol rad**2)  id: a15  >
(1, 0, 3) <AngleType with smirks: [#1:1]-[#6X3:2]~[*:3]  angle: 133.1339832262 deg  k: 68.40592742547 kcal/(mol rad**2)  id: a11  >
(2, 0, 3) <AngleType with smirks: [#1:1]-[#6X3:2]~[*:3]  angle: 133.1339832262 deg  k: 68.40592742547 kcal/(mol rad**2)  id: a11  >
ProperTorsions
(1, 0, 2, 4) <ProperTorsionType with smirks: [#1:1]-[#8X2:2]-[#6X3:3]=[#8X1:4]  periodicity1: 2  periodicity2: 1  phase1: 180.0 deg  phase2: 0.0 deg  id: t100  k1: 2.237928151469 kcal/mol  k2: 1.23728649144 kcal/mol  idivf1: 1.0  idivf2: 1.0  >
(3, 0, 2, 4) <ProperTorsionType with smirks: [*:1]~[#6X3:2](=[#8,#16,#7])-[#8:3]-[#1:4]  periodicity1: 2  phase1: 180.0 deg  id: t99  k1: 2.529110648699 kcal/mol  idivf1: 1.0  >
ImproperTorsions
(1, 0, 2, 3) <ImproperTorsionType with smirks: [*:1]~[#6X3:2](~[#8X1:3])~[#8:4]  periodicity1: 2  phase1: 180.0 deg  k1: 10.5 kcal/mol  id: i2  >
vdW
(0,) <vdWType with smirks: [#6:1]  epsilon: 0.086 kcal/mol  id: n14  rmin_half: 1.908 A  >
(1,) <vdWType with smirks: [#8:1]  epsilon: 0.21 kcal/mol  id: n17  rmin_half: 1.6612 A  >
(2,) <vdWType with smirks: [#8X2H1+0:1]  epsilon: 0.2104 kcal/mol  id: n19  rmin_half: 1.721 A  >
(3,) <vdWType with smirks: [#1:1]-[#6X3](~[#7,#8,#9,#16,#17,#35])~[#7,#8,#9,#16,#17,#35]  epsilon: 0.015 kcal/mol  id: n9  rmin_half: 1.359 A  >
(4,) <vdWType with smirks: [#1:1]-[#8]  epsilon: 5.27e-05 kcal/mol  id: n12  rmin_half: 0.3 A  >

The keys in the above dictionary are our current solution to "slots". We've made our own dictionary subclasses like ValenceDict and ImproperDict with custom __keytransform__ methods which operate by canonically ordering the atom indices in each SMARTS match, such that they produce intentional key collisions. For example, a Bond SMARTS that matches particles (2,1) should collide with a previous match on (1,2). In this case, the desired algorithm is simple -- the particle indices are simply sorted.

This becomes slightly more complex for Angles, where naive sorting may mangle the identity of the central atom, which would mangle the calculation of the geometric angle. So the central atom in an Angle is "priveleged", and is immune to the sorting.

Ditto for ProperTorsions and the two central positions. However, for ProperTorsions, we encounter the complexity that, IF the outer atoms are switched by the sorting, THEN the inner atoms must also be switched.

For ImproperTorsions, the second/central atom is "priveleged", and the other three atoms are sorted. However, this sorting simply identifies the ordering for key collisions. After key collisions resolve which improper parameter should be applied, the "trefoil" rules apply the desired improper three times, each with 1/3rd of the actual k value, on three "canonical" orderings, which are determined by the Topology's indexing system. Specifically, of the six possible permutations of three non-central atoms, it selects the three where the first particle index in the tuple is smaller than the last. The selection of these three sortings is funcitonally important -- It makes the energy of the improper deterministic. If the three permutations were not assigned this way, the same geometry might yield different energies for different atom orderings.

LibraryCharges introduce the possibility of "decomposability" and "partial overlap". Partially-overlapping LibraryCharge SMARTS might be used when many molecules have a common or repeating substructure, but their charges differ for a small functional group. In effect, a LibraryCharge parameter with N tagged atoms is applied as if it had been decomposed into N separate LibraryCharge parameters with one tagged atom each.

Spec for a Slot object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment