View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.nonbonded.pme;
39  
40  import edu.rit.pj.IntegerForLoop;
41  import edu.rit.pj.IntegerSchedule;
42  import edu.rit.pj.ParallelRegion;
43  import edu.rit.pj.ParallelTeam;
44  import edu.rit.pj.reduction.SharedDouble;
45  import edu.rit.pj.reduction.SharedInteger;
46  import ffx.crystal.Crystal;
47  import ffx.crystal.SymOp;
48  import ffx.numerics.atomic.AtomicDoubleArray3D;
49  import ffx.potential.bonded.Atom;
50  import ffx.potential.extended.ExtendedSystem;
51  import ffx.potential.nonbonded.MaskingInterface;
52  import ffx.potential.parameters.ForceField;
53  import ffx.potential.parameters.MultipoleType.MultipoleFrameDefinition;
54  import ffx.potential.utils.EnergyException;
55  
56  import java.util.List;
57  import java.util.logging.Level;
58  import java.util.logging.Logger;
59  
60  import static ffx.numerics.special.Erf.erfc;
61  import static ffx.potential.parameters.MultipoleType.t000;
62  import static ffx.potential.parameters.MultipoleType.t001;
63  import static ffx.potential.parameters.MultipoleType.t002;
64  import static ffx.potential.parameters.MultipoleType.t010;
65  import static ffx.potential.parameters.MultipoleType.t011;
66  import static ffx.potential.parameters.MultipoleType.t020;
67  import static ffx.potential.parameters.MultipoleType.t100;
68  import static ffx.potential.parameters.MultipoleType.t101;
69  import static ffx.potential.parameters.MultipoleType.t110;
70  import static ffx.potential.parameters.MultipoleType.t200;
71  import static java.lang.Double.isInfinite;
72  import static java.lang.Double.isNaN;
73  import static java.lang.String.format;
74  import static java.util.Arrays.fill;
75  import static org.apache.commons.math3.util.FastMath.exp;
76  import static org.apache.commons.math3.util.FastMath.min;
77  import static org.apache.commons.math3.util.FastMath.sqrt;
78  
79  /**
80   * Parallel evaluation of the PME real space energy and gradient.
81   *
82   * @author Michael J. Schnieders
83   * @since 1.0
84   */
85  public class RealSpaceEnergyRegion extends ParallelRegion implements MaskingInterface {
86    private static final Logger logger = Logger.getLogger(RealSpaceEnergyRegion.class.getName());
87    /**
88     * Constant applied to multipole interactions.
89     */
90    private static final double oneThird = 1.0 / 3.0;
91    private final int maxThreads;
92    private final double electric;
93    private final SharedInteger sharedInteractions;
94    private final ForceField.ELEC_FORM elecForm;
95    private final RealSpaceEnergyLoop[] realSpaceEnergyLoop;
96    private final FixedChargeEnergyLoop[] fixedChargeEnergyLoop;
97    /**
98     * Specify inter-molecular softcore.
99     */
100   private final boolean intermolecularSoftcore;
101   /**
102    * Specify intra-molecular softcore.
103    */
104   private final boolean intramolecularSoftcore;
105   /**
106    * Dimensions of [nsymm][nAtoms][3]
107    */
108   public double[][][] inducedDipole;
109   public double[][][] inducedDipoleCR;
110   /**
111    * Polarization groups.
112    */
113   protected int[][] ip11;
114   /**
115    * An ordered array of atoms in the system.
116    */
117   private Atom[] atoms;
118   /**
119    * Unit cell and spacegroup information.
120    */
121   private Crystal crystal;
122   /**
123    * Dimensions of [nsymm][xyz][nAtoms].
124    */
125   private double[][][] coordinates;
126   /**
127    * Multipole frame definition.
128    */
129   private MultipoleFrameDefinition[] frame;
130   /**
131    * Multipole frame defining atoms.
132    */
133   private int[][] axisAtom;
134   /**
135    * Dimensions of [nsymm][nAtoms][10]
136    */
137   private double[][][] globalMultipole;
138   private double[][][] titrationMultipole;
139   private double[][][] tautomerMultipole;
140 
141   private ExtendedSystem extendedSystem = null;
142   private boolean esvTerm = false;
143   /**
144    * When computing the polarization energy at Lambda there are 3 pieces.
145    *
146    * <p>1.) Upol(1) = The polarization energy computed normally (ie. system with ligand).
147    *
148    * <p>2.) Uenv = The polarization energy of the system without the ligand.
149    *
150    * <p>3.) Uligand = The polarization energy of the ligand by itself.
151    *
152    * <p>Upol(L) = L*Upol(1) + (1-L)*(Uenv + Uligand)
153    *
154    * <p>Set the "use" array to true for all atoms for part 1. Set the "use" array to true for all
155    * atoms except the ligand for part 2. Set the "use" array to true only for the ligand atoms for
156    * part 3.
157    *
158    * <p>The "use" array can also be employed to turn off atoms for computing the electrostatic
159    * energy of sub-structures.
160    */
161   private boolean[] use;
162   /**
163    * Molecule number for each atom.
164    */
165   private int[] molecule;
166   /**
167    * Flag for ligand atoms.
168    */
169   private boolean[] isSoft;
170   private double[] ipdamp;
171   private double[] thole;
172   /**
173    * Masking of 1-2, 1-3, 1-4 and 1-5 interactions.
174    */
175   private int[][] mask12;
176   private int[][] mask13;
177   private int[][] mask14;
178   private int[][] mask15;
179   /**
180    * Neighbor lists, without atoms beyond the real space cutoff. [nSymm][nAtoms][nIncludedNeighbors]
181    */
182   private int[][][] realSpaceLists;
183   /**
184    * Number of neighboring atoms within the real space cutoff. [nSymm][nAtoms]
185    */
186   private int[][] realSpaceCounts;
187   /**
188    * Pairwise schedule for load balancing.
189    */
190   private IntegerSchedule realSpaceSchedule;
191   private long[] realSpaceEnergyTime;
192   /**
193    * Atomic Gradient array.
194    */
195   private AtomicDoubleArray3D grad;
196   /**
197    * Atomic Torque array.
198    */
199   private AtomicDoubleArray3D torque;
200   /**
201    * Partial derivative of the gradient with respect to Lambda.
202    */
203   private AtomicDoubleArray3D lambdaGrad;
204   /**
205    * Partial derivative of the torque with respect to Lambda.
206    */
207   private AtomicDoubleArray3D lambdaTorque;
208   /**
209    * Partial derivative with respect to Lambda.
210    */
211   private SharedDouble shareddEdLambda;
212   /**
213    * Second partial derivative with respect to Lambda.
214    */
215   private SharedDouble sharedd2EdLambda2;
216   /**
217    * If true, compute coordinate gradient.
218    */
219   private boolean gradient;
220   /**
221    * If lambdaTerm is true, some ligand atom interactions with the environment are being turned
222    * on/off.
223    */
224   private boolean lambdaTerm;
225   /**
226    * If nnTerm is true, all intramolecular interactions are treated with a neural network.
227    */
228   private boolean nnTerm;
229 
230   /**
231    * The current LambdaMode of this PME instance (or OFF for no lambda dependence).
232    */
233   private LambdaMode lambdaMode = LambdaMode.OFF;
234   private Polarization polarization;
235   /**
236    * lAlpha = α*(1 - L)^2
237    */
238   private double lAlpha = 0.0;
239   private double dlAlpha = 0.0;
240   private double d2lAlpha = 0.0;
241   private double dEdLSign = 1.0;
242   /**
243    * lPowPerm = L^permanentLambdaExponent
244    */
245   private double dlPowPerm = 0.0;
246   private double d2lPowPerm = 0.0;
247   private boolean doPermanentRealSpace;
248   private double permanentScale = 1.0;
249   /**
250    * lPowPol = L^polarizationLambdaExponent
251    */
252   private double lPowPol = 1.0;
253   private double dlPowPol = 0.0;
254   private double d2lPowPol = 0.0;
255   private boolean doPolarization;
256   /**
257    * When computing the polarization energy at L there are 3 pieces.
258    *
259    * <p>1.) Upol(1) = The polarization energy computed normally (ie. system with ligand).
260    *
261    * <p>2.) Uenv = The polarization energy of the system without the ligand.
262    *
263    * <p>3.) Uligand = The polarization energy of the ligand by itself.
264    *
265    * <p>Upol(L) = L*Upol(1) + (1-L)*(Uenv + Uligand)
266    *
267    * <p>Set polarizationScale to L for part 1. Set polarizationScale to (1-L) for parts 2 & 3.
268    */
269   private double polarizationScale = 1.0;
270 
271   // *************************************************************************
272   // Mutable Particle Mesh Ewald constants.
273   private double aewald;
274   private double an0;
275   private double an1;
276   private double an2;
277   private double an3;
278   private double an4;
279   private double an5;
280   private double permanentEnergy;
281   private double polarizationEnergy;
282   private ScaleParameters scaleParameters;
283 
284   public RealSpaceEnergyRegion(ForceField.ELEC_FORM elecForm, int nt, ForceField forceField, boolean lambdaTerm, double electric) {
285     maxThreads = nt;
286     this.electric = electric;
287     this.elecForm = elecForm;
288     sharedInteractions = new SharedInteger();
289     if (elecForm == ForceField.ELEC_FORM.FIXED_CHARGE) {
290       fixedChargeEnergyLoop = new FixedChargeEnergyLoop[nt];
291       realSpaceEnergyLoop = null;
292     } else {
293       fixedChargeEnergyLoop = null;
294       realSpaceEnergyLoop = new RealSpaceEnergyLoop[nt];
295     }
296 
297     // Flag to indicate application of an intermolecular softcore potential.
298     if (lambdaTerm) {
299       intermolecularSoftcore = forceField.getBoolean("INTERMOLECULAR_SOFTCORE", false);
300       intramolecularSoftcore = forceField.getBoolean("INTRAMOLECULAR_SOFTCORE", false);
301     } else {
302       intermolecularSoftcore = false;
303       intramolecularSoftcore = false;
304     }
305   }
306 
307   @Override
308   public void applyMask(int i, boolean[] is14, double[]... masks) {
309     if (ip11[i] != null) {
310       // AMOEBA
311       double[] permanentEnergyMask = masks[0];
312       double[] permanentFieldMask = masks[1];
313       for (int value : mask12[i]) {
314         permanentFieldMask[value] = scaleParameters.p12scale;
315         permanentEnergyMask[value] = scaleParameters.m12scale;
316       }
317       for (int value : mask13[i]) {
318         permanentFieldMask[value] = scaleParameters.p13scale;
319         permanentEnergyMask[value] = scaleParameters.m13scale;
320       }
321       for (int value : mask14[i]) {
322         permanentFieldMask[value] = scaleParameters.p14scale;
323         permanentEnergyMask[value] = scaleParameters.m14scale;
324         for (int k : ip11[i]) {
325           if (k == value) {
326             permanentFieldMask[value] = scaleParameters.intra14Scale * scaleParameters.p14scale;
327             break;
328           }
329         }
330       }
331       for (int value : mask15[i]) {
332         permanentEnergyMask[value] = scaleParameters.m15scale;
333       }
334       // Apply group based polarization masking rule.
335       double[] polarizationGroupMask = masks[2];
336       for (int j : ip11[i]) {
337         polarizationGroupMask[j] = scaleParameters.d11scale;
338       }
339     } else {
340       // Fixed Charge Force Fields.
341       double[] permanentEnergyMask = masks[0];
342       for (int value : mask12[i]) {
343         permanentEnergyMask[value] = scaleParameters.m12scale;
344       }
345       for (int value : mask13[i]) {
346         permanentEnergyMask[value] = scaleParameters.m13scale;
347       }
348       for (int value : mask14[i]) {
349         permanentEnergyMask[value] = scaleParameters.m14scale;
350       }
351     }
352   }
353 
354   /**
355    * Execute the RealSpaceEnergyRegion with the passed ParallelTeam.
356    *
357    * @param parallelTeam The ParallelTeam instance to execute with.
358    */
359   public void executeWith(ParallelTeam parallelTeam) {
360     try {
361       parallelTeam.execute(this);
362     } catch (Exception e) {
363       String message = " Exception computing the electrostatic energy.\n";
364       logger.log(Level.SEVERE, message, e);
365     }
366   }
367 
368   @Override
369   public void finish() {
370     permanentEnergy = 0.0;
371     polarizationEnergy = 0.0;
372     if (elecForm == ForceField.ELEC_FORM.FIXED_CHARGE) {
373       for (int i = 0; i < maxThreads; i++) {
374         permanentEnergy += fixedChargeEnergyLoop[i].permanentEnergy;
375       }
376     } else {
377       for (int i = 0; i < maxThreads; i++) {
378         permanentEnergy += realSpaceEnergyLoop[i].permanentEnergy;
379         polarizationEnergy += realSpaceEnergyLoop[i].inducedEnergy;
380       }
381     }
382     permanentEnergy *= electric;
383     polarizationEnergy *= electric;
384     if (isNaN(permanentEnergy)) {
385       throw new EnergyException(
386           format(" The permanent multipole energy is %16.8f", permanentEnergy));
387     }
388     if (isNaN(polarizationEnergy)) {
389       throw new EnergyException(
390           format(" The polarization energy is %16.8f", polarizationEnergy));
391     }
392   }
393 
394   public int getCount(int i) {
395     if (elecForm == ForceField.ELEC_FORM.FIXED_CHARGE) {
396       return fixedChargeEnergyLoop[i].getCount();
397     } else {
398       return realSpaceEnergyLoop[i].getCount();
399     }
400   }
401 
402   public int getInteractions() {
403     return sharedInteractions.get();
404   }
405 
406   public double getPermanentEnergy() {
407     return permanentEnergy;
408   }
409 
410   public double getPolarizationEnergy() {
411     return polarizationEnergy;
412   }
413 
414   public void init(
415       Atom[] atoms,
416       Crystal crystal,
417       ExtendedSystem extendedSystem,
418       boolean esvTerm,
419       double[][][] coordinates,
420       MultipoleFrameDefinition[] frame,
421       int[][] axisAtom,
422       double[][][] globalMultipole,
423       double[][][] titrationMultipole,
424       double[][][] tautomerMultipole,
425       double[][][] inducedDipole,
426       double[][][] inducedDipoleCR,
427       boolean[] use,
428       int[] molecule,
429       int[][] ip11,
430       int[][] mask12,
431       int[][] mask13,
432       int[][] mask14,
433       int[][] mask15,
434       boolean[] isSoft,
435       double[] ipdamp,
436       double[] thole,
437       RealSpaceNeighborParameters realSpaceNeighborParameters,
438       boolean gradient,
439       boolean lambdaTerm,
440       boolean nnTerm,
441       LambdaMode lambdaMode,
442       Polarization polarization,
443       EwaldParameters ewaldParameters,
444       ScaleParameters scaleParameters,
445       AlchemicalParameters alchemicalParameters,
446       long[] realSpaceEnergyTime,
447       AtomicDoubleArray3D grad,
448       AtomicDoubleArray3D torque,
449       AtomicDoubleArray3D lambdaGrad,
450       AtomicDoubleArray3D lambdaTorque,
451       SharedDouble shareddEdLambda,
452       SharedDouble sharedd2EdLambda2) {
453     // Input
454     this.atoms = atoms;
455     this.crystal = crystal;
456     this.extendedSystem = extendedSystem;
457     this.esvTerm = esvTerm;
458     this.coordinates = coordinates;
459     this.frame = frame;
460     this.axisAtom = axisAtom;
461     this.globalMultipole = globalMultipole;
462     this.titrationMultipole = titrationMultipole;
463     this.tautomerMultipole = tautomerMultipole;
464     this.inducedDipole = inducedDipole;
465     this.inducedDipoleCR = inducedDipoleCR;
466     this.use = use;
467     this.molecule = molecule;
468     this.ip11 = ip11;
469     this.mask12 = mask12;
470     this.mask13 = mask13;
471     this.mask14 = mask14;
472     this.mask15 = mask15;
473     this.isSoft = isSoft;
474     this.ipdamp = ipdamp;
475     this.thole = thole;
476     this.realSpaceLists = realSpaceNeighborParameters.realSpaceLists;
477     this.realSpaceCounts = realSpaceNeighborParameters.realSpaceCounts;
478     this.realSpaceSchedule = realSpaceNeighborParameters.realSpaceSchedule;
479     this.gradient = gradient;
480     this.lambdaTerm = lambdaTerm;
481     this.nnTerm = nnTerm;
482     this.lambdaMode = lambdaMode;
483     this.polarization = polarization;
484     this.lAlpha = alchemicalParameters.lAlpha;
485     this.dlAlpha = alchemicalParameters.dlAlpha;
486     this.d2lAlpha = alchemicalParameters.d2lAlpha;
487     this.dEdLSign = alchemicalParameters.dEdLSign;
488     this.dlPowPerm = alchemicalParameters.dlPowPerm;
489     this.d2lPowPerm = alchemicalParameters.d2lPowPerm;
490     this.doPermanentRealSpace = alchemicalParameters.doPermanentRealSpace;
491     this.permanentScale = alchemicalParameters.permanentScale;
492     this.lPowPol = alchemicalParameters.lPowPol;
493     this.dlPowPol = alchemicalParameters.dlPowPol;
494     this.d2lPowPol = alchemicalParameters.d2lPowPol;
495     this.doPolarization = alchemicalParameters.doPolarization;
496     this.polarizationScale = alchemicalParameters.polarizationScale;
497     this.aewald = ewaldParameters.aewald;
498     this.an0 = ewaldParameters.an0;
499     this.an1 = ewaldParameters.an1;
500     this.an2 = ewaldParameters.an2;
501     this.an3 = ewaldParameters.an3;
502     this.an4 = ewaldParameters.an4;
503     this.an5 = ewaldParameters.an5;
504     this.scaleParameters = scaleParameters;
505     // Output
506     this.realSpaceEnergyTime = realSpaceEnergyTime;
507     this.grad = grad;
508     this.torque = torque;
509     this.lambdaGrad = lambdaGrad;
510     this.lambdaTorque = lambdaTorque;
511     this.shareddEdLambda = shareddEdLambda;
512     this.sharedd2EdLambda2 = sharedd2EdLambda2;
513   }
514 
515   @Override
516   public void removeMask(int i, boolean[] is14, double[]... masks) {
517     if (ip11[i] != null) {
518       // AMOEBA
519       double[] permanentEnergyMask = masks[0];
520       double[] permanentFieldMask = masks[1];
521       for (int value : mask12[i]) {
522         permanentFieldMask[value] = 1.0;
523         permanentEnergyMask[value] = 1.0;
524       }
525       for (int value : mask13[i]) {
526         permanentFieldMask[value] = 1.0;
527         permanentEnergyMask[value] = 1.0;
528       }
529       for (int value : mask14[i]) {
530         permanentFieldMask[value] = 1.0;
531         permanentEnergyMask[value] = 1.0;
532         for (int k : ip11[i]) {
533           if (k == value) {
534             permanentFieldMask[value] = 1.0;
535             break;
536           }
537         }
538       }
539       for (int value : mask15[i]) {
540         permanentEnergyMask[value] = 1.0;
541       }
542       // Apply group based polarization masking rule.
543       double[] polarizationGroupMask = masks[2];
544       for (int j : ip11[i]) {
545         polarizationGroupMask[j] = 1.0;
546       }
547     } else {
548       // Fixed Charge Force Fields.
549       double[] permanentEnergyMask = masks[0];
550       for (int value : mask12[i]) {
551         permanentEnergyMask[value] = 1.0;
552       }
553       for (int value : mask13[i]) {
554         permanentEnergyMask[value] = 1.0;
555       }
556       for (int value : mask14[i]) {
557         permanentEnergyMask[value] = 1.0;
558       }
559     }
560   }
561 
562   @Override
563   public void run() {
564     int threadIndex = getThreadIndex();
565     if (elecForm == ForceField.ELEC_FORM.FIXED_CHARGE) {
566       if (fixedChargeEnergyLoop[threadIndex] == null) {
567         fixedChargeEnergyLoop[threadIndex] = new FixedChargeEnergyLoop();
568       }
569       try {
570         int nAtoms = atoms.length;
571         execute(0, nAtoms - 1, fixedChargeEnergyLoop[threadIndex]);
572       } catch (Exception e) {
573         String message =
574             "Fatal exception computing the real space energy in thread " + getThreadIndex() + "\n";
575         logger.log(Level.SEVERE, message, e);
576       }
577     } else {
578       if (realSpaceEnergyLoop[threadIndex] == null) {
579         realSpaceEnergyLoop[threadIndex] = new RealSpaceEnergyLoop();
580       }
581       try {
582         int nAtoms = atoms.length;
583         execute(0, nAtoms - 1, realSpaceEnergyLoop[threadIndex]);
584       } catch (Exception e) {
585         String message =
586             "Fatal exception computing the real space energy in thread " + getThreadIndex() + "\n";
587         logger.log(Level.SEVERE, message, e);
588       }
589     }
590   }
591 
592   @Override
593   public void start() {
594     sharedInteractions.set(0);
595   }
596 
597   /**
598    * Log the real space electrostatics interaction.
599    *
600    * @param i   Atom i.
601    * @param k   Atom j.
602    * @param r   The distance rij.
603    * @param eij The interaction energy.
604    * @since 1.0
605    */
606   private void log(int i, int k, double r, double eij, int count, double total) {
607     logger.info(format("%s  %6d  %6d  %12.10f  %12.10f %8d %16.10f",
608         "ELEC", atoms[i].getIndex(), atoms[k].getIndex(), r, eij, count, total));
609   }
610 
611   /**
612    * The Real Space Gradient Loop class contains methods and thread local variables to parallelize
613    * the evaluation of the real space permanent and polarization energies and gradients.
614    */
615   private class RealSpaceEnergyLoop extends IntegerForLoop {
616 
617     private final double[] dx_local;
618     private final double[][] rot_local;
619     private final Torque torques;
620     private double ci;
621     private double dix, diy, diz;
622     private double qixx, qiyy, qizz, qixy, qixz, qiyz;
623     private double ck;
624     private double dkx, dky, dkz;
625     private double qkxx, qkyy, qkzz, qkxy, qkxz, qkyz;
626     private double uix, uiy, uiz;
627     private double pix, piy, piz;
628     private double xr, yr, zr;
629     private double ukx, uky, ukz;
630     private double pkx, pky, pkz;
631     private double bn0, bn1, bn2, bn3, bn4, bn5, bn6;
632     private double rr1, rr3, rr5, rr7, rr9, rr11, rr13;
633     private double scale, scale3, scale5, scale7;
634     private double scalep, scaled;
635     private double ddsc3x, ddsc3y, ddsc3z;
636     private double ddsc5x, ddsc5y, ddsc5z;
637     private double ddsc7x, ddsc7y, ddsc7z;
638     private double l2;
639     private boolean soft;
640     private double selfScale;
641     private double permanentEnergy;
642     private double inducedEnergy;
643     private double dUdL, d2UdL2;
644     private int i, k, iSymm, count;
645     private double[] gxk_local, gyk_local, gzk_local;
646     private double[] txk_local, tyk_local, tzk_local;
647     private double[] lxk_local, lyk_local, lzk_local;
648     private double[] ltxk_local, ltyk_local, ltzk_local;
649     private double[] masking_local;
650     private double[] maskingp_local;
651     private double[] maskingd_local;
652     private int threadID;
653 
654     RealSpaceEnergyLoop() {
655       super();
656       dx_local = new double[3];
657       rot_local = new double[3][3];
658       torques = new Torque();
659     }
660 
661     @Override
662     public void finish() {
663       sharedInteractions.addAndGet(count);
664       if (lambdaTerm) {
665         shareddEdLambda.addAndGet(dUdL * electric);
666         sharedd2EdLambda2.addAndGet(d2UdL2 * electric);
667       }
668       realSpaceEnergyTime[getThreadIndex()] += System.nanoTime();
669     }
670 
671     public int getCount() {
672       return count;
673     }
674 
675     @Override
676     public void run(int lb, int ub) {
677       List<SymOp> symOps = crystal.spaceGroup.symOps;
678       int nSymm = symOps.size();
679       int nAtoms = atoms.length;
680       for (iSymm = 0; iSymm < nSymm; iSymm++) {
681         SymOp symOp = symOps.get(iSymm);
682         if (gradient) {
683           fill(gxk_local, 0.0);
684           fill(gyk_local, 0.0);
685           fill(gzk_local, 0.0);
686           fill(txk_local, 0.0);
687           fill(tyk_local, 0.0);
688           fill(tzk_local, 0.0);
689         }
690         if (lambdaTerm) {
691           fill(lxk_local, 0.0);
692           fill(lyk_local, 0.0);
693           fill(lzk_local, 0.0);
694           fill(ltxk_local, 0.0);
695           fill(ltyk_local, 0.0);
696           fill(ltzk_local, 0.0);
697         }
698         realSpaceChunk(lb, ub);
699         if (gradient) {
700           // Turn symmetry mate torques into gradients
701           int[] frameIndex = {-1, -1, -1, -1};
702           double[][] g = new double[4][3];
703           double[] trq = new double[3];
704           for (int i = 0; i < nAtoms; i++) {
705             fill(frameIndex, -1);
706             for (int j = 0; j < 4; j++) {
707               fill(g[j], 0.0);
708             }
709             trq[0] = txk_local[i];
710             trq[1] = tyk_local[i];
711             trq[2] = tzk_local[i];
712             torques.torque(i, iSymm, trq, frameIndex, g);
713             for (int j = 0; j < 4; j++) {
714               int index = frameIndex[j];
715               if (index >= 0) {
716                 double[] gj = g[j];
717                 gxk_local[index] += gj[0];
718                 gyk_local[index] += gj[1];
719                 gzk_local[index] += gj[2];
720               }
721             }
722           }
723           // Rotate symmetry mate gradients
724           if (iSymm != 0) {
725             crystal.applyTransSymRot(
726                 nAtoms, gxk_local, gyk_local, gzk_local, gxk_local, gyk_local, gzk_local, symOp,
727                 rot_local);
728           }
729           // Sum symmetry mate gradients into asymmetric unit gradients
730           for (int j = 0; j < nAtoms; j++) {
731             grad.add(threadID, j, gxk_local[j], gyk_local[j], gzk_local[j]);
732           }
733         }
734         if (lambdaTerm) {
735           // Turn symmetry mate torques into gradients
736           int[] frameIndex = {-1, -1, -1, -1};
737           double[][] g = new double[4][3];
738           double[] trq = new double[3];
739           for (int i = 0; i < nAtoms; i++) {
740             fill(frameIndex, -1);
741             for (int j = 0; j < 4; j++) {
742               fill(g[j], 0.0);
743             }
744             trq[0] = ltxk_local[i];
745             trq[1] = ltyk_local[i];
746             trq[2] = ltzk_local[i];
747             torques.torque(i, iSymm, trq, frameIndex, g);
748             for (int j = 0; j < 4; j++) {
749               int index = frameIndex[j];
750               if (index >= 0) {
751                 double[] gj = g[j];
752                 lxk_local[index] += gj[0];
753                 lyk_local[index] += gj[1];
754                 lzk_local[index] += gj[2];
755               }
756             }
757           }
758           // Rotate symmetry mate gradients
759           if (iSymm != 0) {
760             crystal.applyTransSymRot(
761                 nAtoms, lxk_local, lyk_local, lzk_local, lxk_local, lyk_local, lzk_local, symOp,
762                 rot_local);
763           }
764           // Sum symmetry mate gradients into asymmetric unit gradients
765           for (int j = 0; j < nAtoms; j++) {
766             lambdaGrad.add(threadID, j, lxk_local[j], lyk_local[j], lzk_local[j]);
767           }
768         }
769       }
770     }
771 
772     @Override
773     public IntegerSchedule schedule() {
774       return realSpaceSchedule;
775     }
776 
777     @Override
778     public void start() {
779       init();
780       threadID = getThreadIndex();
781       realSpaceEnergyTime[threadID] -= System.nanoTime();
782       permanentEnergy = 0.0;
783       inducedEnergy = 0.0;
784       count = 0;
785       if (lambdaTerm) {
786         dUdL = 0.0;
787         d2UdL2 = 0.0;
788       }
789       torques.init(axisAtom, frame, coordinates);
790     }
791 
792     private void init() {
793       int nAtoms = atoms.length;
794       if (masking_local == null || masking_local.length < nAtoms) {
795         txk_local = new double[nAtoms];
796         tyk_local = new double[nAtoms];
797         tzk_local = new double[nAtoms];
798         gxk_local = new double[nAtoms];
799         gyk_local = new double[nAtoms];
800         gzk_local = new double[nAtoms];
801         lxk_local = new double[nAtoms];
802         lyk_local = new double[nAtoms];
803         lzk_local = new double[nAtoms];
804         ltxk_local = new double[nAtoms];
805         ltyk_local = new double[nAtoms];
806         ltzk_local = new double[nAtoms];
807         masking_local = new double[nAtoms];
808         maskingp_local = new double[nAtoms];
809         maskingd_local = new double[nAtoms];
810         fill(masking_local, 1.0);
811         fill(maskingp_local, 1.0);
812         fill(maskingd_local, 1.0);
813       }
814     }
815 
816     /**
817      * Evaluate the real space permanent energy and polarization energy for a chunk of atoms.
818      *
819      * @param lb The lower bound of the chunk.
820      * @param ub The upper bound of the chunk.
821      */
822     private void realSpaceChunk(final int lb, final int ub) {
823       final double[] x = coordinates[0][0];
824       final double[] y = coordinates[0][1];
825       final double[] z = coordinates[0][2];
826       final double[][] mpole = globalMultipole[0];
827       final double[] zeropole = new double[10];
828       final double[][] ind = inducedDipole[0];
829       final double[][] indp = inducedDipoleCR[0];
830       final int[][] lists = realSpaceLists[iSymm];
831       final double[] neighborX = coordinates[iSymm][0];
832       final double[] neighborY = coordinates[iSymm][1];
833       final double[] neighborZ = coordinates[iSymm][2];
834       final double[][] neighborMultipole = globalMultipole[iSymm];
835       final double[][] neighborInducedDipole = inducedDipole[iSymm];
836       final double[][] neighborInducedDipolep = inducedDipoleCR[iSymm];
837       for (i = lb; i <= ub; i++) {
838         if (!use[i]) {
839           continue;
840         }
841         final int moleculei = molecule[i];
842         if (iSymm == 0) {
843           applyMask(i, null, masking_local, maskingp_local, maskingd_local);
844         }
845         final double xi = x[i];
846         final double yi = y[i];
847         final double zi = z[i];
848         final double[] globalMultipolei = mpole[i];
849         final double[] inducedDipolei = ind[i];
850         final double[] inducedDipolepi = indp[i];
851         setMultipoleI(globalMultipolei);
852         setInducedI(inducedDipolei);
853         setInducedpI(inducedDipolepi);
854         final boolean softi = isSoft[i];
855         final double pdi = ipdamp[i];
856         final double pti = thole[i];
857         final int[] list = lists[i];
858         final int npair = realSpaceCounts[iSymm][i];
859         for (int j = 0; j < npair; j++) {
860           k = list[j];
861           if (!use[k]) {
862             continue;
863           }
864           boolean sameMolecule = (moleculei == molecule[k]);
865           if (lambdaMode == LambdaMode.VAPOR) {
866             if ((intermolecularSoftcore && !sameMolecule)
867                 || (intramolecularSoftcore && sameMolecule)) {
868               continue;
869             }
870           }
871           selfScale = 1.0;
872           if (i == k) {
873             selfScale = 0.5;
874           }
875           double beta = 0.0;
876           l2 = 1.0;
877           soft = (softi || isSoft[k]);
878           if (soft && doPermanentRealSpace) {
879             beta = lAlpha;
880             l2 = permanentScale;
881           } else if (nnTerm) {
882             l2 = permanentScale;
883           }
884           final double xk = neighborX[k];
885           final double yk = neighborY[k];
886           final double zk = neighborZ[k];
887           dx_local[0] = xk - xi;
888           dx_local[1] = yk - yi;
889           dx_local[2] = zk - zi;
890           double r2 = crystal.image(dx_local);
891           xr = dx_local[0];
892           yr = dx_local[1];
893           zr = dx_local[2];
894           final double[] globalMultipolek = neighborMultipole[k];
895           final double[] inducedDipolek = neighborInducedDipole[k];
896           final double[] inducedDipolepk = neighborInducedDipolep[k];
897           setMultipoleK(globalMultipolek);
898           setInducedK(inducedDipolek);
899           setInducedpK(inducedDipolepk);
900           final double pdk = ipdamp[k];
901           final double ptk = thole[k];
902           scale = masking_local[k];
903           scalep = maskingp_local[k];
904           scaled = maskingd_local[k];
905           scale3 = 1.0;
906           scale5 = 1.0;
907           scale7 = 1.0;
908           double r = sqrt(r2 + beta);
909           double ralpha = aewald * r;
910           double exp2a = exp(-ralpha * ralpha);
911           rr1 = 1.0 / r;
912           double rr2 = rr1 * rr1;
913           bn0 = erfc(ralpha) * rr1;
914           bn1 = (bn0 + an0 * exp2a) * rr2;
915           bn2 = (3.0 * bn1 + an1 * exp2a) * rr2;
916           bn3 = (5.0 * bn2 + an2 * exp2a) * rr2;
917           bn4 = (7.0 * bn3 + an3 * exp2a) * rr2;
918           bn5 = (9.0 * bn4 + an4 * exp2a) * rr2;
919           bn6 = (11.0 * bn5 + an5 * exp2a) * rr2;
920           rr3 = rr1 * rr2;
921           rr5 = 3.0 * rr3 * rr2;
922           rr7 = 5.0 * rr5 * rr2;
923           rr9 = 7.0 * rr7 * rr2;
924           rr11 = 9.0 * rr9 * rr2;
925           rr13 = 11.0 * rr11 * rr2;
926           ddsc3x = 0.0;
927           ddsc3y = 0.0;
928           ddsc3z = 0.0;
929           ddsc5x = 0.0;
930           ddsc5y = 0.0;
931           ddsc5z = 0.0;
932           ddsc7x = 0.0;
933           ddsc7y = 0.0;
934           ddsc7z = 0.0;
935           double damp = pdi * pdk;
936           double thole = min(pti, ptk);
937           double rdamp = r * damp;
938           damp = -thole * rdamp * rdamp * rdamp;
939           if (damp > -50.0) {
940             final double expdamp = exp(damp);
941             scale3 = 1.0 - expdamp;
942             scale5 = 1.0 - expdamp * (1.0 - damp);
943             scale7 = 1.0 - expdamp * (1.0 - damp + 0.6 * damp * damp);
944             final double temp3 = -3.0 * damp * expdamp * rr2;
945             final double temp5 = -damp;
946             final double temp7 = -0.2 - 0.6 * damp;
947             ddsc3x = temp3 * xr;
948             ddsc3y = temp3 * yr;
949             ddsc3z = temp3 * zr;
950             ddsc5x = temp5 * ddsc3x;
951             ddsc5y = temp5 * ddsc3y;
952             ddsc5z = temp5 * ddsc3z;
953             ddsc7x = temp7 * ddsc5x;
954             ddsc7y = temp7 * ddsc5y;
955             ddsc7z = temp7 * ddsc5z;
956           }
957           if (doPermanentRealSpace) {
958             double ei = permanentPair(gradient, lambdaTerm);
959             if (isNaN(ei) || isInfinite(ei)) {
960               String message = format(" %s\n %s\n %s\n The permanent multipole energy between "
961                       + "atoms %d and %d (%d) is %16.8f at %16.8f A.",
962                   crystal.getUnitCell().toString(), atoms[i].toString(), atoms[k].toString(),
963                   i, k, iSymm, ei, r);
964               throw new EnergyException(message);
965             }
966             if (ei != 0.0) {
967               permanentEnergy += ei;
968               count++;
969               // log(i, k, r, ei * electric, count, permanentEnergy * electric);
970             }
971             if (esvTerm) {
972               if (extendedSystem.isTitrating(i)) {
973                 double titrdUdL = 0.0;
974                 double tautdUdL = 0.0;
975                 final double[][] titrMpole = titrationMultipole[0];
976                 final double[] titrMultipolei = titrMpole[i];
977                 setMultipoleI(titrMultipolei);
978                 titrdUdL = electric * permanentPair(false, false);
979                 if (extendedSystem.isTautomerizing(i)) {
980                   final double[][] tautMpole = tautomerMultipole[0];
981                   final double[] tautMultipolei = tautMpole[i];
982                   setMultipoleI(tautMultipolei);
983                   tautdUdL = electric * permanentPair(false, false);
984                 }
985                 extendedSystem.addPermElecDeriv(i, titrdUdL, tautdUdL);
986                 // Reset Multipoles between titration and tautomer ESVs
987                 setMultipoleI(globalMultipolei);
988               }
989               if (extendedSystem.isTitrating(k)) {
990                 double titrdUdL = 0.0;
991                 double tautdUdL = 0.0;
992                 final double[][] titrNeighborMpole = titrationMultipole[iSymm];
993                 final double[] titrMultipolek = titrNeighborMpole[k];
994                 setMultipoleK(titrMultipolek);
995                 titrdUdL = electric * permanentPair(false, false);
996                 if (extendedSystem.isTautomerizing(k)) {
997                   final double[][] tautNeighborMpole = tautomerMultipole[iSymm];
998                   final double[] tautMultipolek = tautNeighborMpole[k];
999                   setMultipoleK(tautMultipolek);
1000                   tautdUdL = electric * permanentPair(false, false);
1001                 }
1002                 extendedSystem.addPermElecDeriv(k, titrdUdL, tautdUdL);
1003                 // Reset Multipoles between titration and tautomer ESVs
1004                 setMultipoleK(globalMultipolek);
1005               }
1006             }
1007           }
1008           if (polarization != Polarization.NONE && doPolarization) {
1009             // Polarization does not use the softcore tensors.
1010             if (soft && doPermanentRealSpace) {
1011               scale3 = 1.0;
1012               scale5 = 1.0;
1013               scale7 = 1.0;
1014               r = sqrt(r2);
1015               ralpha = aewald * r;
1016               exp2a = exp(-ralpha * ralpha);
1017               rr1 = 1.0 / r;
1018               rr2 = rr1 * rr1;
1019               bn0 = erfc(ralpha) * rr1;
1020               bn1 = (bn0 + an0 * exp2a) * rr2;
1021               bn2 = (3.0 * bn1 + an1 * exp2a) * rr2;
1022               bn3 = (5.0 * bn2 + an2 * exp2a) * rr2;
1023               bn4 = (7.0 * bn3 + an3 * exp2a) * rr2;
1024               bn5 = (9.0 * bn4 + an4 * exp2a) * rr2;
1025               bn6 = (11.0 * bn5 + an5 * exp2a) * rr2;
1026               rr3 = rr1 * rr2;
1027               rr5 = 3.0 * rr3 * rr2;
1028               rr7 = 5.0 * rr5 * rr2;
1029               rr9 = 7.0 * rr7 * rr2;
1030               rr11 = 9.0 * rr9 * rr2;
1031               ddsc3x = 0.0;
1032               ddsc3y = 0.0;
1033               ddsc3z = 0.0;
1034               ddsc5x = 0.0;
1035               ddsc5y = 0.0;
1036               ddsc5z = 0.0;
1037               ddsc7x = 0.0;
1038               ddsc7y = 0.0;
1039               ddsc7z = 0.0;
1040               damp = pdi * pdk;
1041               thole = min(pti, ptk);
1042               rdamp = r * damp;
1043               damp = -thole * rdamp * rdamp * rdamp;
1044               if (damp > -50.0) {
1045                 final double expdamp = exp(damp);
1046                 scale3 = 1.0 - expdamp;
1047                 scale5 = 1.0 - expdamp * (1.0 - damp);
1048                 scale7 = 1.0 - expdamp * (1.0 - damp + 0.6 * damp * damp);
1049                 final double temp3 = -3.0 * damp * expdamp * rr2;
1050                 final double temp5 = -damp;
1051                 final double temp7 = -0.2 - 0.6 * damp;
1052                 ddsc3x = temp3 * xr;
1053                 ddsc3y = temp3 * yr;
1054                 ddsc3z = temp3 * zr;
1055                 ddsc5x = temp5 * ddsc3x;
1056                 ddsc5y = temp5 * ddsc3y;
1057                 ddsc5z = temp5 * ddsc3z;
1058                 ddsc7x = temp7 * ddsc5x;
1059                 ddsc7y = temp7 * ddsc5y;
1060                 ddsc7z = temp7 * ddsc5z;
1061               }
1062             }
1063             double ei = polarizationPair(gradient, lambdaTerm);
1064             if (isNaN(ei) || isInfinite(ei)) {
1065               String message = format(" %s\n"
1066                       + " %s\n with induced dipole: %8.3f %8.3f %8.3f\n"
1067                       + " %s\n with induced dipole: %8.3f %8.3f %8.3f\n"
1068                       + " The polarization energy due to atoms "
1069                       + "%d and %d (%d) is %10.6f at %10.6f A.",
1070                   crystal.getUnitCell(), atoms[i], uix, uiy, uiz, atoms[k], ukx, uky, ukz, i + 1, k + 1, iSymm, ei, r);
1071               throw new EnergyException(message);
1072             }
1073             inducedEnergy += ei;
1074             if (esvTerm) {
1075               int esvI = extendedSystem.getTitrationESVIndex(i);
1076               int esvK = extendedSystem.getTitrationESVIndex(k);
1077               if (extendedSystem.isTitrating(i)) {
1078                 double titrdUdL = 0.0;
1079                 double tautdUdL = 0.0;
1080                 final double[][] titrMpole = titrationMultipole[0];
1081                 final double[] titrMultipolei = titrMpole[i];
1082                 setMultipoleI(titrMultipolei);
1083                 // Check if atom i and atom k are controlled by the same ESV.
1084                 if (extendedSystem.isTitrating(k) && esvI == esvK) {
1085                   final double[][] titrNeighborMpole = titrationMultipole[iSymm];
1086                   final double[] titrMultipolek = titrNeighborMpole[k];
1087                   setMultipoleK(titrMultipolek);
1088                 } else {
1089                   setMultipoleK(zeropole);
1090                 }
1091                 titrdUdL = polarizationPair(false, false);
1092                 // Swap induced dipoles and masking rules
1093                 setInducedI(inducedDipolepi);
1094                 setInducedK(inducedDipolepk);
1095                 scaled = maskingp_local[k];
1096                 scalep = maskingd_local[k];
1097                 titrdUdL += polarizationPair(false, false);
1098                 // Reset
1099                 setInducedI(inducedDipolei);
1100                 setInducedK(inducedDipolek);
1101                 scalep = maskingp_local[k];
1102                 scaled = maskingd_local[k];
1103 
1104                 if (extendedSystem.isTautomerizing(i)) {
1105                   final double[][] tautMpole = tautomerMultipole[0];
1106                   final double[] tautMultipolei = tautMpole[i];
1107                   setMultipoleI(tautMultipolei);
1108                   // Check if atom i and atom k are controlled by the same ESV.
1109                   if (extendedSystem.isTautomerizing(k) && esvI == esvK) {
1110                     final double[][] tautNeighborMpole = tautomerMultipole[iSymm];
1111                     final double[] tautMultipolek = tautNeighborMpole[k];
1112                     setMultipoleK(tautMultipolek);
1113                   } else {
1114                     setMultipoleK(zeropole);
1115                   }
1116                   tautdUdL = polarizationPair(false, false);
1117                   // Swap induced dipoles and masking
1118                   setInducedI(inducedDipolepi);
1119                   setInducedK(inducedDipolepk);
1120                   scaled = maskingp_local[k];
1121                   scalep = maskingd_local[k];
1122                   tautdUdL += polarizationPair(false, false);
1123                   // Reset induced dipoles and masking
1124                   setInducedI(inducedDipolei);
1125                   setInducedK(inducedDipolek);
1126                   scalep = maskingp_local[k];
1127                   scaled = maskingd_local[k];
1128                 }
1129                 extendedSystem.addIndElecDeriv(i, titrdUdL * electric, tautdUdL * electric);
1130                 // Reset permanent multipoles
1131                 setMultipoleI(globalMultipolei);
1132                 setMultipoleK(globalMultipolek);
1133               }
1134               // Collect further terms if atom i and atom k are controlled by different ESVs.
1135               if (extendedSystem.isTitrating(k) && esvI != esvK) {
1136                 double titrdUdL = 0.0;
1137                 double tautdUdL = 0.0;
1138                 final double[][] titrNeighborMpole = titrationMultipole[iSymm];
1139                 final double[] titrMultipolek = titrNeighborMpole[k];
1140                 setMultipoleK(titrMultipolek);
1141                 setMultipoleI(zeropole);
1142                 titrdUdL = polarizationPair(false, false);
1143                 // Swap induced dipoles and masking
1144                 setInducedI(inducedDipolepi);
1145                 setInducedK(inducedDipolepk);
1146                 scaled = maskingp_local[k];
1147                 scalep = maskingd_local[k];
1148                 titrdUdL += polarizationPair(false, false);
1149                 // Reset induced dipoles and masking
1150                 setInducedI(inducedDipolei);
1151                 setInducedK(inducedDipolek);
1152                 scalep = maskingp_local[k];
1153                 scaled = maskingd_local[k];
1154                 if (extendedSystem.isTautomerizing(k)) {
1155                   final double[][] tautNeighborMpole = tautomerMultipole[iSymm];
1156                   final double[] tautMultipolek = tautNeighborMpole[k];
1157                   setMultipoleK(tautMultipolek);
1158                   tautdUdL = polarizationPair(false, false);
1159                   // Swap induced dipoles and masking
1160                   setInducedI(inducedDipolepi);
1161                   setInducedK(inducedDipolepk);
1162                   scaled = maskingp_local[k];
1163                   scalep = maskingd_local[k];
1164                   tautdUdL += polarizationPair(false, false);
1165                   // Reset induced dipoles and masking
1166                   setInducedI(inducedDipolei);
1167                   setInducedK(inducedDipolek);
1168                   scalep = maskingp_local[k];
1169                   scaled = maskingd_local[k];
1170                 }
1171                 extendedSystem.addIndElecDeriv(k, titrdUdL * electric, tautdUdL * electric);
1172                 // Reset permanent multipoles
1173                 setMultipoleI(globalMultipolei);
1174                 setMultipoleK(globalMultipolek);
1175               }
1176             }
1177           }
1178         }
1179         if (iSymm == 0) {
1180           removeMask(i, null, masking_local, maskingp_local, maskingd_local);
1181         }
1182       }
1183     }
1184 
1185     /**
1186      * Evaluate the real space permanent energy for a pair of multipole sites.
1187      *
1188      * @return the permanent multipole energy.
1189      */
1190     private double permanentPair(boolean gradientLocal, boolean lambdaTermLocal) {
1191       final double dixdkx = diy * dkz - diz * dky;
1192       final double dixdky = diz * dkx - dix * dkz;
1193       final double dixdkz = dix * dky - diy * dkx;
1194       final double dixrx = diy * zr - diz * yr;
1195       final double dixry = diz * xr - dix * zr;
1196       final double dixrz = dix * yr - diy * xr;
1197       final double dkxrx = dky * zr - dkz * yr;
1198       final double dkxry = dkz * xr - dkx * zr;
1199       final double dkxrz = dkx * yr - dky * xr;
1200       final double qirx = qixx * xr + qixy * yr + qixz * zr;
1201       final double qiry = qixy * xr + qiyy * yr + qiyz * zr;
1202       final double qirz = qixz * xr + qiyz * yr + qizz * zr;
1203       final double qkrx = qkxx * xr + qkxy * yr + qkxz * zr;
1204       final double qkry = qkxy * xr + qkyy * yr + qkyz * zr;
1205       final double qkrz = qkxz * xr + qkyz * yr + qkzz * zr;
1206       final double qiqkrx = qixx * qkrx + qixy * qkry + qixz * qkrz;
1207       final double qiqkry = qixy * qkrx + qiyy * qkry + qiyz * qkrz;
1208       final double qiqkrz = qixz * qkrx + qiyz * qkry + qizz * qkrz;
1209       final double qkqirx = qkxx * qirx + qkxy * qiry + qkxz * qirz;
1210       final double qkqiry = qkxy * qirx + qkyy * qiry + qkyz * qirz;
1211       final double qkqirz = qkxz * qirx + qkyz * qiry + qkzz * qirz;
1212       final double qixqkx =
1213           qixy * qkxz + qiyy * qkyz + qiyz * qkzz - qixz * qkxy - qiyz * qkyy - qizz * qkyz;
1214       final double qixqky =
1215           qixz * qkxx + qiyz * qkxy + qizz * qkxz - qixx * qkxz - qixy * qkyz - qixz * qkzz;
1216       final double qixqkz =
1217           qixx * qkxy + qixy * qkyy + qixz * qkyz - qixy * qkxx - qiyy * qkxy - qiyz * qkxz;
1218       final double rxqirx = yr * qirz - zr * qiry;
1219       final double rxqiry = zr * qirx - xr * qirz;
1220       final double rxqirz = xr * qiry - yr * qirx;
1221       final double rxqkrx = yr * qkrz - zr * qkry;
1222       final double rxqkry = zr * qkrx - xr * qkrz;
1223       final double rxqkrz = xr * qkry - yr * qkrx;
1224       final double rxqikrx = yr * qiqkrz - zr * qiqkry;
1225       final double rxqikry = zr * qiqkrx - xr * qiqkrz;
1226       final double rxqikrz = xr * qiqkry - yr * qiqkrx;
1227       final double rxqkirx = yr * qkqirz - zr * qkqiry;
1228       final double rxqkiry = zr * qkqirx - xr * qkqirz;
1229       final double rxqkirz = xr * qkqiry - yr * qkqirx;
1230       final double qkrxqirx = qkry * qirz - qkrz * qiry;
1231       final double qkrxqiry = qkrz * qirx - qkrx * qirz;
1232       final double qkrxqirz = qkrx * qiry - qkry * qirx;
1233       final double qidkx = qixx * dkx + qixy * dky + qixz * dkz;
1234       final double qidky = qixy * dkx + qiyy * dky + qiyz * dkz;
1235       final double qidkz = qixz * dkx + qiyz * dky + qizz * dkz;
1236       final double qkdix = qkxx * dix + qkxy * diy + qkxz * diz;
1237       final double qkdiy = qkxy * dix + qkyy * diy + qkyz * diz;
1238       final double qkdiz = qkxz * dix + qkyz * diy + qkzz * diz;
1239       final double dixqkrx = diy * qkrz - diz * qkry;
1240       final double dixqkry = diz * qkrx - dix * qkrz;
1241       final double dixqkrz = dix * qkry - diy * qkrx;
1242       final double dkxqirx = dky * qirz - dkz * qiry;
1243       final double dkxqiry = dkz * qirx - dkx * qirz;
1244       final double dkxqirz = dkx * qiry - dky * qirx;
1245       final double rxqidkx = yr * qidkz - zr * qidky;
1246       final double rxqidky = zr * qidkx - xr * qidkz;
1247       final double rxqidkz = xr * qidky - yr * qidkx;
1248       final double rxqkdix = yr * qkdiz - zr * qkdiy;
1249       final double rxqkdiy = zr * qkdix - xr * qkdiz;
1250       final double rxqkdiz = xr * qkdiy - yr * qkdix;
1251 
1252       // Calculate the scalar products for permanent multipoles.
1253       final double sc2 = dix * dkx + diy * dky + diz * dkz;
1254       final double sc3 = dix * xr + diy * yr + diz * zr;
1255       final double sc4 = dkx * xr + dky * yr + dkz * zr;
1256       final double sc5 = qirx * xr + qiry * yr + qirz * zr;
1257       final double sc6 = qkrx * xr + qkry * yr + qkrz * zr;
1258       final double sc7 = qirx * dkx + qiry * dky + qirz * dkz;
1259       final double sc8 = qkrx * dix + qkry * diy + qkrz * diz;
1260       final double sc9 = qirx * qkrx + qiry * qkry + qirz * qkrz;
1261       final double sc10 =
1262           2.0 * (qixy * qkxy + qixz * qkxz + qiyz * qkyz) + qixx * qkxx + qiyy * qkyy + qizz * qkzz;
1263 
1264       // Calculate the gl functions for permanent multipoles.
1265       final double gl0 = ci * ck;
1266       final double gl1 = ck * sc3 - ci * sc4;
1267       final double gl2 = ci * sc6 + ck * sc5 - sc3 * sc4;
1268       final double gl3 = sc3 * sc6 - sc4 * sc5;
1269       final double gl4 = sc5 * sc6;
1270       final double gl5 = -4.0 * sc9;
1271       final double gl6 = sc2;
1272       final double gl7 = 2.0 * (sc7 - sc8);
1273       final double gl8 = 2.0 * sc10;
1274 
1275       // Compute the energy contributions for this interaction.
1276       final double scale1 = 1.0 - scale;
1277       final double ereal =
1278           gl0 * bn0 + (gl1 + gl6) * bn1 + (gl2 + gl7 + gl8) * bn2 + (gl3 + gl5) * bn3 + gl4 * bn4;
1279       final double efix =
1280           scale1
1281               * (gl0 * rr1
1282               + (gl1 + gl6) * rr3
1283               + (gl2 + gl7 + gl8) * rr5
1284               + (gl3 + gl5) * rr7
1285               + gl4 * rr9);
1286       final double e = selfScale * l2 * (ereal - efix);
1287       if (gradientLocal) {
1288         final double gf1 =
1289             bn1 * gl0 + bn2 * (gl1 + gl6) + bn3 * (gl2 + gl7 + gl8) + bn4 * (gl3 + gl5) + bn5 * gl4;
1290         final double gf2 = -ck * bn1 + sc4 * bn2 - sc6 * bn3;
1291         final double gf3 = ci * bn1 + sc3 * bn2 + sc5 * bn3;
1292         final double gf4 = 2.0 * bn2;
1293         final double gf5 = 2.0 * (-ck * bn2 + sc4 * bn3 - sc6 * bn4);
1294         final double gf6 = 2.0 * (-ci * bn2 - sc3 * bn3 - sc5 * bn4);
1295         final double gf7 = 4.0 * bn3;
1296 
1297         // Get the permanent force with screening.
1298         double ftm2x =
1299             gf1 * xr
1300                 + gf2 * dix
1301                 + gf3 * dkx
1302                 + gf4 * (qkdix - qidkx)
1303                 + gf5 * qirx
1304                 + gf6 * qkrx
1305                 + gf7 * (qiqkrx + qkqirx);
1306         double ftm2y =
1307             gf1 * yr
1308                 + gf2 * diy
1309                 + gf3 * dky
1310                 + gf4 * (qkdiy - qidky)
1311                 + gf5 * qiry
1312                 + gf6 * qkry
1313                 + gf7 * (qiqkry + qkqiry);
1314         double ftm2z =
1315             gf1 * zr
1316                 + gf2 * diz
1317                 + gf3 * dkz
1318                 + gf4 * (qkdiz - qidkz)
1319                 + gf5 * qirz
1320                 + gf6 * qkrz
1321                 + gf7 * (qiqkrz + qkqirz);
1322 
1323         // Get the permanent torque with screening.
1324         double ttm2x =
1325             -bn1 * dixdkx
1326                 + gf2 * dixrx
1327                 + gf4 * (dixqkrx + dkxqirx + rxqidkx - 2.0 * qixqkx)
1328                 - gf5 * rxqirx
1329                 - gf7 * (rxqikrx + qkrxqirx);
1330         double ttm2y =
1331             -bn1 * dixdky
1332                 + gf2 * dixry
1333                 + gf4 * (dixqkry + dkxqiry + rxqidky - 2.0 * qixqky)
1334                 - gf5 * rxqiry
1335                 - gf7 * (rxqikry + qkrxqiry);
1336         double ttm2z =
1337             -bn1 * dixdkz
1338                 + gf2 * dixrz
1339                 + gf4 * (dixqkrz + dkxqirz + rxqidkz - 2.0 * qixqkz)
1340                 - gf5 * rxqirz
1341                 - gf7 * (rxqikrz + qkrxqirz);
1342         double ttm3x =
1343             bn1 * dixdkx
1344                 + gf3 * dkxrx
1345                 - gf4 * (dixqkrx + dkxqirx + rxqkdix - 2.0 * qixqkx)
1346                 - gf6 * rxqkrx
1347                 - gf7 * (rxqkirx - qkrxqirx);
1348         double ttm3y =
1349             bn1 * dixdky
1350                 + gf3 * dkxry
1351                 - gf4 * (dixqkry + dkxqiry + rxqkdiy - 2.0 * qixqky)
1352                 - gf6 * rxqkry
1353                 - gf7 * (rxqkiry - qkrxqiry);
1354         double ttm3z =
1355             bn1 * dixdkz
1356                 + gf3 * dkxrz
1357                 - gf4 * (dixqkrz + dkxqirz + rxqkdiz - 2.0 * qixqkz)
1358                 - gf6 * rxqkrz
1359                 - gf7 * (rxqkirz - qkrxqirz);
1360 
1361         // Handle the case where scaling is used.
1362         if (scale1 != 0.0) {
1363           final double gfr1 =
1364               rr3 * gl0
1365                   + rr5 * (gl1 + gl6)
1366                   + rr7 * (gl2 + gl7 + gl8)
1367                   + rr9 * (gl3 + gl5)
1368                   + rr11 * gl4;
1369           final double gfr2 = -ck * rr3 + sc4 * rr5 - sc6 * rr7;
1370           final double gfr3 = ci * rr3 + sc3 * rr5 + sc5 * rr7;
1371           final double gfr4 = 2.0 * rr5;
1372           final double gfr5 = 2.0 * (-ck * rr5 + sc4 * rr7 - sc6 * rr9);
1373           final double gfr6 = 2.0 * (-ci * rr5 - sc3 * rr7 - sc5 * rr9);
1374           final double gfr7 = 4.0 * rr7;
1375 
1376           // Get the permanent force without screening.
1377           final double ftm2rx =
1378               gfr1 * xr
1379                   + gfr2 * dix
1380                   + gfr3 * dkx
1381                   + gfr4 * (qkdix - qidkx)
1382                   + gfr5 * qirx
1383                   + gfr6 * qkrx
1384                   + gfr7 * (qiqkrx + qkqirx);
1385           final double ftm2ry =
1386               gfr1 * yr
1387                   + gfr2 * diy
1388                   + gfr3 * dky
1389                   + gfr4 * (qkdiy - qidky)
1390                   + gfr5 * qiry
1391                   + gfr6 * qkry
1392                   + gfr7 * (qiqkry + qkqiry);
1393           final double ftm2rz =
1394               gfr1 * zr
1395                   + gfr2 * diz
1396                   + gfr3 * dkz
1397                   + gfr4 * (qkdiz - qidkz)
1398                   + gfr5 * qirz
1399                   + gfr6 * qkrz
1400                   + gfr7 * (qiqkrz + qkqirz);
1401 
1402           // Get the permanent torque without screening.
1403           final double ttm2rx =
1404               -rr3 * dixdkx
1405                   + gfr2 * dixrx
1406                   + gfr4 * (dixqkrx + dkxqirx + rxqidkx - 2.0 * qixqkx)
1407                   - gfr5 * rxqirx
1408                   - gfr7 * (rxqikrx + qkrxqirx);
1409           final double ttm2ry =
1410               -rr3 * dixdky
1411                   + gfr2 * dixry
1412                   + gfr4 * (dixqkry + dkxqiry + rxqidky - 2.0 * qixqky)
1413                   - gfr5 * rxqiry
1414                   - gfr7 * (rxqikry + qkrxqiry);
1415           final double ttm2rz =
1416               -rr3 * dixdkz
1417                   + gfr2 * dixrz
1418                   + gfr4 * (dixqkrz + dkxqirz + rxqidkz - 2.0 * qixqkz)
1419                   - gfr5 * rxqirz
1420                   - gfr7 * (rxqikrz + qkrxqirz);
1421           final double ttm3rx =
1422               rr3 * dixdkx
1423                   + gfr3 * dkxrx
1424                   - gfr4 * (dixqkrx + dkxqirx + rxqkdix - 2.0 * qixqkx)
1425                   - gfr6 * rxqkrx
1426                   - gfr7 * (rxqkirx - qkrxqirx);
1427           final double ttm3ry =
1428               rr3 * dixdky
1429                   + gfr3 * dkxry
1430                   - gfr4 * (dixqkry + dkxqiry + rxqkdiy - 2.0 * qixqky)
1431                   - gfr6 * rxqkry
1432                   - gfr7 * (rxqkiry - qkrxqiry);
1433           final double ttm3rz =
1434               rr3 * dixdkz
1435                   + gfr3 * dkxrz
1436                   - gfr4 * (dixqkrz + dkxqirz + rxqkdiz - 2.0 * qixqkz)
1437                   - gfr6 * rxqkrz
1438                   - gfr7 * (rxqkirz - qkrxqirz);
1439           ftm2x -= scale1 * ftm2rx;
1440           ftm2y -= scale1 * ftm2ry;
1441           ftm2z -= scale1 * ftm2rz;
1442           ttm2x -= scale1 * ttm2rx;
1443           ttm2y -= scale1 * ttm2ry;
1444           ttm2z -= scale1 * ttm2rz;
1445           ttm3x -= scale1 * ttm3rx;
1446           ttm3y -= scale1 * ttm3ry;
1447           ttm3z -= scale1 * ttm3rz;
1448         }
1449         double prefactor = electric * selfScale * l2;
1450         grad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
1451         torque.add(threadID, i, prefactor * ttm2x, prefactor * ttm2y, prefactor * ttm2z);
1452 
1453 //        logger.info(format(" %d %d I Perm Force %17.15f %17.15f %17.15f", i, k, ftm2x, ftm2y, ftm2z));
1454 //        logger.info(format(" %d %d I Perm Torque %17.15f %17.15f %17.15f", i, k, ttm2x, ttm2y, ttm2z));
1455 //        logger.info(format(" %d %d K Perm Torque %17.15f %17.15f %17.15f", i, k, ttm3x, ttm3y, ttm3z));
1456 
1457         gxk_local[k] -= prefactor * ftm2x;
1458         gyk_local[k] -= prefactor * ftm2y;
1459         gzk_local[k] -= prefactor * ftm2z;
1460         txk_local[k] += prefactor * ttm3x;
1461         tyk_local[k] += prefactor * ttm3y;
1462         tzk_local[k] += prefactor * ttm3z;
1463 
1464         // This is dU/dL/dX for the first term of dU/dL: d[dlPow * ereal]/dx
1465         if (lambdaTerm && soft) {
1466           prefactor = electric * selfScale * dEdLSign * dlPowPerm;
1467           lambdaGrad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
1468           lambdaTorque.add(threadID, i, prefactor * ttm2x, prefactor * ttm2y, prefactor * ttm2z);
1469           lxk_local[k] -= prefactor * ftm2x;
1470           lyk_local[k] -= prefactor * ftm2y;
1471           lzk_local[k] -= prefactor * ftm2z;
1472           ltxk_local[k] += prefactor * ttm3x;
1473           ltyk_local[k] += prefactor * ttm3y;
1474           ltzk_local[k] += prefactor * ttm3z;
1475         }
1476       }
1477       if (lambdaTermLocal && soft) {
1478         double dRealdL =
1479             gl0 * bn1 + (gl1 + gl6) * bn2 + (gl2 + gl7 + gl8) * bn3 + (gl3 + gl5) * bn4 + gl4 * bn5;
1480         double d2RealdL2 =
1481             gl0 * bn2 + (gl1 + gl6) * bn3 + (gl2 + gl7 + gl8) * bn4 + (gl3 + gl5) * bn5 + gl4 * bn6;
1482 
1483         dUdL += selfScale * (dEdLSign * dlPowPerm * ereal + l2 * dlAlpha * dRealdL);
1484         d2UdL2 +=
1485             selfScale
1486                 * (dEdLSign
1487                 * (d2lPowPerm * ereal
1488                 + dlPowPerm * dlAlpha * dRealdL
1489                 + dlPowPerm * dlAlpha * dRealdL)
1490                 + l2 * d2lAlpha * dRealdL
1491                 + l2 * dlAlpha * dlAlpha * d2RealdL2);
1492 
1493         double dFixdL =
1494             gl0 * rr3
1495                 + (gl1 + gl6) * rr5
1496                 + (gl2 + gl7 + gl8) * rr7
1497                 + (gl3 + gl5) * rr9
1498                 + gl4 * rr11;
1499         double d2FixdL2 =
1500             gl0 * rr5
1501                 + (gl1 + gl6) * rr7
1502                 + (gl2 + gl7 + gl8) * rr9
1503                 + (gl3 + gl5) * rr11
1504                 + gl4 * rr13;
1505         dFixdL *= scale1;
1506         d2FixdL2 *= scale1;
1507         dUdL -= selfScale * (dEdLSign * dlPowPerm * efix + l2 * dlAlpha * dFixdL);
1508         d2UdL2 -=
1509             selfScale
1510                 * (dEdLSign
1511                 * (d2lPowPerm * efix
1512                 + dlPowPerm * dlAlpha * dFixdL
1513                 + dlPowPerm * dlAlpha * dFixdL)
1514                 + l2 * d2lAlpha * dFixdL
1515                 + l2 * dlAlpha * dlAlpha * d2FixdL2);
1516 
1517         // Collect terms for dU/dL/dX for the second term of dU/dL: d[fL2*dfL1dL*dRealdL]/dX
1518         final double gf1 =
1519             bn2 * gl0 + bn3 * (gl1 + gl6) + bn4 * (gl2 + gl7 + gl8) + bn5 * (gl3 + gl5) + bn6 * gl4;
1520         final double gf2 = -ck * bn2 + sc4 * bn3 - sc6 * bn4;
1521         final double gf3 = ci * bn2 + sc3 * bn3 + sc5 * bn4;
1522         final double gf4 = 2.0 * bn3;
1523         final double gf5 = 2.0 * (-ck * bn3 + sc4 * bn4 - sc6 * bn5);
1524         final double gf6 = 2.0 * (-ci * bn3 - sc3 * bn4 - sc5 * bn5);
1525         final double gf7 = 4.0 * bn4;
1526 
1527         // Get the permanent force with screening.
1528         double ftm2x =
1529             gf1 * xr
1530                 + gf2 * dix
1531                 + gf3 * dkx
1532                 + gf4 * (qkdix - qidkx)
1533                 + gf5 * qirx
1534                 + gf6 * qkrx
1535                 + gf7 * (qiqkrx + qkqirx);
1536         double ftm2y =
1537             gf1 * yr
1538                 + gf2 * diy
1539                 + gf3 * dky
1540                 + gf4 * (qkdiy - qidky)
1541                 + gf5 * qiry
1542                 + gf6 * qkry
1543                 + gf7 * (qiqkry + qkqiry);
1544         double ftm2z =
1545             gf1 * zr
1546                 + gf2 * diz
1547                 + gf3 * dkz
1548                 + gf4 * (qkdiz - qidkz)
1549                 + gf5 * qirz
1550                 + gf6 * qkrz
1551                 + gf7 * (qiqkrz + qkqirz);
1552 
1553         // Get the permanent torque with screening.
1554         double ttm2x =
1555             -bn2 * dixdkx
1556                 + gf2 * dixrx
1557                 + gf4 * (dixqkrx + dkxqirx + rxqidkx - 2.0 * qixqkx)
1558                 - gf5 * rxqirx
1559                 - gf7 * (rxqikrx + qkrxqirx);
1560         double ttm2y =
1561             -bn2 * dixdky
1562                 + gf2 * dixry
1563                 + gf4 * (dixqkry + dkxqiry + rxqidky - 2.0 * qixqky)
1564                 - gf5 * rxqiry
1565                 - gf7 * (rxqikry + qkrxqiry);
1566         double ttm2z =
1567             -bn2 * dixdkz
1568                 + gf2 * dixrz
1569                 + gf4 * (dixqkrz + dkxqirz + rxqidkz - 2.0 * qixqkz)
1570                 - gf5 * rxqirz
1571                 - gf7 * (rxqikrz + qkrxqirz);
1572         double ttm3x =
1573             bn2 * dixdkx
1574                 + gf3 * dkxrx
1575                 - gf4 * (dixqkrx + dkxqirx + rxqkdix - 2.0 * qixqkx)
1576                 - gf6 * rxqkrx
1577                 - gf7 * (rxqkirx - qkrxqirx);
1578         double ttm3y =
1579             bn2 * dixdky
1580                 + gf3 * dkxry
1581                 - gf4 * (dixqkry + dkxqiry + rxqkdiy - 2.0 * qixqky)
1582                 - gf6 * rxqkry
1583                 - gf7 * (rxqkiry - qkrxqiry);
1584         double ttm3z =
1585             bn2 * dixdkz
1586                 + gf3 * dkxrz
1587                 - gf4 * (dixqkrz + dkxqirz + rxqkdiz - 2.0 * qixqkz)
1588                 - gf6 * rxqkrz
1589                 - gf7 * (rxqkirz - qkrxqirz);
1590 
1591         // Handle the case where scaling is used.
1592         if (scale1 != 0.0) {
1593           final double gfr1 =
1594               rr5 * gl0
1595                   + rr7 * (gl1 + gl6)
1596                   + rr9 * (gl2 + gl7 + gl8)
1597                   + rr11 * (gl3 + gl5)
1598                   + rr13 * gl4;
1599           final double gfr2 = -ck * rr5 + sc4 * rr7 - sc6 * rr9;
1600           final double gfr3 = ci * rr5 + sc3 * rr7 + sc5 * rr9;
1601           final double gfr4 = 2.0 * rr7;
1602           final double gfr5 = 2.0 * (-ck * rr7 + sc4 * rr9 - sc6 * rr11);
1603           final double gfr6 = 2.0 * (-ci * rr7 - sc3 * rr9 - sc5 * rr11);
1604           final double gfr7 = 4.0 * rr9;
1605 
1606           // Get the permanent force without screening.
1607           final double ftm2rx =
1608               gfr1 * xr
1609                   + gfr2 * dix
1610                   + gfr3 * dkx
1611                   + gfr4 * (qkdix - qidkx)
1612                   + gfr5 * qirx
1613                   + gfr6 * qkrx
1614                   + gfr7 * (qiqkrx + qkqirx);
1615           final double ftm2ry =
1616               gfr1 * yr
1617                   + gfr2 * diy
1618                   + gfr3 * dky
1619                   + gfr4 * (qkdiy - qidky)
1620                   + gfr5 * qiry
1621                   + gfr6 * qkry
1622                   + gfr7 * (qiqkry + qkqiry);
1623           final double ftm2rz =
1624               gfr1 * zr
1625                   + gfr2 * diz
1626                   + gfr3 * dkz
1627                   + gfr4 * (qkdiz - qidkz)
1628                   + gfr5 * qirz
1629                   + gfr6 * qkrz
1630                   + gfr7 * (qiqkrz + qkqirz);
1631 
1632           // Get the permanent torque without screening.
1633           final double ttm2rx =
1634               -rr5 * dixdkx
1635                   + gfr2 * dixrx
1636                   + gfr4 * (dixqkrx + dkxqirx + rxqidkx - 2.0 * qixqkx)
1637                   - gfr5 * rxqirx
1638                   - gfr7 * (rxqikrx + qkrxqirx);
1639           final double ttm2ry =
1640               -rr5 * dixdky
1641                   + gfr2 * dixry
1642                   + gfr4 * (dixqkry + dkxqiry + rxqidky - 2.0 * qixqky)
1643                   - gfr5 * rxqiry
1644                   - gfr7 * (rxqikry + qkrxqiry);
1645           final double ttm2rz =
1646               -rr5 * dixdkz
1647                   + gfr2 * dixrz
1648                   + gfr4 * (dixqkrz + dkxqirz + rxqidkz - 2.0 * qixqkz)
1649                   - gfr5 * rxqirz
1650                   - gfr7 * (rxqikrz + qkrxqirz);
1651           final double ttm3rx =
1652               rr5 * dixdkx
1653                   + gfr3 * dkxrx
1654                   - gfr4 * (dixqkrx + dkxqirx + rxqkdix - 2.0 * qixqkx)
1655                   - gfr6 * rxqkrx
1656                   - gfr7 * (rxqkirx - qkrxqirx);
1657           final double ttm3ry =
1658               rr5 * dixdky
1659                   + gfr3 * dkxry
1660                   - gfr4 * (dixqkry + dkxqiry + rxqkdiy - 2.0 * qixqky)
1661                   - gfr6 * rxqkry
1662                   - gfr7 * (rxqkiry - qkrxqiry);
1663           final double ttm3rz =
1664               rr5 * dixdkz
1665                   + gfr3 * dkxrz
1666                   - gfr4 * (dixqkrz + dkxqirz + rxqkdiz - 2.0 * qixqkz)
1667                   - gfr6 * rxqkrz
1668                   - gfr7 * (rxqkirz - qkrxqirz);
1669           ftm2x -= scale1 * ftm2rx;
1670           ftm2y -= scale1 * ftm2ry;
1671           ftm2z -= scale1 * ftm2rz;
1672           ttm2x -= scale1 * ttm2rx;
1673           ttm2y -= scale1 * ttm2ry;
1674           ttm2z -= scale1 * ttm2rz;
1675           ttm3x -= scale1 * ttm3rx;
1676           ttm3y -= scale1 * ttm3ry;
1677           ttm3z -= scale1 * ttm3rz;
1678         }
1679 
1680         // Add in dU/dL/dX for the second term of dU/dL: d[lPow*dlAlpha*dRealdL]/dX
1681         double prefactor = electric * selfScale * l2 * dlAlpha;
1682         lambdaGrad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
1683         lambdaTorque.add(threadID, i, prefactor * ttm2x, prefactor * ttm2y, prefactor * ttm2z);
1684         lxk_local[k] -= prefactor * ftm2x;
1685         lyk_local[k] -= prefactor * ftm2y;
1686         lzk_local[k] -= prefactor * ftm2z;
1687         ltxk_local[k] += prefactor * ttm3x;
1688         ltyk_local[k] += prefactor * ttm3y;
1689         ltzk_local[k] += prefactor * ttm3z;
1690       }
1691 
1692       return e;
1693     }
1694 
1695     /**
1696      * Evaluate the polarization energy for a pair of polarizable multipole sites.
1697      *
1698      * @return the polarization energy.
1699      */
1700     private double polarizationPair(boolean gradientLocal, boolean lambdaTermLocal) {
1701       final double dsc3 = 1.0 - scale3 * scaled;
1702       final double dsc5 = 1.0 - scale5 * scaled;
1703       final double dsc7 = 1.0 - scale7 * scaled;
1704       final double psc3 = 1.0 - scale3 * scalep;
1705       final double psc5 = 1.0 - scale5 * scalep;
1706       final double psc7 = 1.0 - scale7 * scalep;
1707       final double usc3 = 1.0 - scale3;
1708       final double usc5 = 1.0 - scale5;
1709 
1710       final double dixukx = diy * ukz - diz * uky;
1711       final double dixuky = diz * ukx - dix * ukz;
1712       final double dixukz = dix * uky - diy * ukx;
1713       final double dkxuix = dky * uiz - dkz * uiy;
1714       final double dkxuiy = dkz * uix - dkx * uiz;
1715       final double dkxuiz = dkx * uiy - dky * uix;
1716       final double dixukpx = diy * pkz - diz * pky;
1717       final double dixukpy = diz * pkx - dix * pkz;
1718       final double dixukpz = dix * pky - diy * pkx;
1719       final double dkxuipx = dky * piz - dkz * piy;
1720       final double dkxuipy = dkz * pix - dkx * piz;
1721       final double dkxuipz = dkx * piy - dky * pix;
1722       final double dixrx = diy * zr - diz * yr;
1723       final double dixry = diz * xr - dix * zr;
1724       final double dixrz = dix * yr - diy * xr;
1725       final double dkxrx = dky * zr - dkz * yr;
1726       final double dkxry = dkz * xr - dkx * zr;
1727       final double dkxrz = dkx * yr - dky * xr;
1728       final double qirx = qixx * xr + qixy * yr + qixz * zr;
1729       final double qiry = qixy * xr + qiyy * yr + qiyz * zr;
1730       final double qirz = qixz * xr + qiyz * yr + qizz * zr;
1731       final double qkrx = qkxx * xr + qkxy * yr + qkxz * zr;
1732       final double qkry = qkxy * xr + qkyy * yr + qkyz * zr;
1733       final double qkrz = qkxz * xr + qkyz * yr + qkzz * zr;
1734       final double rxqirx = yr * qirz - zr * qiry;
1735       final double rxqiry = zr * qirx - xr * qirz;
1736       final double rxqirz = xr * qiry - yr * qirx;
1737       final double rxqkrx = yr * qkrz - zr * qkry;
1738       final double rxqkry = zr * qkrx - xr * qkrz;
1739       final double rxqkrz = xr * qkry - yr * qkrx;
1740       final double qiukx = qixx * ukx + qixy * uky + qixz * ukz;
1741       final double qiuky = qixy * ukx + qiyy * uky + qiyz * ukz;
1742       final double qiukz = qixz * ukx + qiyz * uky + qizz * ukz;
1743       final double qkuix = qkxx * uix + qkxy * uiy + qkxz * uiz;
1744       final double qkuiy = qkxy * uix + qkyy * uiy + qkyz * uiz;
1745       final double qkuiz = qkxz * uix + qkyz * uiy + qkzz * uiz;
1746       final double qiukpx = qixx * pkx + qixy * pky + qixz * pkz;
1747       final double qiukpy = qixy * pkx + qiyy * pky + qiyz * pkz;
1748       final double qiukpz = qixz * pkx + qiyz * pky + qizz * pkz;
1749       final double qkuipx = qkxx * pix + qkxy * piy + qkxz * piz;
1750       final double qkuipy = qkxy * pix + qkyy * piy + qkyz * piz;
1751       final double qkuipz = qkxz * pix + qkyz * piy + qkzz * piz;
1752       final double uixqkrx = uiy * qkrz - uiz * qkry;
1753       final double uixqkry = uiz * qkrx - uix * qkrz;
1754       final double uixqkrz = uix * qkry - uiy * qkrx;
1755       final double ukxqirx = uky * qirz - ukz * qiry;
1756       final double ukxqiry = ukz * qirx - ukx * qirz;
1757       final double ukxqirz = ukx * qiry - uky * qirx;
1758       final double uixqkrpx = piy * qkrz - piz * qkry;
1759       final double uixqkrpy = piz * qkrx - pix * qkrz;
1760       final double uixqkrpz = pix * qkry - piy * qkrx;
1761       final double ukxqirpx = pky * qirz - pkz * qiry;
1762       final double ukxqirpy = pkz * qirx - pkx * qirz;
1763       final double ukxqirpz = pkx * qiry - pky * qirx;
1764       final double rxqiukx = yr * qiukz - zr * qiuky;
1765       final double rxqiuky = zr * qiukx - xr * qiukz;
1766       final double rxqiukz = xr * qiuky - yr * qiukx;
1767       final double rxqkuix = yr * qkuiz - zr * qkuiy;
1768       final double rxqkuiy = zr * qkuix - xr * qkuiz;
1769       final double rxqkuiz = xr * qkuiy - yr * qkuix;
1770       final double rxqiukpx = yr * qiukpz - zr * qiukpy;
1771       final double rxqiukpy = zr * qiukpx - xr * qiukpz;
1772       final double rxqiukpz = xr * qiukpy - yr * qiukpx;
1773       final double rxqkuipx = yr * qkuipz - zr * qkuipy;
1774       final double rxqkuipy = zr * qkuipx - xr * qkuipz;
1775       final double rxqkuipz = xr * qkuipy - yr * qkuipx;
1776 
1777       // Calculate the scalar products for permanent multipoles.
1778       final double sc3 = dix * xr + diy * yr + diz * zr;
1779       final double sc4 = dkx * xr + dky * yr + dkz * zr;
1780       final double sc5 = qirx * xr + qiry * yr + qirz * zr;
1781       final double sc6 = qkrx * xr + qkry * yr + qkrz * zr;
1782 
1783       // Calculate the scalar products for polarization components.
1784       final double sci1 = uix * dkx + uiy * dky + uiz * dkz + dix * ukx + diy * uky + diz * ukz;
1785       final double sci3 = uix * xr + uiy * yr + uiz * zr;
1786       final double sci4 = ukx * xr + uky * yr + ukz * zr;
1787       final double sci7 = qirx * ukx + qiry * uky + qirz * ukz;
1788       final double sci8 = qkrx * uix + qkry * uiy + qkrz * uiz;
1789       final double scip1 = pix * dkx + piy * dky + piz * dkz + dix * pkx + diy * pky + diz * pkz;
1790       final double scip2 = uix * pkx + uiy * pky + uiz * pkz + pix * ukx + piy * uky + piz * ukz;
1791       final double scip3 = pix * xr + piy * yr + piz * zr;
1792       final double scip4 = pkx * xr + pky * yr + pkz * zr;
1793       final double scip7 = qirx * pkx + qiry * pky + qirz * pkz;
1794       final double scip8 = qkrx * pix + qkry * piy + qkrz * piz;
1795 
1796       // Calculate the gl functions for polarization components.
1797       final double gli1 = ck * sci3 - ci * sci4;
1798       final double gli2 = -sc3 * sci4 - sci3 * sc4;
1799       final double gli3 = sci3 * sc6 - sci4 * sc5;
1800       final double gli6 = sci1;
1801       final double gli7 = 2.0 * (sci7 - sci8);
1802       final double glip1 = ck * scip3 - ci * scip4;
1803       final double glip2 = -sc3 * scip4 - scip3 * sc4;
1804       final double glip3 = scip3 * sc6 - scip4 * sc5;
1805       final double glip6 = scip1;
1806       final double glip7 = 2.0 * (scip7 - scip8);
1807 
1808       // Compute the energy contributions for this interaction.
1809       final double ereal = (gli1 + gli6) * bn1 + (gli2 + gli7) * bn2 + gli3 * bn3;
1810       final double efix =
1811           (gli1 + gli6) * rr3 * psc3 + (gli2 + gli7) * rr5 * psc5 + gli3 * rr7 * psc7;
1812       final double e = selfScale * 0.5 * (ereal - efix);
1813 
1814       // logger.info(format(" %d %d Polarization Energy (real): %17.15f", i, k, 0.5 * ereal));
1815       // logger.info(format(" %d %d Polarization Energy (fix) : %17.15f", i, k, -0.5 * efix));
1816 
1817       if (!(gradientLocal || lambdaTermLocal)) {
1818         return polarizationScale * e;
1819       }
1820       boolean dorli = false;
1821       if (psc3 != 0.0 || dsc3 != 0.0 || usc3 != 0.0) {
1822         dorli = true;
1823       }
1824 
1825       // Get the induced force with screening.
1826       final double gfi1 =
1827           0.5 * bn2 * (gli1 + glip1 + gli6 + glip6)
1828               + 0.5 * bn2 * scip2
1829               + 0.5 * bn3 * (gli2 + glip2 + gli7 + glip7)
1830               - 0.5 * bn3 * (sci3 * scip4 + scip3 * sci4)
1831               + 0.5 * bn4 * (gli3 + glip3);
1832       final double gfi2 = -ck * bn1 + sc4 * bn2 - sc6 * bn3;
1833       final double gfi3 = ci * bn1 + sc3 * bn2 + sc5 * bn3;
1834       final double gfi4 = 2.0 * bn2;
1835       final double gfi5 = bn3 * (sci4 + scip4);
1836       final double gfi6 = -bn3 * (sci3 + scip3);
1837       double ftm2ix =
1838           gfi1 * xr
1839               + 0.5
1840               * (gfi2 * (uix + pix)
1841               + bn2 * (sci4 * pix + scip4 * uix)
1842               + gfi3 * (ukx + pkx)
1843               + bn2 * (sci3 * pkx + scip3 * ukx)
1844               + (sci4 + scip4) * bn2 * dix
1845               + (sci3 + scip3) * bn2 * dkx
1846               + gfi4 * (qkuix + qkuipx - qiukx - qiukpx))
1847               + gfi5 * qirx
1848               + gfi6 * qkrx;
1849       double ftm2iy =
1850           gfi1 * yr
1851               + 0.5
1852               * (gfi2 * (uiy + piy)
1853               + bn2 * (sci4 * piy + scip4 * uiy)
1854               + gfi3 * (uky + pky)
1855               + bn2 * (sci3 * pky + scip3 * uky)
1856               + (sci4 + scip4) * bn2 * diy
1857               + (sci3 + scip3) * bn2 * dky
1858               + gfi4 * (qkuiy + qkuipy - qiuky - qiukpy))
1859               + gfi5 * qiry
1860               + gfi6 * qkry;
1861       double ftm2iz =
1862           gfi1 * zr
1863               + 0.5
1864               * (gfi2 * (uiz + piz)
1865               + bn2 * (sci4 * piz + scip4 * uiz)
1866               + gfi3 * (ukz + pkz)
1867               + bn2 * (sci3 * pkz + scip3 * ukz)
1868               + (sci4 + scip4) * bn2 * diz
1869               + (sci3 + scip3) * bn2 * dkz
1870               + gfi4 * (qkuiz + qkuipz - qiukz - qiukpz))
1871               + gfi5 * qirz
1872               + gfi6 * qkrz;
1873 
1874       // Get the induced torque with screening.
1875       final double gti2 = 0.5 * bn2 * (sci4 + scip4);
1876       final double gti3 = 0.5 * bn2 * (sci3 + scip3);
1877       final double gti4 = gfi4;
1878       final double gti5 = gfi5;
1879       final double gti6 = gfi6;
1880       double ttm2ix =
1881           -0.5 * bn1 * (dixukx + dixukpx)
1882               + gti2 * dixrx
1883               - gti5 * rxqirx
1884               + 0.5 * gti4 * (ukxqirx + rxqiukx + ukxqirpx + rxqiukpx);
1885       double ttm2iy =
1886           -0.5 * bn1 * (dixuky + dixukpy)
1887               + gti2 * dixry
1888               - gti5 * rxqiry
1889               + 0.5 * gti4 * (ukxqiry + rxqiuky + ukxqirpy + rxqiukpy);
1890       double ttm2iz =
1891           -0.5 * bn1 * (dixukz + dixukpz)
1892               + gti2 * dixrz
1893               - gti5 * rxqirz
1894               + 0.5 * gti4 * (ukxqirz + rxqiukz + ukxqirpz + rxqiukpz);
1895       double ttm3ix =
1896           -0.5 * bn1 * (dkxuix + dkxuipx)
1897               + gti3 * dkxrx
1898               - gti6 * rxqkrx
1899               - 0.5 * gti4 * (uixqkrx + rxqkuix + uixqkrpx + rxqkuipx);
1900       double ttm3iy =
1901           -0.5 * bn1 * (dkxuiy + dkxuipy)
1902               + gti3 * dkxry
1903               - gti6 * rxqkry
1904               - 0.5 * gti4 * (uixqkry + rxqkuiy + uixqkrpy + rxqkuipy);
1905       double ttm3iz =
1906           -0.5 * bn1 * (dkxuiz + dkxuipz)
1907               + gti3 * dkxrz
1908               - gti6 * rxqkrz
1909               - 0.5 * gti4 * (uixqkrz + rxqkuiz + uixqkrpz + rxqkuipz);
1910       double ftm2rix = 0.0;
1911       double ftm2riy = 0.0;
1912       double ftm2riz = 0.0;
1913       double ttm2rix = 0.0;
1914       double ttm2riy = 0.0;
1915       double ttm2riz = 0.0;
1916       double ttm3rix = 0.0;
1917       double ttm3riy = 0.0;
1918       double ttm3riz = 0.0;
1919       if (dorli) {
1920         // Get the induced force without screening.
1921         final double gfri1 =
1922             0.5 * rr5 * ((gli1 + gli6) * psc3 + (glip1 + glip6) * dsc3 + scip2 * usc3)
1923                 + 0.5
1924                 * rr7
1925                 * ((gli7 + gli2) * psc5
1926                 + (glip7 + glip2) * dsc5
1927                 - (sci3 * scip4 + scip3 * sci4) * usc5)
1928                 + 0.5 * rr9 * (gli3 * psc7 + glip3 * dsc7);
1929         final double gfri4 = 2.0 * rr5;
1930         final double gfri5 = rr7 * (sci4 * psc7 + scip4 * dsc7);
1931         final double gfri6 = -rr7 * (sci3 * psc7 + scip3 * dsc7);
1932         ftm2rix =
1933             gfri1 * xr
1934                 + 0.5
1935                 * (-rr3 * ck * (uix * psc3 + pix * dsc3)
1936                 + rr5 * sc4 * (uix * psc5 + pix * dsc5)
1937                 - rr7 * sc6 * (uix * psc7 + pix * dsc7))
1938                 + (rr3 * ci * (ukx * psc3 + pkx * dsc3)
1939                 + rr5 * sc3 * (ukx * psc5 + pkx * dsc5)
1940                 + rr7 * sc5 * (ukx * psc7 + pkx * dsc7))
1941                 * 0.5
1942                 + rr5 * usc5 * (sci4 * pix + scip4 * uix + sci3 * pkx + scip3 * ukx) * 0.5
1943                 + 0.5 * (sci4 * psc5 + scip4 * dsc5) * rr5 * dix
1944                 + 0.5 * (sci3 * psc5 + scip3 * dsc5) * rr5 * dkx
1945                 + 0.5 * gfri4 * ((qkuix - qiukx) * psc5 + (qkuipx - qiukpx) * dsc5)
1946                 + gfri5 * qirx
1947                 + gfri6 * qkrx;
1948         ftm2riy =
1949             gfri1 * yr
1950                 + 0.5
1951                 * (-rr3 * ck * (uiy * psc3 + piy * dsc3)
1952                 + rr5 * sc4 * (uiy * psc5 + piy * dsc5)
1953                 - rr7 * sc6 * (uiy * psc7 + piy * dsc7))
1954                 + (rr3 * ci * (uky * psc3 + pky * dsc3)
1955                 + rr5 * sc3 * (uky * psc5 + pky * dsc5)
1956                 + rr7 * sc5 * (uky * psc7 + pky * dsc7))
1957                 * 0.5
1958                 + rr5 * usc5 * (sci4 * piy + scip4 * uiy + sci3 * pky + scip3 * uky) * 0.5
1959                 + 0.5 * (sci4 * psc5 + scip4 * dsc5) * rr5 * diy
1960                 + 0.5 * (sci3 * psc5 + scip3 * dsc5) * rr5 * dky
1961                 + 0.5 * gfri4 * ((qkuiy - qiuky) * psc5 + (qkuipy - qiukpy) * dsc5)
1962                 + gfri5 * qiry
1963                 + gfri6 * qkry;
1964         ftm2riz =
1965             gfri1 * zr
1966                 + 0.5
1967                 * (-rr3 * ck * (uiz * psc3 + piz * dsc3)
1968                 + rr5 * sc4 * (uiz * psc5 + piz * dsc5)
1969                 - rr7 * sc6 * (uiz * psc7 + piz * dsc7))
1970                 + (rr3 * ci * (ukz * psc3 + pkz * dsc3)
1971                 + rr5 * sc3 * (ukz * psc5 + pkz * dsc5)
1972                 + rr7 * sc5 * (ukz * psc7 + pkz * dsc7))
1973                 * 0.5
1974                 + rr5 * usc5 * (sci4 * piz + scip4 * uiz + sci3 * pkz + scip3 * ukz) * 0.5
1975                 + 0.5 * (sci4 * psc5 + scip4 * dsc5) * rr5 * diz
1976                 + 0.5 * (sci3 * psc5 + scip3 * dsc5) * rr5 * dkz
1977                 + 0.5 * gfri4 * ((qkuiz - qiukz) * psc5 + (qkuipz - qiukpz) * dsc5)
1978                 + gfri5 * qirz
1979                 + gfri6 * qkrz;
1980 
1981         // Get the induced torque without screening.
1982         final double gtri2 = 0.5 * rr5 * (sci4 * psc5 + scip4 * dsc5);
1983         final double gtri3 = 0.5 * rr5 * (sci3 * psc5 + scip3 * dsc5);
1984         final double gtri4 = gfri4;
1985         final double gtri5 = gfri5;
1986         final double gtri6 = gfri6;
1987         ttm2rix =
1988             -rr3 * (dixukx * psc3 + dixukpx * dsc3) * 0.5
1989                 + gtri2 * dixrx
1990                 - gtri5 * rxqirx
1991                 + gtri4 * ((ukxqirx + rxqiukx) * psc5 + (ukxqirpx + rxqiukpx) * dsc5) * 0.5;
1992         ttm2riy =
1993             -rr3 * (dixuky * psc3 + dixukpy * dsc3) * 0.5
1994                 + gtri2 * dixry
1995                 - gtri5 * rxqiry
1996                 + gtri4 * ((ukxqiry + rxqiuky) * psc5 + (ukxqirpy + rxqiukpy) * dsc5) * 0.5;
1997         ttm2riz =
1998             -rr3 * (dixukz * psc3 + dixukpz * dsc3) * 0.5
1999                 + gtri2 * dixrz
2000                 - gtri5 * rxqirz
2001                 + gtri4 * ((ukxqirz + rxqiukz) * psc5 + (ukxqirpz + rxqiukpz) * dsc5) * 0.5;
2002         ttm3rix =
2003             -rr3 * (dkxuix * psc3 + dkxuipx * dsc3) * 0.5
2004                 + gtri3 * dkxrx
2005                 - gtri6 * rxqkrx
2006                 - gtri4 * ((uixqkrx + rxqkuix) * psc5 + (uixqkrpx + rxqkuipx) * dsc5) * 0.5;
2007         ttm3riy =
2008             -rr3 * (dkxuiy * psc3 + dkxuipy * dsc3) * 0.5
2009                 + gtri3 * dkxry
2010                 - gtri6 * rxqkry
2011                 - gtri4 * ((uixqkry + rxqkuiy) * psc5 + (uixqkrpy + rxqkuipy) * dsc5) * 0.5;
2012         ttm3riz =
2013             -rr3 * (dkxuiz * psc3 + dkxuipz * dsc3) * 0.5
2014                 + gtri3 * dkxrz
2015                 - gtri6 * rxqkrz
2016                 - gtri4 * ((uixqkrz + rxqkuiz) * psc5 + (uixqkrpz + rxqkuipz) * dsc5) * 0.5;
2017       }
2018 
2019       // Account for partially excluded induced interactions.
2020       double temp3 = 0.5 * rr3 * ((gli1 + gli6) * scalep + (glip1 + glip6) * scaled);
2021       double temp5 = 0.5 * rr5 * ((gli2 + gli7) * scalep + (glip2 + glip7) * scaled);
2022       final double temp7 = 0.5 * rr7 * (gli3 * scalep + glip3 * scaled);
2023       final double fridmpx = temp3 * ddsc3x + temp5 * ddsc5x + temp7 * ddsc7x;
2024       final double fridmpy = temp3 * ddsc3y + temp5 * ddsc5y + temp7 * ddsc7y;
2025       final double fridmpz = temp3 * ddsc3z + temp5 * ddsc5z + temp7 * ddsc7z;
2026 
2027       // Find some scaling terms for induced-induced force.
2028       temp3 = 0.5 * rr3 * scip2;
2029       temp5 = -0.5 * rr5 * (sci3 * scip4 + scip3 * sci4);
2030       final double findmpx = temp3 * ddsc3x + temp5 * ddsc5x;
2031       final double findmpy = temp3 * ddsc3y + temp5 * ddsc5y;
2032       final double findmpz = temp3 * ddsc3z + temp5 * ddsc5z;
2033 
2034 //      logger.info(format(" %d %d Ewald Polarization grad (i):   %17.15f %17.15f %17.15f", i, k, ftm2ix, ftm2iy, ftm2iz));
2035 //      logger.info(format(" %d %d Ewald Polarization torque (i): %17.15f %17.15f %17.15f", i, k, ttm2ix, ttm2iy, ttm2iz));
2036 //      logger.info(format(" %d %d Ewald Polarization torque (k): %17.15f %17.15f %17.15f", i, k, ttm3ix, ttm3iy, ttm3iz));
2037 
2038       // Modify the forces for partially excluded interactions.
2039       ftm2ix = ftm2ix - fridmpx - findmpx;
2040       ftm2iy = ftm2iy - fridmpy - findmpy;
2041       ftm2iz = ftm2iz - fridmpz - findmpz;
2042 
2043       // Correction to convert mutual to direct polarization force.
2044       if (polarization == Polarization.DIRECT) {
2045         final double gfd = 0.5 * (bn2 * scip2 - bn3 * (scip3 * sci4 + sci3 * scip4));
2046         final double gfdr = 0.5 * (rr5 * scip2 * usc3 - rr7 * (scip3 * sci4 + sci3 * scip4) * usc5);
2047         ftm2ix = ftm2ix - gfd * xr - 0.5 * bn2 * (sci4 * pix + scip4 * uix + sci3 * pkx + scip3 * ukx);
2048         ftm2iy = ftm2iy - gfd * yr - 0.5 * bn2 * (sci4 * piy + scip4 * uiy + sci3 * pky + scip3 * uky);
2049         ftm2iz = ftm2iz - gfd * zr - 0.5 * bn2 * (sci4 * piz + scip4 * uiz + sci3 * pkz + scip3 * ukz);
2050         final double fdirx = gfdr * xr + 0.5 * usc5 * rr5 * (sci4 * pix + scip4 * uix + sci3 * pkx + scip3 * ukx);
2051         final double fdiry = gfdr * yr + 0.5 * usc5 * rr5 * (sci4 * piy + scip4 * uiy + sci3 * pky + scip3 * uky);
2052         final double fdirz = gfdr * zr + 0.5 * usc5 * rr5 * (sci4 * piz + scip4 * uiz + sci3 * pkz + scip3 * ukz);
2053         ftm2ix = ftm2ix + fdirx + findmpx;
2054         ftm2iy = ftm2iy + fdiry + findmpy;
2055         ftm2iz = ftm2iz + fdirz + findmpz;
2056       }
2057 
2058       // Correction for OPT induced dipoles.
2059       //            if (scfAlgorithm == ParticleMeshEwald.SCFAlgorithm.EPT) {
2060       //                double eptx = 0.0;
2061       //                double epty = 0.0;
2062       //                double eptz = 0.0;
2063       //                for (int jj = 0; jj < optOrder; jj++) {
2064       //                    double optix = optDipole[jj][i][0];
2065       //                    double optiy = optDipole[jj][i][1];
2066       //                    double optiz = optDipole[jj][i][2];
2067       //                    double optixp = optDipoleCR[jj][i][0];
2068       //                    double optiyp = optDipoleCR[jj][i][1];
2069       //                    double optizp = optDipoleCR[jj][i][2];
2070       //                    double uirm = optix * xr + optiy * yr + optiz * zr;
2071       //                    for (int mm = 0; mm < optOrder - jj; mm++) {
2072       //                        double optkx = optDipole[mm][k][0];
2073       //                        double optky = optDipole[mm][k][1];
2074       //                        double optkz = optDipole[mm][k][2];
2075       //                        double optkxp = optDipoleCR[mm][k][0];
2076       //                        double optkyp = optDipoleCR[mm][k][1];
2077       //                        double optkzp = optDipoleCR[mm][k][2];
2078       //                        double ukrm = optkx * xr + optky * yr + optkz * zr;
2079       //                        double term1 = bn2 - usc3 * rr5;
2080       //                        double term2 = bn3 - usc5 * rr7;
2081       //                        double term3 = usr5 + term1;
2082       //                        double term4 = rr3;
2083       //                        double term5 = -xr * term3 + ddsc3x * term4;
2084       //                        double term6 = -(bn2 - usc5 * rr5) + xr * xr * term2 - rr5 * xr *
2085       // ddsc5x;
2086       //                        double tixx = optix * term5 + uirm * term6;
2087       //                        double tkxx = optkx * term5 + ukrm * term6;
2088       //                        term5 = -yr * term3 + ddsc3y * term4;
2089       //                        term6 = -usr5 + yr * yr * term2 - rr5 * yr * ddsc5y;
2090       //                        double tiyy = optiy * term5 + uirm * term6;
2091       //                        double tkyy = optky * term5 + ukrm * term6;
2092       //                        term5 = -zr * term3 + ddsc3z * term4;
2093       //                        term6 = -usr5 + zr * zr * term2 - rr5 * zr * ddsc5z;
2094       //                        double tizz = optiz * term5 + uirm * term6;
2095       //                        double tkzz = optkz * term5 + ukrm * term6;
2096       //                        term4 = -usr5 * yr;
2097       //                        term5 = -xr * term1 + rr3 * ddsc3x;
2098       //                        term6 = xr * yr * term2 - rr5 * yr * ddsc5x;
2099       //                        double tixy = optix * term4 + optiy * term5 + uirm * term6;
2100       //                        double tkxy = optkx * term4 + optky * term5 + ukrm * term6;
2101       //                        term4 = -usr5 * zr;
2102       //                        term6 = xr * zr * term2 - rr5 * zr * ddsc5x;
2103       //                        double tixz = optix * term4 + optiz * term5 + uirm * term6;
2104       //                        double tkxz = optkx * term4 + optkz * term5 + ukrm * term6;
2105       //                        term5 = -yr * term1 + rr3 * ddsc3y;
2106       //                        term6 = yr * zr * term2 - rr5 * zr * ddsc5y;
2107       //                        double tiyz = optiy * term4 + optiz * term5 + uirm * term6;
2108       //                        double tkyz = optkz * term4 + optkz * term5 + ukrm * term6;
2109       //                        double depx = tixx * optkxp + tkxx * optixp
2110       //                                + tixy * optkyp + tkxy * optiyp
2111       //                                + tixz * optkzp + tkxz * optizp;
2112       //                        double depy = tixy * optkxp + tkxy * optixp
2113       //                                + tiyy * optkyp + tkyy * optiyp
2114       //                                + tiyz * optkzp + tkyz * optizp;
2115       //                        double depz = tixz * optkxp + tkxz * optixp
2116       //                                + tiyz * optkyp + tkyz * optiyp
2117       //                                + tizz * optkzp + tkzz * optizp;
2118       //                        double optCoefSum = optRegion.optCoefficientsSum[jj + mm + 1];
2119       //                        double fx = optCoefSum * depx;
2120       //                        double fy = optCoefSum * depy;
2121       //                        double fz = optCoefSum * depz;
2122       //                        eptx += fx;
2123       //                        epty += fy;
2124       //                        eptz += fz;
2125       //                    }
2126       //                }
2127       //                if (i == 0 && k == 1) {
2128       //                    logger.info(format(" %s %16.8f %16.8f %16.8f", "ept force", eptx, epty,
2129       // eptz));
2130       //                }
2131       //                ftm2ix += eptx;
2132       //                ftm2iy += epty;
2133       //                ftm2iz += eptz;
2134       //            }
2135 
2136       // Handle the case where scaling is used.
2137 
2138 //      logger.info(format(" %d %d Polarization Coulomb grad (i):   %17.15f %17.15f %17.15f", i, k,
2139 //          -ftm2rix - fridmpx - findmpx, -ftm2riy - fridmpy - findmpy, -ftm2riz - fridmpz - findmpz));
2140 //      logger.info(format(" %d %d Polarization Thole torque (i): %17.15f %17.15f %17.15f", i, k, -ttm2rix, -ttm2riy, -ttm2riz));
2141 //      logger.info(format(" %d %d Polarization Thole torque (k): %17.15f %17.15f %17.15f", i, k, -ttm3rix, -ttm3riy, -ttm3riz));
2142 
2143       ftm2ix = ftm2ix - ftm2rix;
2144       ftm2iy = ftm2iy - ftm2riy;
2145       ftm2iz = ftm2iz - ftm2riz;
2146       ttm2ix = ttm2ix - ttm2rix;
2147       ttm2iy = ttm2iy - ttm2riy;
2148       ttm2iz = ttm2iz - ttm2riz;
2149       ttm3ix = ttm3ix - ttm3rix;
2150       ttm3iy = ttm3iy - ttm3riy;
2151       ttm3iz = ttm3iz - ttm3riz;
2152 
2153       double scalar = electric * polarizationScale * selfScale;
2154 
2155       grad.add(threadID, i, scalar * ftm2ix, scalar * ftm2iy, scalar * ftm2iz);
2156       torque.add(threadID, i, scalar * ttm2ix, scalar * ttm2iy, scalar * ttm2iz);
2157       gxk_local[k] -= scalar * ftm2ix;
2158       gyk_local[k] -= scalar * ftm2iy;
2159       gzk_local[k] -= scalar * ftm2iz;
2160       txk_local[k] += scalar * ttm3ix;
2161       tyk_local[k] += scalar * ttm3iy;
2162       tzk_local[k] += scalar * ttm3iz;
2163       if (lambdaTermLocal) {
2164         dUdL += dEdLSign * dlPowPol * e;
2165         d2UdL2 += dEdLSign * d2lPowPol * e;
2166         scalar = electric * dEdLSign * dlPowPol * selfScale;
2167         lambdaGrad.add(threadID, i, scalar * ftm2ix, scalar * ftm2iy, scalar * ftm2iz);
2168         lambdaTorque.add(threadID, i, scalar * ttm2ix, scalar * ttm2iy, scalar * ttm2iz);
2169         lxk_local[k] -= scalar * ftm2ix;
2170         lyk_local[k] -= scalar * ftm2iy;
2171         lzk_local[k] -= scalar * ftm2iz;
2172         ltxk_local[k] += scalar * ttm3ix;
2173         ltyk_local[k] += scalar * ttm3iy;
2174         ltzk_local[k] += scalar * ttm3iz;
2175       }
2176       return polarizationScale * e;
2177     }
2178 
2179     private void setMultipoleI(double[] globalMultipolei) {
2180       ci = globalMultipolei[t000];
2181       dix = globalMultipolei[t100];
2182       diy = globalMultipolei[t010];
2183       diz = globalMultipolei[t001];
2184       qixx = globalMultipolei[t200] * oneThird;
2185       qiyy = globalMultipolei[t020] * oneThird;
2186       qizz = globalMultipolei[t002] * oneThird;
2187       qixy = globalMultipolei[t110] * oneThird;
2188       qixz = globalMultipolei[t101] * oneThird;
2189       qiyz = globalMultipolei[t011] * oneThird;
2190     }
2191 
2192     private void setMultipoleK(double[] globalMultipolek) {
2193       ck = globalMultipolek[t000];
2194       dkx = globalMultipolek[t100];
2195       dky = globalMultipolek[t010];
2196       dkz = globalMultipolek[t001];
2197       qkxx = globalMultipolek[t200] * oneThird;
2198       qkyy = globalMultipolek[t020] * oneThird;
2199       qkzz = globalMultipolek[t002] * oneThird;
2200       qkxy = globalMultipolek[t110] * oneThird;
2201       qkxz = globalMultipolek[t101] * oneThird;
2202       qkyz = globalMultipolek[t011] * oneThird;
2203     }
2204 
2205     private void setInducedI(double[] inducedDipolei) {
2206       uix = inducedDipolei[0];
2207       uiy = inducedDipolei[1];
2208       uiz = inducedDipolei[2];
2209     }
2210 
2211     private void setInducedK(double[] inducedDipolek) {
2212       ukx = inducedDipolek[0];
2213       uky = inducedDipolek[1];
2214       ukz = inducedDipolek[2];
2215     }
2216 
2217     private void setInducedpI(double[] inducedDipolepi) {
2218       pix = inducedDipolepi[0];
2219       piy = inducedDipolepi[1];
2220       piz = inducedDipolepi[2];
2221     }
2222 
2223     private void setInducedpK(double[] inducedDipolepk) {
2224       pkx = inducedDipolepk[0];
2225       pky = inducedDipolepk[1];
2226       pkz = inducedDipolepk[2];
2227     }
2228 
2229   }
2230 
2231   /**
2232    * The Real Space Gradient Loop class contains methods and thread local variables to parallelize
2233    * the evaluation of the real space permanent and polarization energies and gradients.
2234    */
2235   private class FixedChargeEnergyLoop extends IntegerForLoop {
2236 
2237     private final double[] dx_local;
2238     private final double[][] rot_local;
2239     private double ci;
2240     private double ck;
2241     private double xr, yr, zr;
2242     private double bn0, bn1, bn2;
2243     private double rr1, rr3, rr5;
2244     private double scale;
2245     private double l2;
2246     private boolean soft;
2247     private double selfScale;
2248     private double permanentEnergy;
2249     private double inducedEnergy;
2250     private double dUdL, d2UdL2;
2251     private int i, k, iSymm, count;
2252     private double[] gxk_local, gyk_local, gzk_local;
2253     private double[] lxk_local, lyk_local, lzk_local;
2254     private double[] masking_local;
2255     private int threadID;
2256 
2257     FixedChargeEnergyLoop() {
2258       super();
2259       dx_local = new double[3];
2260       rot_local = new double[3][3];
2261     }
2262 
2263     @Override
2264     public void finish() {
2265       sharedInteractions.addAndGet(count);
2266       if (lambdaTerm) {
2267         shareddEdLambda.addAndGet(dUdL * electric);
2268         sharedd2EdLambda2.addAndGet(d2UdL2 * electric);
2269       }
2270       realSpaceEnergyTime[getThreadIndex()] += System.nanoTime();
2271     }
2272 
2273     public int getCount() {
2274       return count;
2275     }
2276 
2277     @Override
2278     public void run(int lb, int ub) {
2279       List<SymOp> symOps = crystal.spaceGroup.symOps;
2280       int nSymm = symOps.size();
2281       int nAtoms = atoms.length;
2282       for (iSymm = 0; iSymm < nSymm; iSymm++) {
2283         SymOp symOp = symOps.get(iSymm);
2284         if (gradient) {
2285           fill(gxk_local, 0.0);
2286           fill(gyk_local, 0.0);
2287           fill(gzk_local, 0.0);
2288         }
2289         if (lambdaTerm) {
2290           fill(lxk_local, 0.0);
2291           fill(lyk_local, 0.0);
2292           fill(lzk_local, 0.0);
2293         }
2294         realSpaceChunk(lb, ub);
2295         if (gradient) {
2296           // Rotate symmetry mate gradients
2297           if (iSymm != 0) {
2298             crystal.applyTransSymRot(nAtoms, gxk_local, gyk_local, gzk_local, gxk_local, gyk_local, gzk_local, symOp, rot_local);
2299           }
2300           // Sum symmetry mate gradients into asymmetric unit gradients
2301           for (int j = 0; j < nAtoms; j++) {
2302             grad.add(threadID, j, gxk_local[j], gyk_local[j], gzk_local[j]);
2303           }
2304         }
2305         if (lambdaTerm) {
2306           // Rotate symmetry mate gradients
2307           if (iSymm != 0) {
2308             crystal.applyTransSymRot(
2309                 nAtoms, lxk_local, lyk_local, lzk_local, lxk_local, lyk_local, lzk_local, symOp,
2310                 rot_local);
2311           }
2312           // Sum symmetry mate gradients into asymmetric unit gradients
2313           for (int j = 0; j < nAtoms; j++) {
2314             lambdaGrad.add(threadID, j, lxk_local[j], lyk_local[j], lzk_local[j]);
2315           }
2316         }
2317       }
2318     }
2319 
2320     @Override
2321     public IntegerSchedule schedule() {
2322       return realSpaceSchedule;
2323     }
2324 
2325     @Override
2326     public void start() {
2327       init();
2328       threadID = getThreadIndex();
2329       realSpaceEnergyTime[threadID] -= System.nanoTime();
2330       permanentEnergy = 0.0;
2331       inducedEnergy = 0.0;
2332       count = 0;
2333       if (lambdaTerm) {
2334         dUdL = 0.0;
2335         d2UdL2 = 0.0;
2336       }
2337     }
2338 
2339     private void init() {
2340       int nAtoms = atoms.length;
2341       if (masking_local == null || masking_local.length < nAtoms) {
2342         gxk_local = new double[nAtoms];
2343         gyk_local = new double[nAtoms];
2344         gzk_local = new double[nAtoms];
2345         lxk_local = new double[nAtoms];
2346         lyk_local = new double[nAtoms];
2347         lzk_local = new double[nAtoms];
2348         masking_local = new double[nAtoms];
2349         fill(masking_local, 1.0);
2350       }
2351     }
2352 
2353     /**
2354      * Evaluate the real space permanent energy and polarization energy for a chunk of atoms.
2355      *
2356      * @param lb The lower bound of the chunk.
2357      * @param ub The upper bound of the chunk.
2358      */
2359     private void realSpaceChunk(final int lb, final int ub) {
2360       final double[] x = coordinates[0][0];
2361       final double[] y = coordinates[0][1];
2362       final double[] z = coordinates[0][2];
2363       final double[][] mpole = globalMultipole[0];
2364       final int[][] lists = realSpaceLists[iSymm];
2365       final double[] neighborX = coordinates[iSymm][0];
2366       final double[] neighborY = coordinates[iSymm][1];
2367       final double[] neighborZ = coordinates[iSymm][2];
2368       final double[][] neighborMultipole = globalMultipole[iSymm];
2369       for (i = lb; i <= ub; i++) {
2370         if (!use[i]) {
2371           continue;
2372         }
2373         final int moleculei = molecule[i];
2374         if (iSymm == 0) {
2375           applyMask(i, null, masking_local);
2376         }
2377         final double xi = x[i];
2378         final double yi = y[i];
2379         final double zi = z[i];
2380         final double[] globalMultipolei = mpole[i];
2381         setMultipoleI(globalMultipolei);
2382         final boolean softi = isSoft[i];
2383         final int[] list = lists[i];
2384         final int npair = realSpaceCounts[iSymm][i];
2385         for (int j = 0; j < npair; j++) {
2386           k = list[j];
2387           if (!use[k]) {
2388             continue;
2389           }
2390           boolean sameMolecule = (moleculei == molecule[k]);
2391           if (lambdaMode == LambdaMode.VAPOR) {
2392             if ((intermolecularSoftcore && !sameMolecule)
2393                 || (intramolecularSoftcore && sameMolecule)) {
2394               continue;
2395             }
2396           }
2397           selfScale = 1.0;
2398           if (i == k) {
2399             selfScale = 0.5;
2400           }
2401           double beta = 0.0;
2402           l2 = 1.0;
2403           soft = (softi || isSoft[k]);
2404           if (soft && doPermanentRealSpace) {
2405             beta = lAlpha;
2406             l2 = permanentScale;
2407           } else if (nnTerm) {
2408             l2 = permanentScale;
2409           }
2410           final double xk = neighborX[k];
2411           final double yk = neighborY[k];
2412           final double zk = neighborZ[k];
2413           dx_local[0] = xk - xi;
2414           dx_local[1] = yk - yi;
2415           dx_local[2] = zk - zi;
2416           double r2 = crystal.image(dx_local);
2417           xr = dx_local[0];
2418           yr = dx_local[1];
2419           zr = dx_local[2];
2420           final double[] globalMultipolek = neighborMultipole[k];
2421           setMultipoleK(globalMultipolek);
2422           scale = masking_local[k];
2423           double r = sqrt(r2 + beta);
2424           double ralpha = aewald * r;
2425           double exp2a = exp(-ralpha * ralpha);
2426           rr1 = 1.0 / r;
2427           double rr2 = rr1 * rr1;
2428           bn0 = erfc(ralpha) * rr1;
2429           bn1 = (bn0 + an0 * exp2a) * rr2;
2430           bn2 = (3.0 * bn1 + an1 * exp2a) * rr2;
2431           rr3 = rr1 * rr2;
2432           rr5 = 3.0 * rr3 * rr2;
2433           if (doPermanentRealSpace) {
2434             double ei = permanentPair(gradient, lambdaTerm);
2435             if (isNaN(ei) || isInfinite(ei)) {
2436               String message = format(" %s\n %s\n %s\n The permanent multipole energy between "
2437                       + "atoms %d and %d (%d) is %16.8f at %16.8f A.",
2438                   crystal.getUnitCell().toString(), atoms[i].toString(), atoms[k].toString(),
2439                   i, k, iSymm, ei, r);
2440               throw new EnergyException(message);
2441             }
2442             if (ei != 0.0) {
2443               permanentEnergy += ei;
2444               count++;
2445             }
2446             if (esvTerm) {
2447               if (extendedSystem.isTitrating(i)) {
2448                 double titrdUdL = 0.0;
2449                 double tautdUdL = 0.0;
2450                 final double[][] titrMpole = titrationMultipole[0];
2451                 final double[] titrMultipolei = titrMpole[i];
2452                 setMultipoleI(titrMultipolei);
2453                 titrdUdL = electric * permanentPair(false, false);
2454                 if (extendedSystem.isTautomerizing(i)) {
2455                   final double[][] tautMpole = tautomerMultipole[0];
2456                   final double[] tautMultipolei = tautMpole[i];
2457                   setMultipoleI(tautMultipolei);
2458                   tautdUdL = electric * permanentPair(false, false);
2459                 }
2460                 extendedSystem.addPermElecDeriv(i, titrdUdL, tautdUdL);
2461                 // Reset Multipoles between titration and tautomer ESVs
2462                 setMultipoleI(globalMultipolei);
2463               }
2464               if (extendedSystem.isTitrating(k)) {
2465                 double titrdUdL = 0.0;
2466                 double tautdUdL = 0.0;
2467                 final double[][] titrNeighborMpole = titrationMultipole[iSymm];
2468                 final double[] titrMultipolek = titrNeighborMpole[k];
2469                 setMultipoleK(titrMultipolek);
2470                 titrdUdL = electric * permanentPair(false, false);
2471                 if (extendedSystem.isTautomerizing(k)) {
2472                   final double[][] tautNeighborMpole = tautomerMultipole[iSymm];
2473                   final double[] tautMultipolek = tautNeighborMpole[k];
2474                   setMultipoleK(tautMultipolek);
2475                   tautdUdL = electric * permanentPair(false, false);
2476                 }
2477                 extendedSystem.addPermElecDeriv(k, titrdUdL, tautdUdL);
2478                 // Reset Multipoles between titration and tautomer ESVs
2479                 setMultipoleK(globalMultipolek);
2480               }
2481             }
2482           }
2483         }
2484         if (iSymm == 0) {
2485           removeMask(i, null, masking_local);
2486         }
2487       }
2488     }
2489 
2490     /**
2491      * Evaluate the real space permanent energy for a pair of multipole sites.
2492      *
2493      * @return the permanent multipole energy.
2494      */
2495     private double permanentPair(boolean gradientLocal, boolean lambdaTermLocal) {
2496 
2497       // Calculate the gl functions for permanent multipoles.
2498       final double gl0 = ci * ck;
2499 
2500       // Compute the energy contributions for this interaction.
2501       final double scale1 = 1.0 - scale;
2502       final double ereal = gl0 * bn0;
2503       final double efix = scale1 * (gl0 * rr1);
2504       final double e = selfScale * l2 * (ereal - efix);
2505       if (gradientLocal) {
2506         final double gf1 = bn1 * gl0;
2507         // Get the permanent force with screening.
2508         double ftm2x = gf1 * xr;
2509         double ftm2y = gf1 * yr;
2510         double ftm2z = gf1 * zr;
2511 
2512         // Handle the case where scaling is used.
2513         if (scale1 != 0.0) {
2514           final double gfr1 = rr3 * gl0;
2515           // Get the permanent force without screening.
2516           final double ftm2rx = gfr1 * xr;
2517           final double ftm2ry = gfr1 * yr;
2518           final double ftm2rz = gfr1 * zr;
2519           ftm2x -= scale1 * ftm2rx;
2520           ftm2y -= scale1 * ftm2ry;
2521           ftm2z -= scale1 * ftm2rz;
2522         }
2523         double prefactor = electric * selfScale * l2;
2524         grad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
2525         gxk_local[k] -= prefactor * ftm2x;
2526         gyk_local[k] -= prefactor * ftm2y;
2527         gzk_local[k] -= prefactor * ftm2z;
2528 
2529         // This is dU/dL/dX for the first term of dU/dL: d[dlPow * ereal]/dx
2530         if (lambdaTerm && soft) {
2531           prefactor = electric * selfScale * dEdLSign * dlPowPerm;
2532           lambdaGrad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
2533           lxk_local[k] -= prefactor * ftm2x;
2534           lyk_local[k] -= prefactor * ftm2y;
2535           lzk_local[k] -= prefactor * ftm2z;
2536         }
2537       }
2538 
2539       if (lambdaTermLocal && soft) {
2540         double dRealdL = gl0 * bn1;
2541         double d2RealdL2 = gl0 * bn2;
2542 
2543         dUdL += selfScale * (dEdLSign * dlPowPerm * ereal + l2 * dlAlpha * dRealdL);
2544         d2UdL2 += selfScale * (dEdLSign * (d2lPowPerm * ereal
2545             + dlPowPerm * dlAlpha * dRealdL
2546             + dlPowPerm * dlAlpha * dRealdL)
2547             + l2 * d2lAlpha * dRealdL
2548             + l2 * dlAlpha * dlAlpha * d2RealdL2);
2549 
2550         double dFixdL = gl0 * rr3;
2551         double d2FixdL2 = gl0 * rr5;
2552         dFixdL *= scale1;
2553         d2FixdL2 *= scale1;
2554         dUdL -= selfScale * (dEdLSign * dlPowPerm * efix + l2 * dlAlpha * dFixdL);
2555         d2UdL2 -= selfScale * (dEdLSign * (d2lPowPerm * efix
2556             + dlPowPerm * dlAlpha * dFixdL
2557             + dlPowPerm * dlAlpha * dFixdL)
2558             + l2 * d2lAlpha * dFixdL
2559             + l2 * dlAlpha * dlAlpha * d2FixdL2);
2560 
2561         // Collect terms for dU/dL/dX for the second term of dU/dL: d[fL2*dfL1dL*dRealdL]/dX
2562         final double gf1 = bn2 * gl0;
2563         // Get the permanent force with screening.
2564         double ftm2x = gf1 * xr;
2565         double ftm2y = gf1 * yr;
2566         double ftm2z = gf1 * zr;
2567 
2568         // Handle the case where scaling is used.
2569         if (scale1 != 0.0) {
2570           final double gfr1 = rr5 * gl0;
2571           // Get the permanent force without screening.
2572           final double ftm2rx = gfr1 * xr;
2573           final double ftm2ry = gfr1 * yr;
2574           final double ftm2rz = gfr1 * zr;
2575           ftm2x -= scale1 * ftm2rx;
2576           ftm2y -= scale1 * ftm2ry;
2577           ftm2z -= scale1 * ftm2rz;
2578         }
2579 
2580         // Add in dU/dL/dX for the second term of dU/dL: d[lPow*dlAlpha*dRealdL]/dX
2581         double prefactor = electric * selfScale * l2 * dlAlpha;
2582         lambdaGrad.add(threadID, i, prefactor * ftm2x, prefactor * ftm2y, prefactor * ftm2z);
2583         lxk_local[k] -= prefactor * ftm2x;
2584         lyk_local[k] -= prefactor * ftm2y;
2585         lzk_local[k] -= prefactor * ftm2z;
2586       }
2587       return e;
2588     }
2589 
2590     private void setMultipoleI(double[] globalMultipolei) {
2591       ci = globalMultipolei[t000];
2592     }
2593 
2594     private void setMultipoleK(double[] globalMultipolek) {
2595       ck = globalMultipolek[t000];
2596     }
2597 
2598   }
2599 
2600 }