View Javadoc
1   package ffx.potential.constraint;
2   
3   import ffx.numerics.Constraint;
4   
5   import static ffx.utilities.Constants.KCAL_TO_GRAM_ANG2_PER_PS2;
6   
7   public class ShakeChargeConstraint implements Constraint {
8       final int nConstraints;
9       final double tol;
10      final int c;
11      final double maxIters = 150;
12  
13      public ShakeChargeConstraint(int nConstraints, int c, double tol){
14          this.nConstraints = nConstraints;
15          this.c = c;
16          this.tol = tol;
17      }
18      @Override
19      public void applyConstraintToStep(final double[] xPrior, double[] xNew, final double[] masses, double tol){
20      }
21  
22      /**
23       * This method follows the SHAKE Charge Constraint laid out in Appendix B of
24       * Donnini, Serena, et al. "Charge-neutral constant pH molecular dynamics simulations using a parsimonious proton buffer."
25       * Journal of chemical theory and computation 12.3 (2016): 1040-1051.
26       * https://pubs.acs.org/doi/epdf/10.1021/acs.jctc.5b01160
27       * @param x
28       * @param masses
29       */
30      public void applyChargeConstraintToStep(final double[] x, final double[] masses){
31          boolean done = false;
32          int iter = 0;
33          while(!done){
34              done = true;
35              iter++;
36              double totalLambda = 0.0;
37              double totalInverseMass = 0.0;
38              for (int i = 0; i < nConstraints; i++) {
39                  double lambda = Math.sin(x[i]) * Math.sin(x[i]);
40                  totalLambda += lambda;
41                  totalInverseMass += (1.0 / masses[i]);
42              }
43              double delta = totalLambda - c;
44              if (Math.abs(delta) > tol) {
45                  done = false;
46                  double term = delta / totalInverseMass;
47                  for (int i = 0; i < nConstraints; i++) {
48                      double g = -term * Math.sin(2 * x[i]);
49                      // Scale constraint force by 0.01 was determined to improve convergence of constraint through testing
50                      x[i] = x[i] - (g * -KCAL_TO_GRAM_ANG2_PER_PS2 / masses[i]) * 0.01;
51                  }
52              }
53              if(iter >= maxIters){
54                  throw new RuntimeException("SHAKE Charge Constraint -- Warning, Charge Constraint not Satisfied");
55              }
56          }
57      }
58  
59      @Override
60      public void applyConstraintToVelocities(final double[] x, double[] v, final double[] masses, double tol){
61  
62      }
63  
64      @Override
65      public int[] constrainedAtomIndices() {
66          return new int[0];
67      }
68  
69      @Override
70      public boolean constraintSatisfied(double[] x, double tol) {
71          return false;
72      }
73  
74      @Override
75      public boolean constraintSatisfied(double[] x, double[] v, double xTol, double vTol) {
76          return false;
77      }
78  
79      @Override
80      public int getNumDegreesFrozen() {
81          return 0;
82      }
83  }
84  
85