Task: Minimizer does not move constrained massless particles (openmm/openmm#3886)

org: openmm
repo: openmm
pr_number: 3886
issue_title: Minimizer does not move constrained massless particles
issue_body: Fixes #3884.  This addresses an obscure situation.  Normally we don't allow a constraint to involve a massless particle.  But if both particles connected by a constraint are massless we do allow it, since the constraint will just be ignored.  That makes it easy to immobilize whole molecules without worrying about what constraints they contain.  In that situation, the minimizer was incorrectly enforcing the constraint rather than ignoring it.
resolved_issues: number: 3884
title: Minimization with frozen particles
body: Hi everyone,

Recently I have been looking into how one can minimize systems containing frozen particles. In the past, I have attempted to set the mass to zero for the particles that are to be frozen, which works during the normal integration:
```python
for atom in protein_atoms:
    system.setParticleMass(atom.index, 0.000*u.dalton)
integrator = mm.LangevinMiddleIntegrator(298.15*u.kelvin, 1.0/u.picoseconds, 2.0*u.femtoseconds)
sim = app.Simulation(pdb.topology, system, integrator, platform, properties)
sim.context.setPositions(pdb.positions)
sim.minimizeEnergy()
```
However, it is my impression that all particles are still being minimized using this approach. Instead, I was thinking if I should use the [setIntegrationForceGroups](http://docs.openmm.org/latest/api-python/generated/openmm.openmm.LangevinMiddleIntegrator.html#openmm.openmm.LangevinMiddleIntegrator.setIntegrationForceGroups) method from the integrator. When calling [getIntegrationForceGroups](http://docs.openmm.org/latest/api-python/generated/openmm.openmm.LangevinMiddleIntegrator.html#openmm.openmm.LangevinMiddleIntegrator.getIntegrationForceGroups)(self) it returns -1, which I assume means that the integrator is acting on all particles? 

To summarize my questions:
a. Should the ForceGroups not change for the integrator when the system contains particles with zero mass?
b. Could you provide a minimal example of how to freeze a set of particles during minimization? If done by changing the ForceGroups please show one can use either set or int as explained in the [documentation](http://docs.openmm.org/latest/api-python/generated/openmm.openmm.LangevinMiddleIntegrator.html#openmm.openmm.LangevinMiddleIntegrator.setIntegrationForceGroups).



## 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/openmmapi/src/LocalEnergyMinimizer.cpp b/openmmapi/src/LocalEnergyMinimizer.cpp
index 503f45a3d0..4fba9540a9 100644
--- a/openmmapi/src/LocalEnergyMinimizer.cpp
+++ b/openmmapi/src/LocalEnergyMinimizer.cpp
@@ -137,12 +137,16 @@ static lbfgsfloatval_t evaluate(void *instance, const lbfgsfloatval_t *x, lbfgsf
         double dr = r-distance;
         double kdr = k*dr;
         energy += 0.5*kdr*dr;
-        g[3*particle1] -= kdr*delta[0];
-        g[3*particle1+1] -= kdr*delta[1];
-        g[3*particle1+2] -= kdr*delta[2];
-        g[3*particle2] += kdr*delta[0];
-        g[3*particle2+1] += kdr*delta[1];
-        g[3*particle2+2] += kdr*delta[2];
+        if (system.getParticleMass(particle1) != 0) {
+            g[3*particle1] -= kdr*delta[0];
+            g[3*particle1+1] -= kdr*delta[1];
+            g[3*particle1+2] -= kdr*delta[2];
+        }
+        if (system.getParticleMass(particle2) != 0) {
+            g[3*particle2] += kdr*delta[0];
+            g[3*particle2+1] += kdr*delta[1];
+            g[3*particle2+2] += kdr*delta[2];
+        }
     }
     return energy;
 }