1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
56
57
58
59
60
61
62
63 public abstract class MultipoleTensor {
64
65
66
67
68 private static final Logger logger = Logger.getLogger(MultipoleTensor.class.getName());
69
70
71
72
73 protected final int order;
74
75
76
77
78 protected final int o1;
79
80
81
82
83 protected final int il;
84
85
86
87
88 protected final int im;
89
90
91
92
93 protected final int in;
94
95
96
97
98 protected final int size;
99
100
101
102
103 protected Operator operator;
104
105
106
107
108 protected final double[] coulombSource;
109
110
111
112
113
114
115 protected final double[] work;
116
117
118
119
120 protected final double[] T000;
121
122
123
124
125 protected final CoordinateSystem coordinates;
126
127
128
129
130 protected double R;
131
132
133
134
135 protected double r2;
136
137
138
139
140 protected double x;
141
142
143
144
145 protected double y;
146
147
148
149
150 protected double z;
151
152 private double dEdZ = 0.0;
153 private double d2EdZ2 = 0.0;
154
155
156 double E000;
157
158 double E100;
159 double E010;
160 double E001;
161
162 double E200;
163 double E020;
164 double E002;
165 double E110;
166 double E101;
167 double E011;
168
169 double E300;
170 double E030;
171 double E003;
172 double E210;
173 double E201;
174 double E120;
175 double E021;
176 double E102;
177 double E012;
178 double E111;
179
180
181 double R000;
182
183 double R100;
184 double R010;
185 double R001;
186
187 double R200;
188 double R020;
189 double R002;
190 double R110;
191 double R101;
192 double R011;
193
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
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
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
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
274
275
276
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
292 coulombSource = new double[o1];
293 for (short n = 0; n <= order; n++) {
294
295
296
297
298
299 coulombSource[n] = pow(-1, n) * doubleFactorial(2 * n - 1);
300 }
301
302 T000 = new double[order + 1];
303
304 t000 = MultipoleUtilities.ti(0, 0, 0, order);
305
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
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
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
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
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
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
398
399
400
401 public double getd2EdZ2() {
402 return d2EdZ2;
403 }
404
405
406
407
408
409
410 public double getdEdZ() {
411 return dEdZ;
412 }
413
414
415
416
417
418
419 public void log(double[] tensor) {
420 log(this.operator, this.order, tensor);
421 }
422
423
424
425
426
427
428
429
430 public double multipoleEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
431 multipoleIPotentialAtK(mI, 2);
432 return multipoleEnergy(mK);
433 }
434
435
436
437
438
439
440
441
442
443
444
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
456 multipoleTorque(mK, Tk);
457 multipoleKPotentialAtI(mK, 2);
458 multipoleTorque(mI, Ti);
459
460
461
462
463
464
465
466 return energy;
467 }
468
469
470
471
472
473
474
475
476
477 public double polarizationEnergy(PolarizableMultipole mI, PolarizableMultipole mK,
478 double scaleEnergy) {
479
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
486 multipoleIPotentialAtK(mI, 1);
487
488 double eK = polarizationEnergy(mK);
489
490 multipoleKPotentialAtI(mK, 1);
491
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
504
505
506
507
508
509
510
511
512
513
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
525 mI.applyMasks(inductionMask, energyMask);
526 mK.applyMasks(inductionMask, energyMask);
527
528
529 multipoleIPotentialAtK(mI, 2);
530
531
532 double eK = polarizationEnergy(mK);
533
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
539 multipoleKPotentialAtI(mK, 2);
540
541 double eI = polarizationEnergy(mI);
542
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
548 double energy = energyMask * (eI + eK);
549
550
551
552 if (mutualMask != 0.0) {
553
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
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
567 dipoleIPotentialAtK(mI.sx, mI.sy, mI.sz, 2);
568 multipoleTorque(mK, Tk);
569
570
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
584
585
586
587
588
589
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
597
598 double eK = -(mK.ux * E100 + mK.uy * E010 + mK.uz * E001);
599
600
601 multipoleKPotentialAtI(mK, 2);
602
603 double eI = -(mI.ux * E100 + mI.uy * E010 + mI.uz * E001);
604
605 double inducedEnergy = -0.5 * scaleEnergy * (eI + eK);
606
607
608 energyComponents[0] = permanentEnergy;
609 energyComponents[1] = inducedEnergy;
610
611 return permanentEnergy + inducedEnergy;
612 }
613
614
615
616
617
618
619 public final void setR(double[] r) {
620 setR(r[0], r[1], r[2]);
621 }
622
623
624
625
626
627
628
629
630 public abstract void setR(double dx, double dy, double dz);
631
632
633
634
635
636
637 public final void generateTensor(double[] r) {
638 setR(r);
639 generateTensor();
640 }
641
642
643
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
662
663
664
665 protected abstract void source(double[] T000);
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692 protected final int ti(int dx, int dy, int dz) {
693 return MultipoleUtilities.ti(dx, dy, dz, order);
694 }
695
696
697
698
699
700
701
702
703
704
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
723
724
725
726
727
728
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
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761 protected abstract String codeTensorRecursion(final double[] r, final double[] tensor);
762
763
764
765
766
767
768
769
770
771
772
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
845
846
847
848
849
850
851
852
853
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
936
937
938
939
940
941
942
943
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
1015
1016
1017
1018
1019
1020
1021
1022
1023
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
1106
1107
1108
1109
1110
1111
1112
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
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
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
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
1202
1203
1204
1205
1206
1207
1208
1209
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
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
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
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
1308
1309
1310
1311
1312
1313
1314
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
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
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
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
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413 protected void codePotentialMultipoleKSIMD(PolarizableMultipole mK, double[] T, int l, int m, int n, StringBuilder sb) {
1414 String to = "e";
1415
1416
1417 sb.append("\n// Order 0\n");
1418
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
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
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
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
1513
1514
1515
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
1533
1534
1535
1536
1537 protected final void multipoleGradient(PolarizableMultipole m, double[] g) {
1538
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
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
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
1580
1581
1582
1583
1584 protected final void multipoleTorque(PolarizableMultipole m, double[] torque) {
1585
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
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
1599 torque[0] -= (dx + qx);
1600 torque[1] -= (dy + qy);
1601 torque[2] -= (dz + qz);
1602 }
1603
1604
1605
1606
1607
1608
1609
1610 protected final void dipoleTorque(PolarizableMultipole m, double[] torque) {
1611
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
1617 torque[0] -= dx;
1618 torque[1] -= dy;
1619 torque[2] -= dz;
1620 }
1621
1622
1623
1624
1625
1626
1627
1628 protected final void quadrupoleTorque(PolarizableMultipole m, double[] torque) {
1629
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
1638 torque[0] -= qx;
1639 torque[1] -= qy;
1640 torque[2] -= qz;
1641 }
1642
1643
1644
1645
1646
1647
1648
1649 protected final double polarizationEnergy(PolarizableMultipole m) {
1650
1651
1652 return 0.5 * (m.ux * E100 + m.uy * E010 + m.uz * E001);
1653 }
1654
1655
1656
1657
1658
1659
1660
1661 protected final double polarizationEnergyS(PolarizableMultipole m) {
1662
1663
1664 return 0.5 * (m.sx * E100 + m.sy * E010 + m.sz * E001);
1665 }
1666
1667
1668
1669
1670
1671
1672 @SuppressWarnings("fallthrough")
1673 protected final void getTensor(double[] T) {
1674 switch (order) {
1675 default:
1676 case 5:
1677
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
1700 case 4:
1701
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
1718 case 3:
1719
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
1731 case 2:
1732
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
1740 case 1:
1741
1742 T[t100] = R100;
1743 T[t010] = R010;
1744 T[t001] = R001;
1745
1746 case 0:
1747
1748 T[t000] = R000;
1749 }
1750 }
1751
1752
1753
1754
1755
1756
1757 @SuppressWarnings("fallthrough")
1758 protected final void setTensor(double[] T) {
1759 switch (order) {
1760 case 5:
1761
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
1784 case 4:
1785
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
1802 case 3:
1803
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
1815 case 2:
1816
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
1824 case 1:
1825
1826 R100 = T[t100];
1827 R010 = T[t010];
1828 R001 = T[t001];
1829
1830 case 0:
1831
1832 R000 = T[t000];
1833 }
1834 }
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844 protected abstract void noStorageRecursion(double[] tensor);
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855 protected abstract void noStorageRecursion(double[] r, double[] tensor);
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
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
1879
1880
1881
1882
1883 protected abstract void recursion(final double[] tensor);
1884
1885
1886
1887
1888
1889
1890
1891
1892 protected abstract void recursion(final double[] r, final double[] tensor);
1893
1894
1895
1896
1897 protected abstract void order1();
1898
1899
1900
1901
1902 protected abstract void order2();
1903
1904
1905
1906
1907 protected abstract void order3();
1908
1909
1910
1911
1912 protected abstract void order4();
1913
1914
1915
1916
1917
1918 protected abstract void order5();
1919
1920
1921
1922
1923
1924 protected abstract void order6();
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935 protected abstract void multipoleIPotentialAtK(PolarizableMultipole mI, int order);
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946 protected abstract void chargeIPotentialAtK(PolarizableMultipole mI, int order);
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956 protected abstract void dipoleIPotentialAtK(double uxi, double uyi, double uzi, int order);
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967 protected abstract void quadrupoleIPotentialAtK(PolarizableMultipole mI, int order);
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978 protected abstract void multipoleKPotentialAtI(PolarizableMultipole mK, int order);
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989 protected abstract void chargeKPotentialAtI(PolarizableMultipole mK, int order);
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999 protected abstract void dipoleKPotentialAtI(double uxk, double uyk, double uzk, int order);
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010 protected abstract void quadrupoleKPotentialAtI(PolarizableMultipole mK, int order);
2011
2012
2013
2014
2015
2016
2017
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
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
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
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
2062
2063
2064
2065 protected final int t000;
2066
2067
2068
2069
2070 protected final int t100;
2071
2072
2073
2074 protected final int t010;
2075
2076
2077
2078 protected final int t001;
2079
2080
2081
2082
2083 protected final int t200;
2084
2085
2086
2087 protected final int t020;
2088
2089
2090
2091 protected final int t002;
2092
2093
2094
2095 protected final int t110;
2096
2097
2098
2099 protected final int t101;
2100
2101
2102
2103 protected final int t011;
2104
2105
2106
2107
2108 protected final int t300;
2109
2110
2111
2112 protected final int t030;
2113
2114
2115
2116 protected final int t003;
2117
2118
2119
2120 protected final int t210;
2121
2122
2123
2124 protected final int t201;
2125
2126
2127
2128 protected final int t120;
2129
2130
2131
2132 protected final int t021;
2133
2134
2135
2136 protected final int t102;
2137
2138
2139
2140 protected final int t012;
2141
2142
2143
2144 protected final int t111;
2145
2146
2147
2148
2149 protected final int t400;
2150
2151
2152
2153 protected final int t040;
2154
2155
2156
2157 protected final int t004;
2158
2159
2160
2161 protected final int t310;
2162
2163
2164
2165 protected final int t301;
2166
2167
2168
2169 protected final int t130;
2170
2171
2172
2173 protected final int t031;
2174
2175
2176
2177 protected final int t103;
2178
2179
2180
2181 protected final int t013;
2182
2183
2184
2185 protected final int t220;
2186
2187
2188
2189 protected final int t202;
2190
2191
2192
2193 protected final int t022;
2194
2195
2196
2197 protected final int t211;
2198
2199
2200
2201 protected final int t121;
2202
2203
2204
2205 protected final int t112;
2206
2207
2208
2209
2210 protected final int t500;
2211
2212
2213
2214 protected final int t050;
2215
2216
2217
2218 protected final int t005;
2219
2220
2221
2222 protected final int t410;
2223
2224
2225
2226 protected final int t401;
2227
2228
2229
2230 protected final int t140;
2231
2232
2233
2234 protected final int t041;
2235
2236
2237
2238 protected final int t104;
2239
2240
2241
2242 protected final int t014;
2243
2244
2245
2246 protected final int t320;
2247
2248
2249
2250 protected final int t302;
2251
2252
2253
2254 protected final int t230;
2255
2256
2257
2258 protected final int t032;
2259
2260
2261
2262 protected final int t203;
2263
2264
2265
2266 protected final int t023;
2267
2268
2269
2270 protected final int t311;
2271
2272
2273
2274 protected final int t131;
2275
2276
2277
2278 protected final int t113;
2279
2280
2281
2282 protected final int t221;
2283
2284
2285
2286 protected final int t212;
2287
2288
2289
2290 protected final int t122;
2291
2292
2293
2294
2295
2296 protected final int t600;
2297
2298
2299
2300 protected final int t060;
2301
2302
2303
2304 protected final int t006;
2305
2306
2307
2308 protected final int t510;
2309
2310
2311
2312 protected final int t501;
2313
2314
2315
2316 protected final int t150;
2317
2318
2319
2320 protected final int t051;
2321
2322
2323
2324 protected final int t105;
2325
2326
2327
2328 protected final int t015;
2329
2330
2331
2332 protected final int t420;
2333
2334
2335
2336 protected final int t402;
2337
2338
2339
2340 protected final int t240;
2341
2342
2343
2344 protected final int t042;
2345
2346
2347
2348 protected final int t204;
2349
2350
2351
2352 protected final int t024;
2353
2354
2355
2356 protected final int t411;
2357
2358
2359
2360 protected final int t141;
2361
2362
2363
2364 protected final int t114;
2365
2366
2367
2368 protected final int t330;
2369
2370
2371
2372 protected final int t303;
2373
2374
2375
2376 protected final int t033;
2377
2378
2379
2380 protected final int t321;
2381
2382
2383
2384 protected final int t231;
2385
2386
2387
2388 protected final int t213;
2389
2390
2391
2392 protected final int t312;
2393
2394
2395
2396 protected final int t132;
2397
2398
2399
2400 protected final int t123;
2401
2402
2403
2404 protected final int t222;
2405 }