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.numerics.multipole;
39  
40  import java.util.HashMap;
41  import java.util.logging.Level;
42  import java.util.logging.Logger;
43  
44  import static ffx.numerics.math.ScalarMath.doubleFactorial;
45  import static ffx.numerics.multipole.MultipoleUtilities.lmn;
46  import static ffx.numerics.multipole.MultipoleUtilities.loadTensor;
47  import static ffx.numerics.multipole.MultipoleUtilities.storePotential;
48  import static ffx.numerics.multipole.MultipoleUtilities.storePotentialNeg;
49  import static ffx.numerics.multipole.MultipoleUtilities.term;
50  import static java.lang.Math.fma;
51  import static java.lang.String.format;
52  import static org.apache.commons.math3.util.FastMath.pow;
53  
54  /**
55   * The abstract MultipoleTensor is extended by classes that compute derivatives of 1/|<b>r</b>| via
56   * recursion to arbitrary order using Cartesian multipoles in either a global frame or a
57   * quasi-internal frame. <br> This class serves as the abstract parent to both and defines all shared
58   * logic. Non-abstract methods are declared final to disallow unnecessary overrides.
59   *
60   * @author Michael J. Schnieders
61   * @since 1.0
62   */
63  public abstract class MultipoleTensor {
64  
65    /**
66     * Logger for the MultipoleTensor class.
67     */
68    private static final Logger logger = Logger.getLogger(MultipoleTensor.class.getName());
69  
70    /**
71     * Order of the tensor recursion (5th is needed for AMOEBA forces).
72     */
73    protected final int order;
74  
75    /**
76     * Order plus 1.
77     */
78    protected final int o1;
79  
80    /**
81     * Order plus one.
82     */
83    protected final int il;
84  
85    /**
86     * im = (Order plus one)^2.
87     */
88    protected final int im;
89  
90    /**
91     * in = (Order plus one)^3.
92     */
93    protected final int in;
94  
95    /**
96     * Size = (order + 1) * (order + 2) * (order + 3) / 6;
97     */
98    protected final int size;
99  
100   /**
101    * The OPERATOR in use.
102    */
103   protected Operator operator;
104 
105   /**
106    * These are the "source" terms for the recursion for the Coulomb operator (1/R).
107    */
108   protected final double[] coulombSource;
109 
110   /**
111    * Store the work array to avoid memory consumption. Note that rather than use an array for
112    * intermediate values, a 4D matrix was tried. It was approximately 50% slower than the linear work
113    * array.
114    */
115   protected final double[] work;
116 
117   /**
118    * Store the auxiliary tensor memory to avoid memory consumption.
119    */
120   protected final double[] T000;
121 
122   /**
123    * The coordinate system in use (global or QI).
124    */
125   protected final CoordinateSystem coordinates;
126 
127   /**
128    * Separation distance.
129    */
130   protected double R;
131 
132   /**
133    * Separation distance squared.
134    */
135   protected double r2;
136 
137   /**
138    * Xk - Xi.
139    */
140   protected double x;
141 
142   /**
143    * Yk - Yi.
144    */
145   protected double y;
146 
147   /**
148    * Zk - Zi.
149    */
150   protected double z;
151 
152   private double dEdZ = 0.0;
153   private double d2EdZ2 = 0.0;
154 
155   // Components of the potential, field and field gradient.
156   double E000; // Potential
157   // l + m + n = 1 (3)   4
158   double E100; // d/dX
159   double E010; // d/dY
160   double E001; // d/dz
161   // l + m + n = 2 (6)  10
162   double E200; // d^2/dXdX
163   double E020; // d^2/dYdY
164   double E002; // d^2/dZdZ
165   double E110; // d^2/dXdY
166   double E101; // d^2/dXdZ
167   double E011; // d^2/dYdZ
168   // l + m + n = 3 (10) 20
169   double E300; // d^3/dXdXdX
170   double E030; // d^3/dYdYdY
171   double E003; // d^3/dZdZdZ
172   double E210; // d^3/dXdXdY
173   double E201; // d^3/dXdXdZ
174   double E120; // d^3/dXdYdY
175   double E021; // d^3/dYdYdZ
176   double E102; // d^3/dXdZdZ
177   double E012; // d^3/dYdZdZ
178   double E111; // d^3/dXdYdZ
179 
180   // Cartesian tensor elements (for 1/R, erfc(Beta*R)/R or Thole damping.
181   double R000;
182   // l + m + n = 1 (3)   4
183   double R100;
184   double R010;
185   double R001;
186   // l + m + n = 2 (6)  10
187   double R200;
188   double R020;
189   double R002;
190   double R110;
191   double R101;
192   double R011;
193   // l + m + n = 3 (10) 20
194   double R300;
195   double R030;
196   double R003;
197   double R210;
198   double R201;
199   double R120;
200   double R021;
201   double R102;
202   double R012;
203   double R111;
204   // l + m + n = 4 (15) 35
205   double R400;
206   double R040;
207   double R004;
208   double R310;
209   double R301;
210   double R130;
211   double R031;
212   double R103;
213   double R013;
214   double R220;
215   double R202;
216   double R022;
217   double R211;
218   double R121;
219   double R112;
220   // l + m + n = 5 (21) 56
221   double R500;
222   double R050;
223   double R005;
224   double R410;
225   double R401;
226   double R140;
227   double R041;
228   double R104;
229   double R014;
230   double R320;
231   double R302;
232   double R230;
233   double R032;
234   double R203;
235   double R023;
236   double R311;
237   double R131;
238   double R113;
239   double R221;
240   double R212;
241   double R122;
242   // l + m + n = 6 (28) 84
243   double R006;
244   double R402;
245   double R042;
246   double R204;
247   double R024;
248   double R222;
249   double R600;
250   double R060;
251   double R510;
252   double R501;
253   double R150;
254   double R051;
255   double R105;
256   double R015;
257   double R420;
258   double R240;
259   double R411;
260   double R141;
261   double R114;
262   double R330;
263   double R303;
264   double R033;
265   double R321;
266   double R231;
267   double R213;
268   double R312;
269   double R132;
270   double R123;
271 
272   /**
273    * Constructor for MultipoleTensor.
274    *
275    * @param order       The order of the tensor.
276    * @param coordinates a {@link CoordinateSystem} object.
277    */
278   public MultipoleTensor(CoordinateSystem coordinates, int order) {
279     assert (order > 0);
280     o1 = order + 1;
281     il = o1;
282     im = il * o1;
283     in = im * o1;
284     size = (order + 1) * (order + 2) * (order + 3) / 6;
285     work = new double[in * o1];
286 
287     this.order = order;
288     this.coordinates = coordinates;
289     this.operator = Operator.COULOMB;
290 
291     // Auxiliary terms for Coulomb and Thole Screening.
292     coulombSource = new double[o1];
293     for (short n = 0; n <= order; n++) {
294       /*
295        Math.pow(-1.0, j) returns positive for all j, with -1.0 as the //
296        argument rather than -1. This is a bug?
297        Challacombe Eq. 21, first two factors.
298       */
299       coulombSource[n] = pow(-1, n) * doubleFactorial(2 * n - 1);
300     }
301 
302     T000 = new double[order + 1];
303     // l + m + n = 0 (1)
304     t000 = MultipoleUtilities.ti(0, 0, 0, order);
305     // l + m + n = 1 (3)   4
306     t100 = MultipoleUtilities.ti(1, 0, 0, order);
307     t010 = MultipoleUtilities.ti(0, 1, 0, order);
308     t001 = MultipoleUtilities.ti(0, 0, 1, order);
309     // l + m + n = 2 (6)  10
310     t200 = MultipoleUtilities.ti(2, 0, 0, order);
311     t020 = MultipoleUtilities.ti(0, 2, 0, order);
312     t002 = MultipoleUtilities.ti(0, 0, 2, order);
313     t110 = MultipoleUtilities.ti(1, 1, 0, order);
314     t101 = MultipoleUtilities.ti(1, 0, 1, order);
315     t011 = MultipoleUtilities.ti(0, 1, 1, order);
316     // l + m + n = 3 (10) 20
317     t300 = MultipoleUtilities.ti(3, 0, 0, order);
318     t030 = MultipoleUtilities.ti(0, 3, 0, order);
319     t003 = MultipoleUtilities.ti(0, 0, 3, order);
320     t210 = MultipoleUtilities.ti(2, 1, 0, order);
321     t201 = MultipoleUtilities.ti(2, 0, 1, order);
322     t120 = MultipoleUtilities.ti(1, 2, 0, order);
323     t021 = MultipoleUtilities.ti(0, 2, 1, order);
324     t102 = MultipoleUtilities.ti(1, 0, 2, order);
325     t012 = MultipoleUtilities.ti(0, 1, 2, order);
326     t111 = MultipoleUtilities.ti(1, 1, 1, order);
327     // l + m + n = 4 (15) 35
328     t400 = MultipoleUtilities.ti(4, 0, 0, order);
329     t040 = MultipoleUtilities.ti(0, 4, 0, order);
330     t004 = MultipoleUtilities.ti(0, 0, 4, order);
331     t310 = MultipoleUtilities.ti(3, 1, 0, order);
332     t301 = MultipoleUtilities.ti(3, 0, 1, order);
333     t130 = MultipoleUtilities.ti(1, 3, 0, order);
334     t031 = MultipoleUtilities.ti(0, 3, 1, order);
335     t103 = MultipoleUtilities.ti(1, 0, 3, order);
336     t013 = MultipoleUtilities.ti(0, 1, 3, order);
337     t220 = MultipoleUtilities.ti(2, 2, 0, order);
338     t202 = MultipoleUtilities.ti(2, 0, 2, order);
339     t022 = MultipoleUtilities.ti(0, 2, 2, order);
340     t211 = MultipoleUtilities.ti(2, 1, 1, order);
341     t121 = MultipoleUtilities.ti(1, 2, 1, order);
342     t112 = MultipoleUtilities.ti(1, 1, 2, order);
343     // l + m + n = 5 (21) 56
344     t500 = MultipoleUtilities.ti(5, 0, 0, order);
345     t050 = MultipoleUtilities.ti(0, 5, 0, order);
346     t005 = MultipoleUtilities.ti(0, 0, 5, order);
347     t410 = MultipoleUtilities.ti(4, 1, 0, order);
348     t401 = MultipoleUtilities.ti(4, 0, 1, order);
349     t140 = MultipoleUtilities.ti(1, 4, 0, order);
350     t041 = MultipoleUtilities.ti(0, 4, 1, order);
351     t104 = MultipoleUtilities.ti(1, 0, 4, order);
352     t014 = MultipoleUtilities.ti(0, 1, 4, order);
353     t320 = MultipoleUtilities.ti(3, 2, 0, order);
354     t302 = MultipoleUtilities.ti(3, 0, 2, order);
355     t230 = MultipoleUtilities.ti(2, 3, 0, order);
356     t032 = MultipoleUtilities.ti(0, 3, 2, order);
357     t203 = MultipoleUtilities.ti(2, 0, 3, order);
358     t023 = MultipoleUtilities.ti(0, 2, 3, order);
359     t311 = MultipoleUtilities.ti(3, 1, 1, order);
360     t131 = MultipoleUtilities.ti(1, 3, 1, order);
361     t113 = MultipoleUtilities.ti(1, 1, 3, order);
362     t221 = MultipoleUtilities.ti(2, 2, 1, order);
363     t212 = MultipoleUtilities.ti(2, 1, 2, order);
364     t122 = MultipoleUtilities.ti(1, 2, 2, order);
365     // l + m + n = 6 (28) 84
366     t600 = MultipoleUtilities.ti(6, 0, 0, order);
367     t060 = MultipoleUtilities.ti(0, 6, 0, order);
368     t006 = MultipoleUtilities.ti(0, 0, 6, order);
369     t510 = MultipoleUtilities.ti(5, 1, 0, order);
370     t501 = MultipoleUtilities.ti(5, 0, 1, order);
371     t150 = MultipoleUtilities.ti(1, 5, 0, order);
372     t051 = MultipoleUtilities.ti(0, 5, 1, order);
373     t105 = MultipoleUtilities.ti(1, 0, 5, order);
374     t015 = MultipoleUtilities.ti(0, 1, 5, order);
375     t420 = MultipoleUtilities.ti(4, 2, 0, order);
376     t402 = MultipoleUtilities.ti(4, 0, 2, order);
377     t240 = MultipoleUtilities.ti(2, 4, 0, order);
378     t042 = MultipoleUtilities.ti(0, 4, 2, order);
379     t204 = MultipoleUtilities.ti(2, 0, 4, order);
380     t024 = MultipoleUtilities.ti(0, 2, 4, order);
381     t411 = MultipoleUtilities.ti(4, 1, 1, order);
382     t141 = MultipoleUtilities.ti(1, 4, 1, order);
383     t114 = MultipoleUtilities.ti(1, 1, 4, order);
384     t330 = MultipoleUtilities.ti(3, 3, 0, order);
385     t303 = MultipoleUtilities.ti(3, 0, 3, order);
386     t033 = MultipoleUtilities.ti(0, 3, 3, order);
387     t321 = MultipoleUtilities.ti(3, 2, 1, order);
388     t231 = MultipoleUtilities.ti(2, 3, 1, order);
389     t213 = MultipoleUtilities.ti(2, 1, 3, order);
390     t312 = MultipoleUtilities.ti(3, 1, 2, order);
391     t132 = MultipoleUtilities.ti(1, 3, 2, order);
392     t123 = MultipoleUtilities.ti(1, 2, 3, order);
393     t222 = MultipoleUtilities.ti(2, 2, 2, order);
394   }
395 
396   /**
397    * getd2EdZ2.
398    *
399    * @return a double.
400    */
401   public double getd2EdZ2() {
402     return d2EdZ2;
403   }
404 
405   /**
406    * getdEdZ.
407    *
408    * @return a double.
409    */
410   public double getdEdZ() {
411     return dEdZ;
412   }
413 
414   /**
415    * log.
416    *
417    * @param tensor an array of {@link double} objects.
418    */
419   public void log(double[] tensor) {
420     log(this.operator, this.order, tensor);
421   }
422 
423   /**
424    * Permanent multipole energy.
425    *
426    * @param mI PolarizableMultipole at site I.
427    * @param mK PolarizableMultipole at site K.
428    * @return a double.
429    */
430   public double multipoleEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
431     multipoleIPotentialAtK(mI, 2);
432     return multipoleEnergy(mK);
433   }
434 
435   /**
436    * Permanent multipole energy and gradient.
437    *
438    * @param mI PolarizableMultipole at site I.
439    * @param mK PolarizableMultipole at site K.
440    * @param Gi Coordinate gradient at site I.
441    * @param Gk Coordinate gradient at site K.
442    * @param Ti Torque at site I.
443    * @param Tk Torque at site K.
444    * @return the permanent multipole energy.
445    */
446   public double multipoleEnergyAndGradient(PolarizableMultipole mI, PolarizableMultipole mK,
447                                            double[] Gi, double[] Gk, double[] Ti, double[] Tk) {
448     multipoleIPotentialAtK(mI, 3);
449     double energy = multipoleEnergy(mK);
450     multipoleGradient(mK, Gk);
451     Gi[0] = -Gk[0];
452     Gi[1] = -Gk[1];
453     Gi[2] = -Gk[2];
454 
455     // Torques
456     multipoleTorque(mK, Tk);
457     multipoleKPotentialAtI(mK, 2);
458     multipoleTorque(mI, Ti);
459 
460     // dEdZ = -Gi[2];
461     // if (order >= 6) {
462     //  multipoleIdZ2(mI);
463     //  d2EdZ2 = dotMultipole(mK);
464     // }
465 
466     return energy;
467   }
468 
469   /**
470    * Polarization Energy.
471    *
472    * @param mI          PolarizableMultipole at site I.
473    * @param mK          PolarizableMultipole at site K.
474    * @param scaleEnergy a double.
475    * @return a double.
476    */
477   public double polarizationEnergy(PolarizableMultipole mI, PolarizableMultipole mK,
478                                    double scaleEnergy) {
479     // Incorporate core charges into multipole potential
480     if (mI.Z != 0 && mK.Z != 0 && operator == Operator.THOLE_DIRECT_FIELD) {
481       mI.q += mI.Z;
482       mK.q += mK.Z;
483     }
484 
485     // Find the permanent multipole potential and derivatives at k.
486     multipoleIPotentialAtK(mI, 1);
487     // Energy of induced dipole k in the field of permanent multipole i.
488     double eK = polarizationEnergy(mK);
489     // Find the permanent multipole potential and derivatives at site i.
490     multipoleKPotentialAtI(mK, 1);
491     // Energy of induced dipole i in the field of permanent multipole k.
492     double eI = polarizationEnergy(mI);
493 
494     if (mI.Z != 0 && mK.Z != 0 && operator == Operator.THOLE_DIRECT_FIELD) {
495       mI.q -= mI.Z;
496       mK.q -= mK.Z;
497     }
498 
499     return scaleEnergy * (eI + eK);
500   }
501 
502   /**
503    * Polarization Energy and Gradient.
504    *
505    * @param mI            PolarizableMultipole at site I.
506    * @param mK            PolarizableMultipole at site K.
507    * @param inductionMask a double.
508    * @param energyMask    a double.
509    * @param mutualMask    a double.
510    * @param Gi            an array of {@link double} objects.
511    * @param Ti            an array of {@link double} objects.
512    * @param Tk            an array of {@link double} objects.
513    * @return a double.
514    */
515   public double polarizationEnergyAndGradient(PolarizableMultipole mI, PolarizableMultipole mK,
516                                               double inductionMask, double energyMask, double mutualMask,
517                                               double[] Gi, double[] Ti, double[] Tk) {
518 
519     if (mI.Z != 0 && mK.Z != 0) {
520       mI.q += mI.Z;
521       mK.q += mK.Z;
522     }
523 
524     // Add the induction and energy masks to create an "averaged" induced dipole (sx, sy, sz).
525     mI.applyMasks(inductionMask, energyMask);
526     mK.applyMasks(inductionMask, energyMask);
527 
528     // Find the permanent multipole potential and derivatives at site k.
529     multipoleIPotentialAtK(mI, 2);
530     // Energy of induced dipole k in the field of multipole i.
531     // The field E_x = -E100.
532     double eK = polarizationEnergy(mK);
533     // Derivative with respect to moving atom k.
534     Gi[0] = -(mK.sx * E200 + mK.sy * E110 + mK.sz * E101);
535     Gi[1] = -(mK.sx * E110 + mK.sy * E020 + mK.sz * E011);
536     Gi[2] = -(mK.sx * E101 + mK.sy * E011 + mK.sz * E002);
537 
538     // Find the permanent multipole potential and derivatives at site i.
539     multipoleKPotentialAtI(mK, 2);
540     // Energy of induced dipole i in the field of multipole k.
541     double eI = polarizationEnergy(mI);
542     // Derivative with respect to moving atom i.
543     Gi[0] += (mI.sx * E200 + mI.sy * E110 + mI.sz * E101);
544     Gi[1] += (mI.sx * E110 + mI.sy * E020 + mI.sz * E011);
545     Gi[2] += (mI.sx * E101 + mI.sy * E011 + mI.sz * E002);
546 
547     // Total polarization energy.
548     double energy = energyMask * (eI + eK);
549 
550     // Get the induced-induced portion of the force (Ud . dC/dX . Up).
551     // This contribution does not exist for direct polarization (mutualMask == 0.0).
552     if (mutualMask != 0.0) {
553       // Find the potential and its derivatives at k due to induced dipole i.
554       dipoleIPotentialAtK(mI.ux, mI.uy, mI.uz, 2);
555       Gi[0] -= 0.5 * mutualMask * (mK.px * E200 + mK.py * E110 + mK.pz * E101);
556       Gi[1] -= 0.5 * mutualMask * (mK.px * E110 + mK.py * E020 + mK.pz * E011);
557       Gi[2] -= 0.5 * mutualMask * (mK.px * E101 + mK.py * E011 + mK.pz * E002);
558 
559       // Find the potential and its derivatives at i due to induced dipole k.
560       dipoleKPotentialAtI(mK.ux, mK.uy, mK.uz, 2);
561       Gi[0] += 0.5 * mutualMask * (mI.px * E200 + mI.py * E110 + mI.pz * E101);
562       Gi[1] += 0.5 * mutualMask * (mI.px * E110 + mI.py * E020 + mI.pz * E011);
563       Gi[2] += 0.5 * mutualMask * (mI.px * E101 + mI.py * E011 + mI.pz * E002);
564     }
565 
566     // Find the potential and its derivatives at K due to the averaged induced dipole at site i.
567     dipoleIPotentialAtK(mI.sx, mI.sy, mI.sz, 2);
568     multipoleTorque(mK, Tk);
569 
570     // Find the potential and its derivatives at I due to the averaged induced dipole at site k.
571     dipoleKPotentialAtI(mK.sx, mK.sy, mK.sz, 2);
572     multipoleTorque(mI, Ti);
573 
574     if (mI.Z != 0 && mK.Z != 0) {
575       mI.q -= mI.Z;
576       mK.q -= mK.Z;
577     }
578 
579     return energy;
580   }
581 
582   /**
583    * Permanent Multipole + Polarization Energy.
584    *
585    * @param mI               PolarizableMultipole at site I.
586    * @param mK               PolarizableMultipole at site K.
587    * @param scaleEnergy      a double.
588    * @param energyComponents The permanent and induced energy components.
589    * @return a double.
590    */
591   public double totalEnergy(PolarizableMultipole mI, PolarizableMultipole mK, double scaleEnergy,
592                             double[] energyComponents) {
593     multipoleIPotentialAtK(mI, 2);
594     double permanentEnergy = multipoleEnergy(mK);
595 
596     // Energy of multipole k in the field of induced dipole i.
597     // The field E_x = -E100.
598     double eK = -(mK.ux * E100 + mK.uy * E010 + mK.uz * E001);
599 
600     // Find the permanent multipole potential and derivatives at site i.
601     multipoleKPotentialAtI(mK, 2);
602     // Energy of multipole i in the field of induced dipole k.
603     double eI = -(mI.ux * E100 + mI.uy * E010 + mI.uz * E001);
604 
605     double inducedEnergy = -0.5 * scaleEnergy * (eI + eK);
606 
607     // Story the energy components.
608     energyComponents[0] = permanentEnergy;
609     energyComponents[1] = inducedEnergy;
610 
611     return permanentEnergy + inducedEnergy;
612   }
613 
614   /**
615    * Set the separation vector.
616    *
617    * @param r The separation vector.
618    */
619   public final void setR(double[] r) {
620     setR(r[0], r[1], r[2]);
621   }
622 
623   /**
624    * Set the separation vector.
625    *
626    * @param dx Separation along the X-axis.
627    * @param dy Separation along the Y-axis.
628    * @param dz Separation along the Z-axis.
629    */
630   public abstract void setR(double dx, double dy, double dz);
631 
632   /**
633    * For the MultipoleTensorTest class and testing.
634    *
635    * @param r an array of {@link double} objects.
636    */
637   public final void generateTensor(double[] r) {
638     setR(r);
639     generateTensor();
640   }
641 
642   /**
643    * Generate the tensor using hard-coded methods or via recursion.
644    */
645   public void generateTensor() {
646     switch (order) {
647       case 1 -> order1();
648       case 2 -> order2();
649       case 3 -> order3();
650       case 4 -> order4();
651       case 5 -> order5();
652       case 6 -> order6();
653       default -> {
654         double[] r = {x, y, z};
655         recursion(r, work);
656       }
657     }
658   }
659 
660   /**
661    * Generate source terms for the Challacombe et al. recursion.
662    *
663    * @param T000 Location to store the source terms.
664    */
665   protected abstract void source(double[] T000);
666 
667   /**
668    * The index is based on the idea of filling tetrahedron.
669    * <p>
670    * 1/r has an index of 0.
671    * <br>
672    * derivatives of x are first; indices from 1..o for d/dx..(d/dx)^o
673    * <br>
674    * derivatives of x and y are second; base triangle of size (o+1)(o+2)/2
675    * <br>
676    * derivatives of x, y and z are last; total size (o+1)*(o+2)*(o+3)/6
677    * <br>
678    * <p>
679    * This function is useful to set up masking constants:
680    * <br>
681    * static int Tlmn = ti(l,m,n,order)
682    * <br>
683    * For example the (d/dy)^2 (1/R) storage location:
684    * <br>
685    * static int T020 = ti(0,2,0,order)
686    *
687    * @param dx int The number of d/dx operations.
688    * @param dy int The number of d/dy operations.
689    * @param dz int The number of d/dz operations.
690    * @return int in the range (0..binomial(order + 3, 3) - 1)
691    */
692   protected final int ti(int dx, int dy, int dz) {
693     return MultipoleUtilities.ti(dx, dy, dz, order);
694   }
695 
696   /**
697    * Contract multipole moments with their respective electrostatic potential derivatives.
698    *
699    * @param mI PolarizableMultipole at site I.
700    * @param T  array of electrostatic potential and partial derivatives
701    * @param l  apply (d/dx)^l to the potential
702    * @param m  apply (d/dy)^l to the potential
703    * @param n  apply (d/dz)^l to the potential
704    * @return the contracted interaction.
705    */
706   protected double contractMultipoleI(PolarizableMultipole mI, double[] T, int l, int m, int n) {
707     double total = 0.0;
708     total += mI.q * T[ti(l, m, n)];
709     total -= mI.dx * T[ti(l + 1, m, n)];
710     total -= mI.dy * T[ti(l, m + 1, n)];
711     total -= mI.dz * T[ti(l, m, n + 1)];
712     total += mI.qxx * T[ti(l + 2, m, n)];
713     total += mI.qyy * T[ti(l, m + 2, n)];
714     total += mI.qzz * T[ti(l, m, n + 2)];
715     total += mI.qxy * T[ti(l + 1, m + 1, n)];
716     total += mI.qxz * T[ti(l + 1, m, n + 1)];
717     total += mI.qyz * T[ti(l, m + 1, n + 1)];
718     return total;
719   }
720 
721   /**
722    * Collect the field at R due to Q multipole moments at the origin (site I).
723    *
724    * @param mI PolarizableMultipole at site I.
725    * @param T  Electrostatic potential and partial derivatives
726    * @param l  apply (d/dx)^l to the potential
727    * @param m  apply (d/dy)^l to the potential
728    * @param n  apply (d/dz)^l to the potential
729    */
730   protected final void potentialMultipoleI(PolarizableMultipole mI, double[] T, int l, int m,
731                                            int n) {
732     E000 = contractMultipoleI(mI, T, l, m, n);
733     E100 = contractMultipoleI(mI, T, l + 1, m, n);
734     E010 = contractMultipoleI(mI, T, l, m + 1, n);
735     E001 = contractMultipoleI(mI, T, l, m, n + 1);
736     E200 = contractMultipoleI(mI, T, l + 2, m, n);
737     E020 = contractMultipoleI(mI, T, l, m + 2, n);
738     E002 = contractMultipoleI(mI, T, l, m, n + 2);
739     E110 = contractMultipoleI(mI, T, l + 1, n + 1, m);
740     E101 = contractMultipoleI(mI, T, l + 1, m, n + 1);
741     E011 = contractMultipoleI(mI, T, l, m + 1, n + 1);
742   }
743 
744   /**
745    * <p>This function is a driver to collect elements of the Cartesian multipole tensor. Collecting
746    * all tensors scales slightly better than O(order^4).
747    *
748    * <p>For a multipole expansion truncated at quadrupole order, for example, up to order 5 is
749    * needed for energy gradients. The number of terms this requires is binomial(5 + 3, 3) or 8! / (5!
750    * * 3!), which is 56.
751    *
752    * <p>The packing of the tensor elements for order = 1<br>
753    * tensor[0] = 1/|r| <br> tensor[1] = -x/|r|^3 <br> tensor[2] = -y/|r|^3 <br> tensor[3] = -z/|r|^3
754    * <br>
755    *
756    * @param r      The separation vector.
757    * @param tensor The tensor elements.
758    * @return The tensor recursion code.
759    * @since 1.0
760    */
761   protected abstract String codeTensorRecursion(final double[] r, final double[] tensor);
762 
763   /**
764    * Contract multipole moments with their respective electrostatic potential derivatives.
765    *
766    * @param mI PolarizableMultipole at site I.
767    * @param T  array of electrostatic potential and partial derivatives
768    * @param l  apply (d/dx)^l to the potential
769    * @param m  apply (d/dy)^l to the potential
770    * @param n  apply (d/dz)^l to the potential
771    * @param sb the code will be appended to the StringBuilder.
772    * @return the contracted interaction.
773    */
774   private double codeContractMultipoleI(PolarizableMultipole mI, double[] T, int l, int m, int n,
775                                         StringBuilder sb) {
776     double total = 0.0;
777     String name = term(l, m, n);
778     sb.append(format("double %s = 0.0;\n", name));
779     StringBuilder sb1 = new StringBuilder();
780     double term = mI.q * T[ti(l, m, n)];
781     if (term != 0) {
782       total += term;
783       sb1.append(format("%s = fma(mI.q, R%s, %s);\n", name, lmn(l, m, n), name));
784     }
785     term = mI.dx * T[ti(l + 1, m, n)];
786     if (term != 0) {
787       total += term;
788       sb1.append(format("%s = fma(mI.dx, -R%s, %s);\n", name, lmn(l + 1, m, n), name));
789     }
790     term = mI.dy * T[ti(l, m + 1, n)];
791     if (term != 0) {
792       total += term;
793       sb1.append(format("%s = fma(mI.dy, -R%s, %s);\n", name, lmn(l, m + 1, n), name));
794     }
795     term = mI.dz * T[ti(l, m, n + 1)];
796     if (term != 0) {
797       total += term;
798       sb1.append(format("%s = fma(mI.dz, -R%s, %s);\n", name, lmn(l, m, n + 1), name));
799     }
800     StringBuilder traceSB = new StringBuilder();
801     double trace = 0.0;
802     term = mI.qxx * T[ti(l + 2, m, n)];
803     if (term != 0) {
804       trace += term;
805       traceSB.append(format("%s = fma(mI.qxx, R%s, %s);\n", name, lmn(l + 2, m, n), name));
806     }
807     term = mI.qyy * T[ti(l, m + 2, n)];
808     if (term != 0) {
809       trace += term;
810       traceSB.append(format("%s = fma(mI.qyy, R%s, %s);\n", name, lmn(l, m + 2, n), name));
811     }
812     term = mI.qzz * T[ti(l, m, n + 2)];
813     if (term != 0) {
814       trace += term;
815       traceSB.append(format("%s = fma(mI.qzz, R%s, %s);\n", name, lmn(l, m, n + 2), name));
816     }
817     total += trace;
818     if (total != 0) {
819       sb.append(sb1);
820       if (trace != 0) {
821         sb.append(traceSB);
822       }
823     }
824     term = mI.qxy * T[ti(l + 1, m + 1, n)];
825     if (term != 0) {
826       total += term;
827       sb.append(format("%s = fma(mI.qxy, R%s, %s);\n", name, lmn(l + 1, m + 1, n), name));
828     }
829     term = mI.qxz * T[ti(l + 1, m, n + 1)];
830     if (term != 0) {
831       total += term;
832       sb.append(format("%s = fma(mI.qxz, R%s, %s);\n", name, lmn(l + 1, m, n + 1), name));
833     }
834     term = mI.qyz * T[ti(l, m + 1, n + 1)];
835     if (term != 0) {
836       total += term;
837       sb.append(format("%s = fma(mI.qyz, R%s, %s);\n", name, lmn(l, m + 1, n + 1), name));
838     }
839     return total;
840   }
841 
842 
843   /**
844    * Contract multipole moments with their respective electrostatic potential derivatives
845    * using SIMD instructions.
846    *
847    * @param mI PolarizableMultipole at site I.
848    * @param T  array of electrostatic potential and partial derivatives
849    * @param l  apply (d/dx)^l to the potential
850    * @param m  apply (d/dy)^l to the potential
851    * @param n  apply (d/dz)^l to the potential
852    * @param sb the code will be appended to the StringBuilder.
853    * @return the contracted interaction.
854    */
855   private double codeContractMultipoleISIMD(PolarizableMultipole mI, double[] T, int l, int m, int n,
856                                             StringBuilder sb, HashMap<Integer, String> tensorMap) {
857     double total = 0.0;
858     String name = term(l, m, n);
859     StringBuilder sb1 = new StringBuilder();
860     double term = mI.q * T[ti(l, m, n)];
861     if (term != 0) {
862       total += term;
863       sb1.append(loadTensor(l, m, n, tensorMap));
864       sb1.append(format("\tDoubleVector %s = q.mul(t%s);\n", name, lmn(l, m, n)));
865     } else {
866       sb.append(format("\tDoubleVector %s = zero;\n", name));
867     }
868     term = mI.dx * T[ti(l + 1, m, n)];
869     if (term != 0) {
870       total += term;
871       sb1.append(loadTensor(l + 1, m, n, tensorMap));
872       sb1.append(format("\t%s = dx.fma(t%s.neg(), %s);\n", name, lmn(l + 1, m, n), name));
873     }
874     term = mI.dy * T[ti(l, m + 1, n)];
875     if (term != 0) {
876       total += term;
877       sb1.append(loadTensor(l, m + 1, n, tensorMap));
878       sb1.append(format("\t%s = dy.fma(t%s.neg(), %s);\n", name, lmn(l, m + 1, n), name));
879     }
880     term = mI.dz * T[ti(l, m, n + 1)];
881     if (term != 0) {
882       total += term;
883       sb1.append(loadTensor(l, m, n + 1, tensorMap));
884       sb1.append(format("\t%s = dz.fma(t%s.neg(), %s);\n", name, lmn(l, m, n + 1), name));
885     }
886     StringBuilder traceSB = new StringBuilder();
887     double trace = 0.0;
888     term = mI.qxx * T[ti(l + 2, m, n)];
889     if (term != 0) {
890       trace += term;
891       traceSB.append(loadTensor(l + 2, m, n, tensorMap));
892       traceSB.append(format("\t%s = qxx.fma(t%s, %s);\n", name, lmn(l + 2, m, n), name));
893     }
894     term = mI.qyy * T[ti(l, m + 2, n)];
895     if (term != 0) {
896       trace += term;
897       traceSB.append(loadTensor(l, m + 2, n, tensorMap));
898       traceSB.append(format("\t%s = qyy.fma(t%s, %s);\n", name, lmn(l, m + 2, n), name));
899     }
900     term = mI.qzz * T[ti(l, m, n + 2)];
901     if (term != 0) {
902       trace += term;
903       traceSB.append(loadTensor(l, m, n + 2, tensorMap));
904       traceSB.append(format("\t%s = qzz.fma(t%s, %s);\n", name, lmn(l, m, n + 2), name));
905     }
906     total += trace;
907     if (total != 0) {
908       sb.append(sb1);
909       if (trace != 0) {
910         sb.append(traceSB);
911       }
912     }
913     term = mI.qxy * T[ti(l + 1, m + 1, n)];
914     if (term != 0) {
915       total += term;
916       sb.append(loadTensor(l + 1, m + 1, n, tensorMap));
917       sb.append(format("\t%s = qxy.fma(t%s, %s);\n", name, lmn(l + 1, m + 1, n), name));
918     }
919     term = mI.qxz * T[ti(l + 1, m, n + 1)];
920     if (term != 0) {
921       total += term;
922       sb.append(loadTensor(l + 1, m, n + 1, tensorMap));
923       sb.append(format("\t%s = qxz.fma(t%s, %s);\n", name, lmn(l + 1, m, n + 1), name));
924     }
925     term = mI.qyz * T[ti(l, m + 1, n + 1)];
926     if (term != 0) {
927       total += term;
928       sb.append(loadTensor(l, m + 1, n + 1, tensorMap));
929       sb.append(format("\t%s = qyz.fma(t%s, %s);\n", name, lmn(l, m + 1, n + 1), name));
930     }
931     return total;
932   }
933 
934   /**
935    * Contract multipole moments with their respective electrostatic potential derivatives.
936    *
937    * @param mK PolarizableMultipole at site K.
938    * @param T  array of electrostatic potential and partial derivatives
939    * @param l  apply (d/dx)^l to the potential
940    * @param m  apply (d/dy)^l to the potential
941    * @param n  apply (d/dz)^l to the potential
942    * @param sb the code will be appended to the StringBuilder.
943    * @return the contracted interaction.
944    */
945   private double codeContractMultipoleK(PolarizableMultipole mK, double[] T, int l, int m, int n,
946                                         StringBuilder sb) {
947     double total = 0.0;
948     String name = term(l, m, n);
949     sb.append(format("double %s = 0.0;\n", name));
950     StringBuilder sb1 = new StringBuilder();
951     double term = mK.q * T[ti(l, m, n)];
952     if (term != 0) {
953       total += term;
954       sb1.append(format("%s = fma(mK.q, R%s, %s);\n", name, lmn(l, m, n), name));
955     }
956     term = mK.dx * T[ti(l + 1, m, n)];
957     if (term != 0) {
958       total += term;
959       sb1.append(format("%s = fma(mK.dx, R%s, %s);\n", name, lmn(l + 1, m, n), name));
960     }
961     term = mK.dy * T[ti(l, m + 1, n)];
962     if (term != 0) {
963       total += term;
964       sb1.append(format("%s = fma(mK.dy, R%s, %s);\n", name, lmn(l, m + 1, n), name));
965     }
966     term = mK.dz * T[ti(l, m, n + 1)];
967     if (term != 0) {
968       total += term;
969       sb1.append(format("%s = fma(mK.dz, R%s, %s);\n", name, lmn(l, m, n + 1), name));
970     }
971     StringBuilder traceSB = new StringBuilder();
972     double trace = 0.0;
973     term = mK.qxx * T[ti(l + 2, m, n)];
974     if (term != 0) {
975       trace += term;
976       traceSB.append(format("%s = fma(mK.qxx, R%s, %s);\n", name, lmn(l + 2, m, n), name));
977     }
978     term = mK.qyy * T[ti(l, m + 2, n)];
979     if (term != 0) {
980       trace += term;
981       traceSB.append(format("%s = fma(mK.qyy, R%s, %s);\n", name, lmn(l, m + 2, n), name));
982     }
983     term = mK.qzz * T[ti(l, m, n + 2)];
984     if (term != 0) {
985       trace += term;
986       traceSB.append(format("%s = fma(mK.qzz, R%s, %s);\n", name, lmn(l, m, n + 2), name));
987     }
988     total += trace;
989     if (total != 0) {
990       sb.append(sb1);
991       if (trace != 0) {
992         sb.append(traceSB);
993       }
994     }
995     term = mK.qxy * T[ti(l + 1, m + 1, n)];
996     if (term != 0) {
997       total += term;
998       sb.append(format("%s = fma(mK.qxy, R%s, %s);\n", name, lmn(l + 1, m + 1, n), name));
999     }
1000     term = mK.qxz * T[ti(l + 1, m, n + 1)];
1001     if (term != 0) {
1002       total += term;
1003       sb.append(format("%s = fma(mK.qxz, R%s, %s);\n", name, lmn(l + 1, m, n + 1), name));
1004     }
1005     term = mK.qyz * T[ti(l, m + 1, n + 1)];
1006     if (term != 0) {
1007       total += term;
1008       sb.append(format("%s = fma(mK.qyz, R%s, %s);\n", name, lmn(l, m + 1, n + 1), name));
1009     }
1010     return total;
1011   }
1012 
1013   /**
1014    * Contract multipole moments with their respective electrostatic potential derivatives
1015    * using SIMD instructions.
1016    *
1017    * @param mK PolarizableMultipole at site K.
1018    * @param T  array of electrostatic potential and partial derivatives
1019    * @param l  apply (d/dx)^l to the potential
1020    * @param m  apply (d/dy)^l to the potential
1021    * @param n  apply (d/dz)^l to the potential
1022    * @param sb the code will be appended to the StringBuilder.
1023    * @return the contracted interaction.
1024    */
1025   private double codeContractMultipoleKSIMD(PolarizableMultipole mK, double[] T, int l, int m, int n,
1026                                             StringBuilder sb, HashMap<Integer, String> tensorHash) {
1027     double total = 0.0;
1028     String name = term(l, m, n);
1029     StringBuilder sb1 = new StringBuilder();
1030     double term = mK.q * T[ti(l, m, n)];
1031     if (term != 0) {
1032       total += term;
1033       sb1.append(loadTensor(l, m, n, tensorHash));
1034       sb1.append(format("\tDoubleVector %s = q.mul(t%s);\n", name, lmn(l, m, n)));
1035     } else {
1036       sb.append(format("\tDoubleVector %s = zero;\n", name));
1037     }
1038     term = mK.dx * T[ti(l + 1, m, n)];
1039     if (term != 0) {
1040       total += term;
1041       sb1.append(loadTensor(l + 1, m, n, tensorHash));
1042       sb1.append(format("\t%s = dx.fma(t%s, %s);\n", name, lmn(l + 1, m, n), name));
1043     }
1044     term = mK.dy * T[ti(l, m + 1, n)];
1045     if (term != 0) {
1046       total += term;
1047       sb1.append(loadTensor(l, m + 1, n, tensorHash));
1048       sb1.append(format("\t%s = dy.fma(t%s, %s);\n", name, lmn(l, m + 1, n), name));
1049     }
1050     term = mK.dz * T[ti(l, m, n + 1)];
1051     if (term != 0) {
1052       total += term;
1053       sb1.append(loadTensor(l, m, n + 1, tensorHash));
1054       sb1.append(format("\t%s = dz.fma(t%s, %s);\n", name, lmn(l, m, n + 1), name));
1055     }
1056     StringBuilder traceSB = new StringBuilder();
1057     double trace = 0.0;
1058     term = mK.qxx * T[ti(l + 2, m, n)];
1059     if (term != 0) {
1060       trace += term;
1061       traceSB.append(loadTensor(l + 2, m, n, tensorHash));
1062       traceSB.append(format("\t%s = qxx.fma(t%s, %s);\n", name, lmn(l + 2, m, n), name));
1063     }
1064     term = mK.qyy * T[ti(l, m + 2, n)];
1065     if (term != 0) {
1066       trace += term;
1067       traceSB.append(loadTensor(l, m + 2, n, tensorHash));
1068       traceSB.append(format("\t%s = qyy.fma(t%s, %s);\n", name, lmn(l, m + 2, n), name));
1069     }
1070     term = mK.qzz * T[ti(l, m, n + 2)];
1071     if (term != 0) {
1072       trace += term;
1073       traceSB.append(loadTensor(l, m, n + 2, tensorHash));
1074       traceSB.append(format("\t%s = qzz.fma(t%s, %s);\n", name, lmn(l, m, n + 2), name));
1075     }
1076     total += trace;
1077     if (total != 0) {
1078       sb.append(sb1);
1079       if (trace != 0) {
1080         sb.append(traceSB);
1081       }
1082     }
1083     term = mK.qxy * T[ti(l + 1, m + 1, n)];
1084     if (term != 0) {
1085       total += term;
1086       sb.append(loadTensor(l + 1, m + 1, n, tensorHash));
1087       sb.append(format("\t%s = qxy.fma(t%s, %s);\n", name, lmn(l + 1, m + 1, n), name));
1088     }
1089     term = mK.qxz * T[ti(l + 1, m, n + 1)];
1090     if (term != 0) {
1091       total += term;
1092       sb.append(loadTensor(l + 1, m, n + 1, tensorHash));
1093       sb.append(format("\t%s = qxz.fma(t%s, %s);\n", name, lmn(l + 1, m, n + 1), name));
1094     }
1095     term = mK.qyz * T[ti(l, m + 1, n + 1)];
1096     if (term != 0) {
1097       total += term;
1098       sb.append(loadTensor(l, m + 1, n + 1, tensorHash));
1099       sb.append(format("\t%s = qyz.fma(t%s, %s);\n", name, lmn(l, m + 1, n + 1), name));
1100     }
1101     return total;
1102   }
1103 
1104   /**
1105    * Collect the potential its partial derivatives at K due to multipole moments at the origin.
1106    *
1107    * @param mI PolarizableMultipole at site I.
1108    * @param T  Electrostatic potential and partial derivatives.
1109    * @param l  apply (d/dx)^l to the potential.
1110    * @param m  apply (d/dy)^l to the potential.
1111    * @param n  apply (d/dz)^l to the potential.
1112    * @param sb Append the code to the StringBuilder.
1113    */
1114   protected void codePotentialMultipoleI(PolarizableMultipole mI, double[] T, int l, int m, int n, StringBuilder sb) {
1115     E000 = codeContractMultipoleI(mI, T, l, m, n, sb);
1116     if (E000 != 0) {
1117       sb.append(format("E000 = %s;\n", term(l, m, n)));
1118     }
1119     // Order 1
1120     E100 = codeContractMultipoleI(mI, T, l + 1, m, n, sb);
1121     if (E100 != 0) {
1122       sb.append(format("E100 = %s;\n", term(l + 1, m, n)));
1123     }
1124     E010 = codeContractMultipoleI(mI, T, l, m + 1, n, sb);
1125     if (E100 != 0) {
1126       sb.append(format("E010 = %s;\n", term(l, m + 1, n)));
1127     }
1128     E001 = codeContractMultipoleI(mI, T, l, m, n + 1, sb);
1129     if (E001 != 0) {
1130       sb.append(format("E001 = %s;\n", term(l, m, n + 1)));
1131     }
1132     // Order 2
1133     E200 = codeContractMultipoleI(mI, T, l + 2, m, n, sb);
1134     if (E200 != 0) {
1135       sb.append(format("E200 = %s;\n", term(l + 2, m, n)));
1136     }
1137     E020 = codeContractMultipoleI(mI, T, l, m + 2, n, sb);
1138     if (E020 != 0) {
1139       sb.append(format("E020 = %s;\n", term(l, m + 2, n)));
1140     }
1141     E002 = codeContractMultipoleI(mI, T, l, m, n + 2, sb);
1142     if (E002 != 0) {
1143       sb.append(format("E002 = %s;\n", term(l, m, n + 2)));
1144     }
1145     E110 = codeContractMultipoleI(mI, T, l + 1, m + 1, n, sb);
1146     if (E110 != 0) {
1147       sb.append(format("E110 = %s;\n", term(l + 1, m + 1, n)));
1148     }
1149     E101 = codeContractMultipoleI(mI, T, l + 1, m, n + 1, sb);
1150     if (E101 != 0) {
1151       sb.append(format("E101 = %s;\n", term(l + 1, m, n + 1)));
1152     }
1153     E011 = codeContractMultipoleI(mI, T, l, m + 1, n + 1, sb);
1154     if (E011 != 0) {
1155       sb.append(format("E011 = %s;\n", term(l, m + 1, n + 1)));
1156     }
1157     // Order 3
1158     E300 = codeContractMultipoleI(mI, T, l + 3, m, n, sb);
1159     if (E300 != 0) {
1160       sb.append(format("E300 = %s;\n", term(l + 3, m, n)));
1161     }
1162     E030 = codeContractMultipoleI(mI, T, l, m + 3, n, sb);
1163     if (E030 != 0) {
1164       sb.append(format("E030 = %s;\n", term(l, m + 3, n)));
1165     }
1166     E003 = codeContractMultipoleI(mI, T, l, m, n + 3, sb);
1167     if (E003 != 0) {
1168       sb.append(format("E003 = %s;\n", term(l, m, n + 3)));
1169     }
1170     E210 = codeContractMultipoleI(mI, T, l + 2, m + 1, n, sb);
1171     if (E210 != 0) {
1172       sb.append(format("E210 = %s;\n", term(l + 2, m + 1, n)));
1173     }
1174     E201 = codeContractMultipoleI(mI, T, l + 2, m, n + 1, sb);
1175     if (E201 != 0) {
1176       sb.append(format("E201 = %s;\n", term(l + 2, m, n + 1)));
1177     }
1178     E120 = codeContractMultipoleI(mI, T, l + 1, m + 2, n, sb);
1179     if (E120 != 0) {
1180       sb.append(format("E120 = %s;\n", term(l + 1, m + 2, n)));
1181     }
1182     E021 = codeContractMultipoleI(mI, T, l, m + 2, n + 1, sb);
1183     if (E021 != 0) {
1184       sb.append(format("E021 = %s;\n", term(l, m + 2, n + 1)));
1185     }
1186     E102 = codeContractMultipoleI(mI, T, l + 1, m, n + 2, sb);
1187     if (E102 != 0) {
1188       sb.append(format("E102 = %s;\n", term(l + 1, m, n + 2)));
1189     }
1190     E012 = codeContractMultipoleI(mI, T, l, m + 1, n + 2, sb);
1191     if (E012 != 0) {
1192       sb.append(format("E012 = %s;\n", term(l, m + 1, n + 2)));
1193     }
1194     E111 = codeContractMultipoleI(mI, T, l + 1, m + 1, n + 1, sb);
1195     if (E111 != 0) {
1196       sb.append(format("E111 = %s;\n", term(l + 1, m + 1, n + 1)));
1197     }
1198   }
1199 
1200   /**
1201    * Collect the potential its partial derivatives at K due to multipole moments at the origin
1202    * using SIMD instructions.
1203    *
1204    * @param mI PolarizableMultipole at site I.
1205    * @param T  Electrostatic potential and partial derivatives.
1206    * @param l  apply (d/dx)^l to the potential.
1207    * @param m  apply (d/dy)^l to the potential.
1208    * @param n  apply (d/dz)^l to the potential.
1209    * @param sb Append the code to the StringBuilder.
1210    */
1211   protected void codePotentialMultipoleISIMD(PolarizableMultipole mI, double[] T, int l, int m, int n, StringBuilder sb) {
1212     String to = "e";
1213     HashMap<Integer, String> tensorHash = new HashMap<>();
1214     sb.append("\n// Order 0\n");
1215     E000 = codeContractMultipoleISIMD(mI, T, l, m, n, sb, tensorHash);
1216     if (E000 != 0) {
1217       sb.append(storePotential(to, l, m, n));
1218     }
1219 
1220     // Order 1
1221     sb.append("\n// Order 1\n");
1222     E100 = codeContractMultipoleISIMD(mI, T, l + 1, m, n, sb, tensorHash);
1223     if (E100 != 0) {
1224       sb.append(storePotential(to, l + 1, m, n));
1225     }
1226     E010 = codeContractMultipoleISIMD(mI, T, l, m + 1, n, sb, tensorHash);
1227     if (E100 != 0) {
1228       sb.append(storePotential(to, l, m + 1, n));
1229     }
1230     E001 = codeContractMultipoleISIMD(mI, T, l, m, n + 1, sb, tensorHash);
1231     if (E001 != 0) {
1232       sb.append(storePotential(to, l, m, n + 1));
1233     }
1234 
1235     // Order 2
1236     sb.append("\n// Order 2\n");
1237     E200 = codeContractMultipoleISIMD(mI, T, l + 2, m, n, sb, tensorHash);
1238     if (E200 != 0) {
1239       sb.append(storePotential(to, l + 2, m, n));
1240     }
1241     E020 = codeContractMultipoleISIMD(mI, T, l, m + 2, n, sb, tensorHash);
1242     if (E020 != 0) {
1243       sb.append(storePotential(to, l, m + 2, n));
1244     }
1245     E002 = codeContractMultipoleISIMD(mI, T, l, m, n + 2, sb, tensorHash);
1246     if (E002 != 0) {
1247       sb.append(storePotential(to, l, m, n + 2));
1248     }
1249     E110 = codeContractMultipoleISIMD(mI, T, l + 1, m + 1, n, sb, tensorHash);
1250     if (E110 != 0) {
1251       sb.append(storePotential(to, l + 1, m + 1, n));
1252     }
1253     E101 = codeContractMultipoleISIMD(mI, T, l + 1, m, n + 1, sb, tensorHash);
1254     if (E101 != 0) {
1255       sb.append(storePotential(to, l + 1, m, n + 1));
1256     }
1257     E011 = codeContractMultipoleISIMD(mI, T, l, m + 1, n + 1, sb, tensorHash);
1258     if (E011 != 0) {
1259       sb.append(storePotential(to, l, m + 1, n + 1));
1260     }
1261 
1262     // Order 3
1263     sb.append("\n// Order 3\n");
1264     E300 = codeContractMultipoleISIMD(mI, T, l + 3, m, n, sb, tensorHash);
1265     if (E300 != 0) {
1266       sb.append(storePotential(to, l + 3, m, n));
1267     }
1268     E030 = codeContractMultipoleISIMD(mI, T, l, m + 3, n, sb, tensorHash);
1269     if (E030 != 0) {
1270       sb.append(storePotential(to, l, m + 3, n));
1271     }
1272     E003 = codeContractMultipoleISIMD(mI, T, l, m, n + 3, sb, tensorHash);
1273     if (E003 != 0) {
1274       sb.append(storePotential(to, l, m, n + 3));
1275     }
1276     E210 = codeContractMultipoleISIMD(mI, T, l + 2, m + 1, n, sb, tensorHash);
1277     if (E210 != 0) {
1278       sb.append(storePotential(to, l + 2, m + 1, n));
1279     }
1280     E201 = codeContractMultipoleISIMD(mI, T, l + 2, m, n + 1, sb, tensorHash);
1281     if (E201 != 0) {
1282       sb.append(storePotential(to, l + 2, m, n + 1));
1283     }
1284     E120 = codeContractMultipoleISIMD(mI, T, l + 1, m + 2, n, sb, tensorHash);
1285     if (E120 != 0) {
1286       sb.append(storePotential(to, l + 1, m + 2, n));
1287     }
1288     E021 = codeContractMultipoleISIMD(mI, T, l, m + 2, n + 1, sb, tensorHash);
1289     if (E021 != 0) {
1290       sb.append(storePotential(to, l, m + 2, n + 1));
1291     }
1292     E102 = codeContractMultipoleISIMD(mI, T, l + 1, m, n + 2, sb, tensorHash);
1293     if (E102 != 0) {
1294       sb.append(storePotential(to, l + 1, m, n + 2));
1295     }
1296     E012 = codeContractMultipoleISIMD(mI, T, l, m + 1, n + 2, sb, tensorHash);
1297     if (E012 != 0) {
1298       sb.append(storePotential(to, l, m + 1, n + 2));
1299     }
1300     E111 = codeContractMultipoleISIMD(mI, T, l + 1, m + 1, n + 1, sb, tensorHash);
1301     if (E111 != 0) {
1302       sb.append(storePotential(to, l + 1, m + 1, n + 1));
1303     }
1304   }
1305 
1306   /**
1307    * Collect the potential its partial derivatives at the origin due to multipole moments at site K.
1308    *
1309    * @param mK PolarizableMultipole at site I.
1310    * @param T  Electrostatic potential and partial derivatives.
1311    * @param l  apply (d/dx)^l to the potential.
1312    * @param m  apply (d/dy)^l to the potential.
1313    * @param n  apply (d/dz)^l to the potential.
1314    * @param sb Append the code to the StringBuilder.
1315    */
1316   protected void codePotentialMultipoleK(PolarizableMultipole mK, double[] T, int l, int m, int n, StringBuilder sb) {
1317     E000 = codeContractMultipoleK(mK, T, l, m, n, sb);
1318     if (E000 != 0) {
1319       sb.append(format("E000 = %s;\n", term(l, m, n)));
1320     }
1321     // Order 1 (need a minus sign)
1322     E100 = codeContractMultipoleK(mK, T, l + 1, m, n, sb);
1323     if (E100 != 0) {
1324       sb.append(format("E100 = -%s;\n", term(l + 1, m, n)));
1325     }
1326     E010 = codeContractMultipoleK(mK, T, l, m + 1, n, sb);
1327     if (E100 != 0) {
1328       sb.append(format("E010 = -%s;\n", term(l, m + 1, n)));
1329     }
1330     E001 = codeContractMultipoleK(mK, T, l, m, n + 1, sb);
1331     if (E001 != 0) {
1332       sb.append(format("E001 = -%s;\n", term(l, m, n + 1)));
1333     }
1334     // Order 2
1335     E200 = codeContractMultipoleK(mK, T, l + 2, m, n, sb);
1336     if (E200 != 0) {
1337       sb.append(format("E200 = %s;\n", term(l + 2, m, n)));
1338     }
1339     E020 = codeContractMultipoleK(mK, T, l, m + 2, n, sb);
1340     if (E020 != 0) {
1341       sb.append(format("E020 = %s;\n", term(l, m + 2, n)));
1342     }
1343     E002 = codeContractMultipoleK(mK, T, l, m, n + 2, sb);
1344     if (E002 != 0) {
1345       sb.append(format("E002 = %s;\n", term(l, m, n + 2)));
1346     }
1347     E110 = codeContractMultipoleK(mK, T, l + 1, m + 1, n, sb);
1348     if (E110 != 0) {
1349       sb.append(format("E110 = %s;\n", term(l + 1, m + 1, n)));
1350     }
1351     E101 = codeContractMultipoleK(mK, T, l + 1, m, n + 1, sb);
1352     if (E101 != 0) {
1353       sb.append(format("E101 = %s;\n", term(l + 1, m, n + 1)));
1354     }
1355     E011 = codeContractMultipoleK(mK, T, l, m + 1, n + 1, sb);
1356     if (E011 != 0) {
1357       sb.append(format("E011 = %s;\n", term(l, m + 1, n + 1)));
1358     }
1359     // Order 3 (need a minus sign)
1360     E300 = codeContractMultipoleK(mK, T, l + 3, m, n, sb);
1361     if (E300 != 0) {
1362       sb.append(format("E300 = -%s;\n", term(l + 3, m, n)));
1363     }
1364     E030 = codeContractMultipoleK(mK, T, l, m + 3, n, sb);
1365     if (E030 != 0) {
1366       sb.append(format("E030 = -%s;\n", term(l, m + 3, n)));
1367     }
1368     E003 = codeContractMultipoleK(mK, T, l, m, n + 3, sb);
1369     if (E003 != 0) {
1370       sb.append(format("E003 = -%s;\n", term(l, m, n + 3)));
1371     }
1372     E210 = codeContractMultipoleK(mK, T, l + 2, m + 1, n, sb);
1373     if (E210 != 0) {
1374       sb.append(format("E210 = -%s;\n", term(l + 2, m + 1, n)));
1375     }
1376     E201 = codeContractMultipoleK(mK, T, l + 2, m, n + 1, sb);
1377     if (E201 != 0) {
1378       sb.append(format("E201 = -%s;\n", term(l + 2, m, n + 1)));
1379     }
1380     E120 = codeContractMultipoleK(mK, T, l + 1, m + 2, n, sb);
1381     if (E120 != 0) {
1382       sb.append(format("E120 = -%s;\n", term(l + 1, m + 2, n)));
1383     }
1384     E021 = codeContractMultipoleK(mK, T, l, m + 2, n + 1, sb);
1385     if (E021 != 0) {
1386       sb.append(format("E021 = -%s;\n", term(l, m + 2, n + 1)));
1387     }
1388     E102 = codeContractMultipoleK(mK, T, l + 1, m, n + 2, sb);
1389     if (E102 != 0) {
1390       sb.append(format("E102 = -%s;\n", term(l + 1, m, n + 2)));
1391     }
1392     E012 = codeContractMultipoleK(mK, T, l, m + 1, n + 2, sb);
1393     if (E012 != 0) {
1394       sb.append(format("E012 = -%s;\n", term(l, m + 1, n + 2)));
1395     }
1396     E111 = codeContractMultipoleK(mK, T, l + 1, m + 1, n + 1, sb);
1397     if (E111 != 0) {
1398       sb.append(format("E111 = -%s;\n", term(l + 1, m + 1, n + 1)));
1399     }
1400   }
1401 
1402   /**
1403    * Collect the potential its partial derivatives at the origin due to multipole moments at site K
1404    * using SIMD instructions.
1405    *
1406    * @param mK PolarizableMultipole at site I.
1407    * @param T  Electrostatic potential and partial derivatives.
1408    * @param l  apply (d/dx)^l to the potential.
1409    * @param m  apply (d/dy)^l to the potential.
1410    * @param n  apply (d/dz)^l to the potential.
1411    * @param sb Append the code to the StringBuilder.
1412    */
1413   protected void codePotentialMultipoleKSIMD(PolarizableMultipole mK, double[] T, int l, int m, int n, StringBuilder sb) {
1414     String to = "e";
1415 
1416     // Order 0.
1417     sb.append("\n// Order 0\n");
1418     // Store tensor names to avoid reloading them.
1419     HashMap<Integer, String> tensorHash = new HashMap<>();
1420     E000 = codeContractMultipoleKSIMD(mK, T, l, m, n, sb, tensorHash);
1421     if (E000 != 0) {
1422       sb.append(storePotential(to, l, m, n));
1423     }
1424 
1425     // Order 1 (need a minus sign)
1426     sb.append("\n// Order 1\n");
1427     E100 = codeContractMultipoleKSIMD(mK, T, l + 1, m, n, sb, tensorHash);
1428     if (E100 != 0) {
1429       sb.append(storePotentialNeg(to, l + 1, m, n));
1430     }
1431     E010 = codeContractMultipoleKSIMD(mK, T, l, m + 1, n, sb, tensorHash);
1432     if (E010 != 0) {
1433       sb.append(storePotentialNeg(to, l, m + 1, n));
1434     }
1435     E001 = codeContractMultipoleKSIMD(mK, T, l, m, n + 1, sb, tensorHash);
1436     if (E001 != 0) {
1437       sb.append(storePotentialNeg(to, l, m, n + 1));
1438     }
1439 
1440     // Order 2
1441     sb.append("\n// Order 2\n");
1442     E200 = codeContractMultipoleKSIMD(mK, T, l + 2, m, n, sb, tensorHash);
1443     if (E200 != 0) {
1444       sb.append(storePotential(to, l + 2, m, n));
1445     }
1446     E020 = codeContractMultipoleKSIMD(mK, T, l, m + 2, n, sb, tensorHash);
1447     if (E020 != 0) {
1448       sb.append(storePotential(to, l, m + 2, n));
1449     }
1450     E002 = codeContractMultipoleKSIMD(mK, T, l, m, n + 2, sb, tensorHash);
1451     if (E002 != 0) {
1452       sb.append(storePotential(to, l, m, n + 2));
1453     }
1454     E110 = codeContractMultipoleKSIMD(mK, T, l + 1, m + 1, n, sb, tensorHash);
1455     if (E110 != 0) {
1456       sb.append(storePotential(to, l + 1, m + 1, n));
1457     }
1458     E101 = codeContractMultipoleKSIMD(mK, T, l + 1, m, n + 1, sb, tensorHash);
1459     if (E101 != 0) {
1460       sb.append(storePotential(to, l + 1, m, n + 1));
1461     }
1462     E011 = codeContractMultipoleKSIMD(mK, T, l, m + 1, n + 1, sb, tensorHash);
1463     if (E011 != 0) {
1464       sb.append(storePotential(to, l, m + 1, n + 1));
1465     }
1466 
1467     // Order 3 (need a minus sign)
1468     sb.append("\n// Order 3\n");
1469     E300 = codeContractMultipoleKSIMD(mK, T, l + 3, m, n, sb, tensorHash);
1470     if (E300 != 0) {
1471       sb.append(storePotentialNeg(to, l + 3, m, n));
1472     }
1473     E030 = codeContractMultipoleKSIMD(mK, T, l, m + 3, n, sb, tensorHash);
1474     if (E030 != 0) {
1475       sb.append(storePotentialNeg(to, l, m + 3, n));
1476     }
1477     E003 = codeContractMultipoleKSIMD(mK, T, l, m, n + 3, sb, tensorHash);
1478     if (E003 != 0) {
1479       sb.append(storePotentialNeg(to, l, m, n + 3));
1480     }
1481     E210 = codeContractMultipoleKSIMD(mK, T, l + 2, m + 1, n, sb, tensorHash);
1482     if (E210 != 0) {
1483       sb.append(storePotentialNeg(to, l + 2, m + 1, n));
1484     }
1485     E201 = codeContractMultipoleKSIMD(mK, T, l + 2, m, n + 1, sb, tensorHash);
1486     if (E201 != 0) {
1487       sb.append(storePotentialNeg(to, l + 2, m, n + 1));
1488     }
1489     E120 = codeContractMultipoleKSIMD(mK, T, l + 1, m + 2, n, sb, tensorHash);
1490     if (E120 != 0) {
1491       sb.append(storePotentialNeg(to, l + 1, m + 2, n));
1492     }
1493     E021 = codeContractMultipoleKSIMD(mK, T, l, m + 2, n + 1, sb, tensorHash);
1494     if (E021 != 0) {
1495       sb.append(storePotentialNeg(to, l, m + 2, n + 1));
1496     }
1497     E102 = codeContractMultipoleKSIMD(mK, T, l + 1, m, n + 2, sb, tensorHash);
1498     if (E102 != 0) {
1499       sb.append(storePotentialNeg(to, l + 1, m, n + 2));
1500     }
1501     E012 = codeContractMultipoleKSIMD(mK, T, l, m + 1, n + 2, sb, tensorHash);
1502     if (E012 != 0) {
1503       sb.append(storePotentialNeg(to, l, m + 1, n + 2));
1504     }
1505     E111 = codeContractMultipoleKSIMD(mK, T, l + 1, m + 1, n + 1, sb, tensorHash);
1506     if (E111 != 0) {
1507       sb.append(storePotentialNeg(to, l + 1, m + 1, n + 1));
1508     }
1509   }
1510 
1511   /**
1512    * Contract a multipole with the potential and its derivatives.
1513    *
1514    * @param m PolarizableMultipole at the site of the potential.
1515    * @return The permanent multipole energy.
1516    */
1517   protected final double multipoleEnergy(PolarizableMultipole m) {
1518     double total = m.q * E000;
1519     total = fma(m.dx, E100, total);
1520     total = fma(m.dy, E010, total);
1521     total = fma(m.dz, E001, total);
1522     total = fma(m.qxx, E200, total);
1523     total = fma(m.qyy, E020, total);
1524     total = fma(m.qzz, E002, total);
1525     total = fma(m.qxy, E110, total);
1526     total = fma(m.qxz, E101, total);
1527     total = fma(m.qyz, E011, total);
1528     return total;
1529   }
1530 
1531   /**
1532    * Compute the permanent multipole gradient.
1533    *
1534    * @param m PolarizableMultipole at the site of the potential.
1535    * @param g The atomic gradient.
1536    */
1537   protected final void multipoleGradient(PolarizableMultipole m, double[] g) {
1538     // dEnergy/dY
1539     double total = m.q * E100;
1540     total = fma(m.dx, E200, total);
1541     total = fma(m.dy, E110, total);
1542     total = fma(m.dz, E101, total);
1543     total = fma(m.qxx, E300, total);
1544     total = fma(m.qyy, E120, total);
1545     total = fma(m.qzz, E102, total);
1546     total = fma(m.qxy, E210, total);
1547     total = fma(m.qxz, E201, total);
1548     total = fma(m.qyz, E111, total);
1549     g[0] = total;
1550 
1551     // dEnergy/dY
1552     total = m.q * E010;
1553     total = fma(m.dx, E110, total);
1554     total = fma(m.dy, E020, total);
1555     total = fma(m.dz, E011, total);
1556     total = fma(m.qxx, E210, total);
1557     total = fma(m.qyy, E030, total);
1558     total = fma(m.qzz, E012, total);
1559     total = fma(m.qxy, E120, total);
1560     total = fma(m.qxz, E111, total);
1561     total = fma(m.qyz, E021, total);
1562     g[1] = total;
1563 
1564     // dEnergy/dZ
1565     total = m.q * E001;
1566     total = fma(m.dx, E101, total);
1567     total = fma(m.dy, E011, total);
1568     total = fma(m.dz, E002, total);
1569     total = fma(m.qxx, E201, total);
1570     total = fma(m.qyy, E021, total);
1571     total = fma(m.qzz, E003, total);
1572     total = fma(m.qxy, E111, total);
1573     total = fma(m.qxz, E102, total);
1574     total = fma(m.qyz, E012, total);
1575     g[2] = total;
1576   }
1577 
1578   /**
1579    * Compute the torque on a permanent multipole.
1580    *
1581    * @param m      PolarizableMultipole at the site of the potential.
1582    * @param torque an array of {@link double} objects.
1583    */
1584   protected final void multipoleTorque(PolarizableMultipole m, double[] torque) {
1585     // Torque on the permanent dipole due to the field.
1586     double dx = m.dy * E001 - m.dz * E010;
1587     double dy = m.dz * E100 - m.dx * E001;
1588     double dz = m.dx * E010 - m.dy * E100;
1589 
1590     // Torque on the permanent quadrupole due to the gradient of the field.
1591     double qx = m.qxy * E101 + 2.0 * m.qyy * E011 + m.qyz * E002
1592         - (m.qxz * E110 + m.qyz * E020 + 2.0 * m.qzz * E011);
1593     double qy = m.qxz * E200 + m.qyz * E110 + 2.0 * m.qzz * E101
1594         - (2.0 * m.qxx * E101 + m.qxy * E011 + m.qxz * E002);
1595     double qz = 2.0 * m.qxx * E110 + m.qxy * E020 + m.qxz * E011
1596         - (m.qxy * E200 + 2.0 * m.qyy * E110 + m.qyz * E101);
1597 
1598     // The field along X is -E001, so we need a negative sign.
1599     torque[0] -= (dx + qx);
1600     torque[1] -= (dy + qy);
1601     torque[2] -= (dz + qz);
1602   }
1603 
1604   /**
1605    * Compute the torque on a permanent dipole.
1606    *
1607    * @param m      PolarizableMultipole at the site of the potential.
1608    * @param torque an array of {@link double} objects.
1609    */
1610   protected final void dipoleTorque(PolarizableMultipole m, double[] torque) {
1611     // Torque on the permanent dipole due to the field.
1612     double dx = m.dy * E001 - m.dz * E010;
1613     double dy = m.dz * E100 - m.dx * E001;
1614     double dz = m.dx * E010 - m.dy * E100;
1615 
1616     // The field along X is -E001, so we need a negative sign.
1617     torque[0] -= dx;
1618     torque[1] -= dy;
1619     torque[2] -= dz;
1620   }
1621 
1622   /**
1623    * Compute the torque on a permanent quadrupole.
1624    *
1625    * @param m      PolarizableMultipole at the site of the potential.
1626    * @param torque an array of {@link double} objects.
1627    */
1628   protected final void quadrupoleTorque(PolarizableMultipole m, double[] torque) {
1629     // Torque on the permanent quadrupole due to the gradient of the field.
1630     double qx = m.qxy * E101 + 2.0 * m.qyy * E011 + m.qyz * E002
1631         - (m.qxz * E110 + m.qyz * E020 + 2.0 * m.qzz * E011);
1632     double qy = m.qxz * E200 + m.qyz * E110 + 2.0 * m.qzz * E101
1633         - (2.0 * m.qxx * E101 + m.qxy * E011 + m.qxz * E002);
1634     double qz = 2.0 * m.qxx * E110 + m.qxy * E020 + m.qxz * E011
1635         - (m.qxy * E200 + 2.0 * m.qyy * E110 + m.qyz * E101);
1636 
1637     // The field along X is -E001, so we need a negative sign.
1638     torque[0] -= qx;
1639     torque[1] -= qy;
1640     torque[2] -= qz;
1641   }
1642 
1643   /**
1644    * Contract an induced dipole with the potential and its derivatives.
1645    *
1646    * @param m PolarizableMultipole at the site of the potential.
1647    * @return The polarization energy.
1648    */
1649   protected final double polarizationEnergy(PolarizableMultipole m) {
1650     // E = -1/2 * u.E
1651     // No negative sign because the field E = [-E100, -E010, -E001].
1652     return 0.5 * (m.ux * E100 + m.uy * E010 + m.uz * E001);
1653   }
1654 
1655   /**
1656    * Contract an induced dipole with the potential and its derivatives.
1657    *
1658    * @param m PolarizableMultipole at the site of the potential.
1659    * @return The polarization energy.
1660    */
1661   protected final double polarizationEnergyS(PolarizableMultipole m) {
1662     // E = -1/2 * u.E
1663     // No negative sign because the field E = [-E100, -E010, -E001].
1664     return 0.5 * (m.sx * E100 + m.sy * E010 + m.sz * E001);
1665   }
1666 
1667   /**
1668    * Load the tensor components.
1669    *
1670    * @param T an array of {@link double} objects.
1671    */
1672   @SuppressWarnings("fallthrough")
1673   protected final void getTensor(double[] T) {
1674     switch (order) {
1675       default:
1676       case 5:
1677         // l + m + n = 5 (21) 56
1678         T[t500] = R500;
1679         T[t050] = R050;
1680         T[t005] = R005;
1681         T[t410] = R410;
1682         T[t401] = R401;
1683         T[t140] = R140;
1684         T[t041] = R041;
1685         T[t104] = R104;
1686         T[t014] = R014;
1687         T[t320] = R320;
1688         T[t302] = R302;
1689         T[t230] = R230;
1690         T[t032] = R032;
1691         T[t203] = R203;
1692         T[t023] = R023;
1693         T[t311] = R311;
1694         T[t131] = R131;
1695         T[t113] = R113;
1696         T[t221] = R221;
1697         T[t212] = R212;
1698         T[t122] = R122;
1699         // Fall through to 4th order.
1700       case 4:
1701         // l + m + n = 4 (15) 35
1702         T[t400] = R400;
1703         T[t040] = R040;
1704         T[t004] = R004;
1705         T[t310] = R310;
1706         T[t301] = R301;
1707         T[t130] = R130;
1708         T[t031] = R031;
1709         T[t103] = R103;
1710         T[t013] = R013;
1711         T[t220] = R220;
1712         T[t202] = R202;
1713         T[t022] = R022;
1714         T[t211] = R211;
1715         T[t121] = R121;
1716         T[t112] = R112;
1717         // Fall through to 3rd order.
1718       case 3:
1719         // l + m + n = 3 (10) 20
1720         T[t300] = R300;
1721         T[t030] = R030;
1722         T[t003] = R003;
1723         T[t210] = R210;
1724         T[t201] = R201;
1725         T[t120] = R120;
1726         T[t021] = R021;
1727         T[t102] = R102;
1728         T[t012] = R012;
1729         T[t111] = R111;
1730         // Fall through to 2nd order.
1731       case 2:
1732         // l + m + n = 2 (6)  10
1733         T[t200] = R200;
1734         T[t020] = R020;
1735         T[t002] = R002;
1736         T[t110] = R110;
1737         T[t101] = R101;
1738         T[t011] = R011;
1739         // Fall through to 1st order.
1740       case 1:
1741         // l + m + n = 1 (3)   4
1742         T[t100] = R100;
1743         T[t010] = R010;
1744         T[t001] = R001;
1745         // Fall through to the potential.
1746       case 0:
1747         // l + m + n = 0 (1)
1748         T[t000] = R000;
1749     }
1750   }
1751 
1752   /**
1753    * Set the tensor components.
1754    *
1755    * @param T an array of {@link double} objects.
1756    */
1757   @SuppressWarnings("fallthrough")
1758   protected final void setTensor(double[] T) {
1759     switch (order) {
1760       case 5:
1761         // l + m + n = 5 (21) 56
1762         R500 = T[t500];
1763         R050 = T[t050];
1764         R005 = T[t005];
1765         R410 = T[t410];
1766         R401 = T[t401];
1767         R140 = T[t140];
1768         R041 = T[t041];
1769         R104 = T[t104];
1770         R014 = T[t014];
1771         R320 = T[t320];
1772         R302 = T[t302];
1773         R230 = T[t230];
1774         R032 = T[t032];
1775         R203 = T[t203];
1776         R023 = T[t023];
1777         R311 = T[t311];
1778         R131 = T[t131];
1779         R113 = T[t113];
1780         R221 = T[t221];
1781         R212 = T[t212];
1782         R122 = T[t122];
1783         // Fall through to 4th order.
1784       case 4:
1785         // l + m + n = 4 (15) 35
1786         R400 = T[t400];
1787         R040 = T[t040];
1788         R004 = T[t004];
1789         R310 = T[t310];
1790         R301 = T[t301];
1791         R130 = T[t130];
1792         R031 = T[t031];
1793         R103 = T[t103];
1794         R013 = T[t013];
1795         R220 = T[t220];
1796         R202 = T[t202];
1797         R022 = T[t022];
1798         R211 = T[t211];
1799         R121 = T[t121];
1800         R112 = T[t112];
1801         // Fall through to 3rd order.
1802       case 3:
1803         // l + m + n = 3 (10) 20
1804         R300 = T[t300];
1805         R030 = T[t030];
1806         R003 = T[t003];
1807         R210 = T[t210];
1808         R201 = T[t201];
1809         R120 = T[t120];
1810         R021 = T[t021];
1811         R102 = T[t102];
1812         R012 = T[t012];
1813         R111 = T[t111];
1814         // Fall through to 2nd order.
1815       case 2:
1816         // l + m + n = 2 (6)  10
1817         R200 = T[t200];
1818         R020 = T[t020];
1819         R002 = T[t002];
1820         R110 = T[t110];
1821         R101 = T[t101];
1822         R011 = T[t011];
1823         // Fall through to 1st order.
1824       case 1:
1825         // l + m + n = 1 (3)   4
1826         R100 = T[t100];
1827         R010 = T[t010];
1828         R001 = T[t001];
1829         // Fall through to the potential.
1830       case 0:
1831         // l + m + n = 0 (1)
1832         R000 = T[t000];
1833     }
1834   }
1835 
1836   /**
1837    * This method is a driver to collect elements of the Cartesian multipole tensor given the
1838    * recursion relationships implemented by the method "Tlmnj", which can be called directly to get a
1839    * single tensor element. It does not store intermediate values of the recursion, causing it to
1840    * scale O(order^8). For order = 5, this approach is a factor of 10 slower than recursion.
1841    *
1842    * @param tensor double[] length must be at least binomial(order + 3, 3).
1843    */
1844   protected abstract void noStorageRecursion(double[] tensor);
1845 
1846   /**
1847    * This method is a driver to collect elements of the Cartesian multipole tensor given the
1848    * recursion relationships implemented by the method "Tlmnj", which can be called directly to get a
1849    * single tensor element. It does not store intermediate values of the recursion, causing it to
1850    * scale O(order^8). For order = 5, this approach is a factor of 10 slower than recursion.
1851    *
1852    * @param r      double[] vector between two sites.
1853    * @param tensor double[] length must be at least binomial(order + 3, 3).
1854    */
1855   protected abstract void noStorageRecursion(double[] r, double[] tensor);
1856 
1857   /**
1858    * This routine implements the recurrence relations for computation of any Cartesian multipole
1859    * tensor in ~O(L^8) time, where L is the total order l + m + n, given the auxiliary elements
1860    * T0000. <br> It implements the recursion relationships in brute force fashion, without saving
1861    * intermediate values. This is useful for finding a single tensor, rather than all binomial(L + 3,
1862    * 3). <br> The specific recursion equations (41-43) and set of auxiliary tensor elements from
1863    * equation (40) can be found in Challacombe et al.
1864    *
1865    * @param l    int The number of (d/dx) operations.
1866    * @param m    int The number of (d/dy) operations.
1867    * @param n    int The number of (d/dz) operations.
1868    * @param j    int j = 0 is the Tlmn tensor, j .GT. 0 is an intermediate.
1869    * @param r    double[] The {x,y,z} coordinates.
1870    * @param T000 double[] Initial auxiliary tensor elements from Eq. (40).
1871    * @return double The requested Tensor element (intermediate if j .GT. 0).
1872    * @since 1.0
1873    */
1874   protected abstract double Tlmnj(final int l, final int m, final int n, final int j,
1875                                   final double[] r, final double[] T000);
1876 
1877   /**
1878    * This method is a driver to collect elements of the Cartesian multipole tensor using recursion
1879    * relationships and storing intermediate values. It scales approximately O(order^4).
1880    *
1881    * @param tensor double[] length must be at least binomial(order + 3, 3).
1882    */
1883   protected abstract void recursion(final double[] tensor);
1884 
1885   /**
1886    * This method is a driver to collect elements of the Cartesian multipole tensor using recursion
1887    * relationships and storing intermediate values. It scales approximately O(order^4).
1888    *
1889    * @param r      double[] vector between two sites.
1890    * @param tensor double[] length must be at least binomial(order + 3, 3).
1891    */
1892   protected abstract void recursion(final double[] r, final double[] tensor);
1893 
1894   /**
1895    * Hard coded computation of the Cartesian multipole tensors up to 1st order.
1896    */
1897   protected abstract void order1();
1898 
1899   /**
1900    * Hard coded computation of the Cartesian multipole tensors up to 2nd order.
1901    */
1902   protected abstract void order2();
1903 
1904   /**
1905    * Hard coded computation of the Cartesian multipole tensors up to 3rd order.
1906    */
1907   protected abstract void order3();
1908 
1909   /**
1910    * Hard coded computation of the Cartesian multipole tensors up to 4th order.
1911    */
1912   protected abstract void order4();
1913 
1914   /**
1915    * Hard coded computation of the Cartesian multipole tensors up to 5th order, which is needed for
1916    * quadrupole-quadrupole forces.
1917    */
1918   protected abstract void order5();
1919 
1920   /**
1921    * Hard coded computation of the Cartesian multipole tensors up to 6th order, which is needed for
1922    * quadrupole-quadrupole forces and orthogonal space sampling.
1923    */
1924   protected abstract void order6();
1925 
1926   /**
1927    * Compute the field components due to multipole I at site K.
1928    *
1929    * @param mI    PolarizableMultipole at site I.
1930    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
1931    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
1932    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
1933    *              3: 3rd derivatives: (needed for quadrupole forces).
1934    */
1935   protected abstract void multipoleIPotentialAtK(PolarizableMultipole mI, int order);
1936 
1937   /**
1938    * Compute the field components due to charge I at site K.
1939    *
1940    * @param mI    PolarizableMultipole at site I.
1941    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
1942    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
1943    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
1944    *              3: 3rd derivatives: (needed for quadrupole forces).
1945    */
1946   protected abstract void chargeIPotentialAtK(PolarizableMultipole mI, int order);
1947 
1948   /**
1949    * Compute the induced dipole field components due to site I at site K.
1950    *
1951    * @param uxi   X-dipole component.
1952    * @param uyi   Y-dipole component.
1953    * @param uzi   Z-dipole component.
1954    * @param order Potential order.
1955    */
1956   protected abstract void dipoleIPotentialAtK(double uxi, double uyi, double uzi, int order);
1957 
1958   /**
1959    * Compute the field components due to quadrupole I at site K.
1960    *
1961    * @param mI    PolarizableMultipole at site I.
1962    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
1963    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
1964    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
1965    *              3: 3rd derivatives: (needed for quadrupole forces).
1966    */
1967   protected abstract void quadrupoleIPotentialAtK(PolarizableMultipole mI, int order);
1968 
1969   /**
1970    * Compute the field components due to multipole K at site I.
1971    *
1972    * @param mK    PolarizableMultipole at site K.
1973    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
1974    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
1975    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
1976    *              3: 3rd derivatives: (needed for quadrupole forces).
1977    */
1978   protected abstract void multipoleKPotentialAtI(PolarizableMultipole mK, int order);
1979 
1980   /**
1981    * Compute the field components due to multipole K at site I.
1982    *
1983    * @param mK    PolarizableMultipole at site K.
1984    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
1985    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
1986    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
1987    *              3: 3rd derivatives: (needed for quadrupole forces).
1988    */
1989   protected abstract void chargeKPotentialAtI(PolarizableMultipole mK, int order);
1990 
1991   /**
1992    * Compute the induced dipole field components due to site K at site I.
1993    *
1994    * @param uxk   X-dipole component.
1995    * @param uyk   Y-dipole component.
1996    * @param uzk   Z-dipole component.
1997    * @param order Potential order.
1998    */
1999   protected abstract void dipoleKPotentialAtI(double uxk, double uyk, double uzk, int order);
2000 
2001   /**
2002    * Compute the field components due to multipole K at site I.
2003    *
2004    * @param mK    PolarizableMultipole at site K.
2005    * @param order Compute derivatives of the potential up to this order. Order 0: Electrostatic
2006    *              potential (E000) Order 1: First derivatives: d/dX is E100, d/dY is E010, d/dZ is E001. Order
2007    *              2: Second derivatives: d2/dXdX is E200, d2/dXdY is E110 (needed for quadrupole energy) Order
2008    *              3: 3rd derivatives: (needed for quadrupole forces).
2009    */
2010   protected abstract void quadrupoleKPotentialAtI(PolarizableMultipole mK, int order);
2011 
2012   /**
2013    * Log the tensors.
2014    *
2015    * @param operator The OPERATOR to use.
2016    * @param order    The tensor order.
2017    * @param tensor   The tensor array.
2018    */
2019   private static void log(Operator operator, int order, double[] tensor) {
2020     final int o1 = order + 1;
2021     StringBuilder sb = new StringBuilder();
2022 
2023     sb.append(format("\n %s Operator to order %d:", operator, order));
2024     sb.append(format("\n%5s %4s %4s %4s %12s\n", "Index", "d/dx", "d/dy", "d/dz", "Tensor"));
2025     sb.append(format("%5d %4d %4d %4d %12.8f\n", 0, 0, 0, 0, tensor[0]));
2026     int count = 1;
2027     // Print (d/dx)^l for l = 1..order (m = 0, n = 0)
2028     for (int l = 1; l <= order; l++) {
2029       double value = tensor[MultipoleUtilities.ti(l, 0, 0, order)];
2030       if (value != 0.0) {
2031         sb.append(format("%5d %4d %4d %4d %12.8f\n", MultipoleUtilities.ti(l, 0, 0, order), l, 0, 0, value));
2032         count++;
2033       }
2034     }
2035     // Print (d/dx)^l * (d/dy)^m for l + m = 1..order (m >= 1, n = 0)
2036     for (int l = 0; l <= o1; l++) {
2037       for (int m = 1; m <= order - l; m++) {
2038         double value = tensor[MultipoleUtilities.ti(l, m, 0, order)];
2039         if (value != 0.0) {
2040           sb.append(format("%5d %4d %4d %4d %12.8f\n", MultipoleUtilities.ti(l, m, 0, order), l, m, 0, value));
2041           count++;
2042         }
2043       }
2044     }
2045     // Print (d/dx)^l * (d/dy)^m * (d/dz)^n for l + m + n = 1..o (n >= 1)
2046     for (int l = 0; l <= o1; l++) {
2047       for (int m = 0; m <= o1 - l; m++) {
2048         for (int n = 1; n <= order - l - m; n++) {
2049           double value = tensor[MultipoleUtilities.ti(l, m, n, order)];
2050           if (value != 0.0) {
2051             sb.append(format("%5d %4d %4d %4d %12.8f\n", MultipoleUtilities.ti(l, m, n, order), l, m, n, value));
2052             count++;
2053           }
2054         }
2055       }
2056     }
2057     sb.append(format("\n Total number of active tensors: %d\n", count));
2058     logger.log(Level.INFO, sb.toString());
2059   }
2060 
2061   // l + m + n = 0 (1)
2062   /**
2063    * No derivatives.
2064    */
2065   protected final int t000;
2066   // l + m + n = 1 (3)   4
2067   /**
2068    * First derivative with respect to x.
2069    */
2070   protected final int t100;
2071   /**
2072    * First derivative with respect to y.
2073    */
2074   protected final int t010;
2075   /**
2076    * First derivative with respect to z.
2077    */
2078   protected final int t001;
2079   // l + m + n = 2 (6)  10
2080   /**
2081    * Second derivative with respect to x.
2082    */
2083   protected final int t200;
2084   /**
2085    * Second derivative with respect to y.
2086    */
2087   protected final int t020;
2088   /**
2089    * Second derivative with respect to z.
2090    */
2091   protected final int t002;
2092   /**
2093    * Derivatives with respect to x and y.
2094    */
2095   protected final int t110;
2096   /**
2097    * Derivatives with respect to x and z.
2098    */
2099   protected final int t101;
2100   /**
2101    * Derivatives with respect to y and z.
2102    */
2103   protected final int t011;
2104   // l + m + n = 3 (10) 20
2105   /**
2106    * Third derivative with respect to x.
2107    */
2108   protected final int t300;
2109   /**
2110    * Third derivative with respect to y.
2111    */
2112   protected final int t030;
2113   /**
2114    * Third derivative with respect to z.
2115    */
2116   protected final int t003;
2117   /**
2118    * Derivatives with respect to x and y.
2119    */
2120   protected final int t210;
2121   /**
2122    * Derivatives with respect to x and z.
2123    */
2124   protected final int t201;
2125   /**
2126    * Derivatives with respect to x and y.
2127    */
2128   protected final int t120;
2129   /**
2130    * Derivatives with respect to y and z.
2131    */
2132   protected final int t021;
2133   /**
2134    * Derivatives with respect to x and z.
2135    */
2136   protected final int t102;
2137   /**
2138    * Derivatives with respect to y and z.
2139    */
2140   protected final int t012;
2141   /**
2142    * Derivatives with respect to x, y and z.
2143    */
2144   protected final int t111;
2145   // l + m + n = 4 (15) 35
2146   /**
2147    * Fourth derivative with respect to x.
2148    */
2149   protected final int t400;
2150   /**
2151    * Fourth derivative with respect to y.
2152    */
2153   protected final int t040;
2154   /**
2155    * Fourth derivative with respect to z.
2156    */
2157   protected final int t004;
2158   /**
2159    * Derivatives with respect to x and y.
2160    */
2161   protected final int t310;
2162   /**
2163    * Derivatives with respect to x and z.
2164    */
2165   protected final int t301;
2166   /**
2167    * Derivatives with respect to x and y.
2168    */
2169   protected final int t130;
2170   /**
2171    * Derivatives with respect to y and z.
2172    */
2173   protected final int t031;
2174   /**
2175    * Derivatives with respect to x and z.
2176    */
2177   protected final int t103;
2178   /**
2179    * Derivatives with respect to y and z.
2180    */
2181   protected final int t013;
2182   /**
2183    * Derivatives with respect to x and y.
2184    */
2185   protected final int t220;
2186   /**
2187    * Derivatives with respect to x and z.
2188    */
2189   protected final int t202;
2190   /**
2191    * Derivatives with respect to y and z.
2192    */
2193   protected final int t022;
2194   /**
2195    * Derivatives with respect to x, y and z.
2196    */
2197   protected final int t211;
2198   /**
2199    * Derivatives with respect to x, y and z.
2200    */
2201   protected final int t121;
2202   /**
2203    * Derivatives with respect to x, y and z.
2204    */
2205   protected final int t112;
2206   // l + m + n = 5 (21) 56
2207   /**
2208    * Fifth derivative with respect to x.
2209    */
2210   protected final int t500;
2211   /**
2212    * Fifth derivative with respect to y.
2213    */
2214   protected final int t050;
2215   /**
2216    * Fifth derivative with respect to z.
2217    */
2218   protected final int t005;
2219   /**
2220    * Derivatives with respect to x and y.
2221    */
2222   protected final int t410;
2223   /**
2224    * Derivatives with respect to x and z.
2225    */
2226   protected final int t401;
2227   /**
2228    * Derivatives with respect to x and y.
2229    */
2230   protected final int t140;
2231   /**
2232    * Derivatives with respect to y and z.
2233    */
2234   protected final int t041;
2235   /**
2236    * Derivatives with respect to x and z.
2237    */
2238   protected final int t104;
2239   /**
2240    * Derivatives with respect to y and z.
2241    */
2242   protected final int t014;
2243   /**
2244    * Derivatives with respect to x and y.
2245    */
2246   protected final int t320;
2247   /**
2248    * Derivatives with respect to x and z.
2249    */
2250   protected final int t302;
2251   /**
2252    * Derivatives with respect to x and y.
2253    */
2254   protected final int t230;
2255   /**
2256    * Derivatives with respect to y and z.
2257    */
2258   protected final int t032;
2259   /**
2260    * Derivatives with respect to x and z.
2261    */
2262   protected final int t203;
2263   /**
2264    * Derivatives with respect to y and z.
2265    */
2266   protected final int t023;
2267   /**
2268    * Derivatives with respect to x, y and z.
2269    */
2270   protected final int t311;
2271   /**
2272    * Derivatives with respect to x, y and z.
2273    */
2274   protected final int t131;
2275   /**
2276    * Derivatives with respect to x, y and z.
2277    */
2278   protected final int t113;
2279   /**
2280    * Derivatives with respect to x, y and z.
2281    */
2282   protected final int t221;
2283   /**
2284    * Derivatives with respect to x, y and z.
2285    */
2286   protected final int t212;
2287   /**
2288    * Derivatives with respect to x, y and z.
2289    */
2290   protected final int t122;
2291 
2292   // l + m + n = 6 (28) 84
2293   /**
2294    * Sixth derivative with respect to x.
2295    */
2296   protected final int t600;
2297   /**
2298    * Sixth derivative with respect to y.
2299    */
2300   protected final int t060;
2301   /**
2302    * Sixth derivative with respect to z.
2303    */
2304   protected final int t006;
2305   /**
2306    * Derivatives with respect to x and y.
2307    */
2308   protected final int t510;
2309   /**
2310    * Derivatives with respect to x and z.
2311    */
2312   protected final int t501;
2313   /**
2314    * Derivatives with respect to x and y.
2315    */
2316   protected final int t150;
2317   /**
2318    * Derivatives with respect to y and z.
2319    */
2320   protected final int t051;
2321   /**
2322    * Derivatives with respect to x and z.
2323    */
2324   protected final int t105;
2325   /**
2326    * Derivatives with respect to y and z.
2327    */
2328   protected final int t015;
2329   /**
2330    * Derivatives with respect to x and y.
2331    */
2332   protected final int t420;
2333   /**
2334    * Derivatives with respect to x and z.
2335    */
2336   protected final int t402;
2337   /**
2338    * Derivatives with respect to x and y.
2339    */
2340   protected final int t240;
2341   /**
2342    * Derivatives with respect to y and z.
2343    */
2344   protected final int t042;
2345   /**
2346    * Derivatives with respect to x and z.
2347    */
2348   protected final int t204;
2349   /**
2350    * Derivatives with respect to y and z.
2351    */
2352   protected final int t024;
2353   /**
2354    * Derivatives with respect to x, y and z.
2355    */
2356   protected final int t411;
2357   /**
2358    * Derivatives with respect to x, y and z.
2359    */
2360   protected final int t141;
2361   /**
2362    * Derivatives with respect to x, y and z.
2363    */
2364   protected final int t114;
2365   /**
2366    * Derivatives with respect to x and y.
2367    */
2368   protected final int t330;
2369   /**
2370    * Derivatives with respect to x and z.
2371    */
2372   protected final int t303;
2373   /**
2374    * Derivatives with respect to y and z.
2375    */
2376   protected final int t033;
2377   /**
2378    * Derivatives with respect to x, y and z.
2379    */
2380   protected final int t321;
2381   /**
2382    * Derivatives with respect to x, y and z.
2383    */
2384   protected final int t231;
2385   /**
2386    * Derivatives with respect to x, y and z.
2387    */
2388   protected final int t213;
2389   /**
2390    * Derivatives with respect to x, y and z.
2391    */
2392   protected final int t312;
2393   /**
2394    * Derivatives with respect to x, y and z.
2395    */
2396   protected final int t132;
2397   /**
2398    * Derivatives with respect to x, y and z.
2399    */
2400   protected final int t123;
2401   /**
2402    * Derivatives with respect to x, y and z.
2403    */
2404   protected final int t222;
2405 }