Task: Serialization proxy for ATMForce did not record the particles (openmm/openmm#4317)

org: openmm
repo: openmm
pr_number: 4317
issue_title: Serialization proxy for ATMForce did not record the particles
issue_body: Fixes #4316.
resolved_issues: number: 4316
title: `ATMForce` SIGSEGV's after copying / serialization
body: Copying (or serializing / deserializing) a system that contains an ATM force, and then using that system in a context yields a segfault:

```
import openmm

nb_force = openmm.NonbondedForce()
nb_force.addParticle(0.0, 1.0, 1.0)

atm_force = openmm.ATMForce(0.0, 0.0, 0.0, 0.0, 0.0, 100.0, 50.0, 1.0 / 16.0, 1)
atm_force.addParticle(openmm.Vec3(0.0, 0.0, 0.0))
atm_force.addForce(nb_force)

system = openmm.System()
system.addParticle(1.0)
system.addForce(atm_force)

system = openmm.XmlSerializer.deserialize(openmm.XmlSerializer.serialize(system))

context = openmm.Context(system, openmm.VerletIntegrator(1.0))
context.setPositions([openmm.Vec3(0.0, 0.0, 0.0)] * openmm.unit.angstrom)

print(context.getState(getEnergy=True).getPotentialEnergy(), flush=True)
```

removing the `system = openmm.XmlSerializer.deserialize(openmm.XmlSerializer.serialize(system))` line yields an energy of 0.0 as exepcted without any segfaults.

## IMPORTANT INSTRUCTIONS

1. If you edit a python file, you MUST run 'make PythonInstall' inside the build directory
2. If you edit a c++ file, you MUST run 'make -j4 && make install" inside the build directory

Reference solution:
fix_patch: diff --git a/serialization/src/ATMForceProxy.cpp b/serialization/src/ATMForceProxy.cpp
index d86cbd4a50..75d70fb6f8 100644
--- a/serialization/src/ATMForceProxy.cpp
+++ b/serialization/src/ATMForceProxy.cpp
@@ -60,6 +60,13 @@ void ATMForceProxy::serialize(const void* object, SerializationNode& node) const
         SerializationNode& f = forces.createChildNode("Force");
         f.createChildNode("Force", &force.getForce(i));
     }
+    SerializationNode& particles = node.createChildNode("Particles");
+    for (int i = 0; i < force.getNumParticles(); i++) {
+        Vec3 d1, d0;
+        force.getParticleParameters(i, d1, d0);
+        particles.createChildNode("Particle").setDoubleProperty("d1x", d1[0]).setDoubleProperty("d1y", d1[1]).setDoubleProperty("d1z", d1[2])
+                .setDoubleProperty("d0x", d0[0]).setDoubleProperty("d0y", d0[1]).setDoubleProperty("d0z", d0[2]);
+    }
 }
 
 void* ATMForceProxy::deserialize(const SerializationNode& node) const {
@@ -80,6 +87,10 @@ void* ATMForceProxy::deserialize(const SerializationNode& node) const {
         const SerializationNode& forces = node.getChildNode("Forces");
         for (auto& f : forces.getChildren())
             force->addForce(f.getChildren()[0].decodeObject<Force>());
+        const SerializationNode& particles = node.getChildNode("Particles");
+        for (auto& p : particles.getChildren())
+            force->addParticle(Vec3(p.getDoubleProperty("d1x"), p.getDoubleProperty("d1y"), p.getDoubleProperty("d1z")),
+                               Vec3(p.getDoubleProperty("d0x"), p.getDoubleProperty("d0y"), p.getDoubleProperty("d0z")));
         return force;
     }
     catch (...) {