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 jdk.incubator.vector.DoubleVector;
41
42
43
44
45
46
47
48
49 public class GKTensorGlobalSIMD extends CoulombTensorGlobalSIMD {
50
51
52
53
54 protected final GKMultipoleOrder multipoleOrder;
55
56
57
58
59 private final double c;
60
61 private final GKSourceSIMD gkSource;
62
63 private final DoubleVector zero = DoubleVector.zero(DoubleVector.SPECIES_PREFERRED);
64
65
66
67
68
69
70
71
72
73
74 public GKTensorGlobalSIMD(GKMultipoleOrder multipoleOrder, int order, GKSourceSIMD gkSource, double Eh, double Es) {
75 super(order);
76 this.multipoleOrder = multipoleOrder;
77 this.gkSource = gkSource;
78
79
80 c = GKSource.cn(multipoleOrder.getOrder(), Eh, Es);
81 }
82
83
84
85
86
87
88
89
90 @Override
91 public DoubleVector multipoleEnergy(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
92 return switch (multipoleOrder) {
93 default -> {
94 chargeIPotentialAtK(mI, 2);
95 DoubleVector eK = multipoleEnergy(mK);
96 chargeKPotentialAtI(mK, 2);
97 DoubleVector eI = multipoleEnergy(mI);
98 yield eK.add(eI).mul(c * 0.5);
99 }
100 case DIPOLE -> {
101 dipoleIPotentialAtK(mI.dx, mI.dy, mI.dz, 2);
102 DoubleVector eK = multipoleEnergy(mK);
103 dipoleKPotentialAtI(mK.dx, mK.dy, mK.dz, 2);
104 DoubleVector eI = multipoleEnergy(mI);
105 yield eK.add(eI).mul(c * 0.5);
106 }
107 case QUADRUPOLE -> {
108 quadrupoleIPotentialAtK(mI, 2);
109 DoubleVector eK = multipoleEnergy(mK);
110 quadrupoleKPotentialAtI(mK, 2);
111 DoubleVector eI = multipoleEnergy(mI);
112 yield eK.add(eI).mul(c * 0.5);
113 }
114 };
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128 @Override
129 public DoubleVector multipoleEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
130 DoubleVector[] Gi, DoubleVector[] Gk,
131 DoubleVector[] Ti, DoubleVector[] Tk) {
132 return switch (multipoleOrder) {
133 default -> monopoleEnergyAndGradient(mI, mK, Gi, Gk, Ti, Tk);
134 case DIPOLE -> dipoleEnergyAndGradient(mI, mK, Gi, Gk, Ti, Tk);
135 case QUADRUPOLE -> quadrupoleEnergyAndGradient(mI, mK, Gi, Gk, Ti, Tk);
136 };
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150 protected DoubleVector monopoleEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
151 DoubleVector[] Gi, DoubleVector[] Gk,
152 DoubleVector[] Ti, DoubleVector[] Tk) {
153
154
155 chargeIPotentialAtK(mI, 3);
156 DoubleVector eK = multipoleEnergy(mK);
157 multipoleGradient(mK, Gk);
158 multipoleTorque(mK, Tk);
159
160
161 chargeKPotentialAtI(mK, 3);
162 DoubleVector eI = multipoleEnergy(mI);
163 multipoleGradient(mI, Gi);
164 multipoleTorque(mI, Ti);
165
166 double scale = c * 0.5;
167 Gi[0] = Gi[0].sub(Gk[0]).mul(scale);
168 Gi[1] = Gi[1].sub(Gk[1]).mul(scale);
169 Gi[2] = Gi[2].sub(Gk[2]).mul(scale);
170 Gk[0] = Gi[0].neg();
171 Gk[1] = Gi[1].neg();
172 Gk[2] = Gi[2].neg();
173
174 Ti[0] = Ti[0].mul(scale);
175 Ti[1] = Ti[1].mul(scale);
176 Ti[2] = Ti[2].mul(scale);
177 Tk[0] = Tk[0].mul(scale);
178 Tk[1] = Tk[1].mul(scale);
179 Tk[2] = Tk[2].mul(scale);
180
181 return eK.add(eI).mul(scale);
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195 protected DoubleVector dipoleEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
196 DoubleVector[] Gi, DoubleVector[] Gk,
197 DoubleVector[] Ti, DoubleVector[] Tk) {
198
199
200 dipoleIPotentialAtK(mI.dx, mI.dy, mI.dz, 3);
201 DoubleVector eK = multipoleEnergy(mK);
202 multipoleGradient(mK, Gk);
203 multipoleTorque(mK, Tk);
204
205
206
207 multipoleKPotentialAtI(mK, 1);
208 dipoleTorque(mI, Ti);
209
210
211 dipoleKPotentialAtI(mK.dx, mK.dy, mK.dz, 3);
212 DoubleVector eI = multipoleEnergy(mI);
213 multipoleGradient(mI, Gi);
214 multipoleTorque(mI, Ti);
215
216
217
218 multipoleIPotentialAtK(mI, 1);
219 dipoleTorque(mK, Tk);
220
221 double scale = c * 0.5;
222 Gi[0] = Gi[0].sub(Gk[0]).mul(scale);
223 Gi[1] = Gi[1].sub(Gk[1]).mul(scale);
224 Gi[2] = Gi[2].sub(Gk[2]).mul(scale);
225 Gk[0] = Gi[0].neg();
226 Gk[1] = Gi[1].neg();
227 Gk[2] = Gi[2].neg();
228
229 Ti[0] = Ti[0].mul(scale);
230 Ti[1] = Ti[1].mul(scale);
231 Ti[2] = Ti[2].mul(scale);
232 Tk[0] = Tk[0].mul(scale);
233 Tk[1] = Tk[1].mul(scale);
234 Tk[2] = Tk[2].mul(scale);
235
236 return eK.add(eI).mul(scale);
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250 protected DoubleVector quadrupoleEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
251 DoubleVector[] Gi, DoubleVector[] Gk,
252 DoubleVector[] Ti, DoubleVector[] Tk) {
253
254
255 quadrupoleIPotentialAtK(mI, 3);
256 DoubleVector eK = multipoleEnergy(mK);
257 multipoleGradient(mK, Gk);
258 multipoleTorque(mK, Tk);
259
260
261 multipoleKPotentialAtI(mK, 2);
262 quadrupoleTorque(mI, Ti);
263
264
265 quadrupoleKPotentialAtI(mK, 3);
266 DoubleVector eI = multipoleEnergy(mI);
267 multipoleGradient(mI, Gi);
268 multipoleTorque(mI, Ti);
269
270
271 multipoleIPotentialAtK(mI, 2);
272 quadrupoleTorque(mK, Tk);
273
274 double scale = c * 0.5;
275 Gi[0] = Gi[0].sub(Gk[0]).mul(scale);
276 Gi[1] = Gi[1].sub(Gk[1]).mul(scale);
277 Gi[2] = Gi[2].sub(Gk[2]).mul(scale);
278 Gk[0] = Gi[0].neg();
279 Gk[1] = Gi[1].neg();
280 Gk[2] = Gi[2].neg();
281
282 Ti[0] = Ti[0].mul(scale);
283 Ti[1] = Ti[1].mul(scale);
284 Ti[2] = Ti[2].mul(scale);
285 Tk[0] = Tk[0].mul(scale);
286 Tk[1] = Tk[1].mul(scale);
287 Tk[2] = Tk[2].mul(scale);
288
289 return eK.add(eI).mul(scale);
290 }
291
292
293
294
295
296
297
298
299 public DoubleVector multipoleEnergyBornGrad(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
300 return multipoleEnergy(mI, mK);
301 }
302
303
304
305
306
307
308
309
310
311
312 public DoubleVector polarizationEnergy(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK, DoubleVector scaleEnergy) {
313 return polarizationEnergy(mI, mK);
314 }
315
316
317
318
319
320
321
322
323 public DoubleVector polarizationEnergy(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
324 return switch (multipoleOrder) {
325 default -> {
326
327 chargeIPotentialAtK(mI, 1);
328
329 DoubleVector eK = polarizationEnergy(mK);
330
331 chargeKPotentialAtI(mK, 1);
332
333 DoubleVector eI = polarizationEnergy(mI);
334 yield eK.add(eI).mul(c * 0.5);
335 }
336 case DIPOLE -> {
337
338 dipoleIPotentialAtK(mI.dx, mI.dy, mI.dz, 1);
339
340 DoubleVector eK = polarizationEnergy(mK);
341
342 dipoleIPotentialAtK(mI.ux, mI.uy, mI.uz, 2);
343
344 eK = multipoleEnergy(mK).mul(0.5).add(eK);
345
346 dipoleKPotentialAtI(mK.dx, mK.dy, mK.dz, 1);
347
348 DoubleVector eI = polarizationEnergy(mI);
349
350 dipoleKPotentialAtI(mK.ux, mK.uy, mK.uz, 2);
351
352 eI = multipoleEnergy(mI).mul(0.5).add(eI);
353 yield eK.add(eI).mul(c * 0.5);
354 }
355 case QUADRUPOLE -> {
356
357 quadrupoleIPotentialAtK(mI, 1);
358
359 DoubleVector eK = polarizationEnergy(mK);
360
361 quadrupoleKPotentialAtI(mK, 1);
362
363 DoubleVector eI = polarizationEnergy(mI);
364 yield eK.add(eI).mul(c * 0.5);
365 }
366 };
367 }
368
369
370
371
372
373
374
375
376 public DoubleVector polarizationEnergyBorn(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
377 return switch (multipoleOrder) {
378 default -> {
379
380 chargeIPotentialAtK(mI, 1);
381
382 DoubleVector eK = polarizationEnergyS(mK);
383
384 chargeKPotentialAtI(mK, 1);
385
386 DoubleVector eI = polarizationEnergyS(mI);
387 yield eK.add(eI).mul(c * 0.5);
388 }
389 case DIPOLE -> {
390
391 dipoleIPotentialAtK(mI.dx, mI.dy, mI.dz, 1);
392
393 DoubleVector eK = polarizationEnergyS(mK);
394
395 dipoleIPotentialAtK(mI.sx, mI.sy, mI.sz, 2);
396
397 eK = multipoleEnergy(mK).mul(0.5).add(eK);
398
399 dipoleKPotentialAtI(mK.dx, mK.dy, mK.dz, 1);
400
401 DoubleVector eI = polarizationEnergyS(mI);
402
403 dipoleKPotentialAtI(mK.sx, mK.sy, mK.sz, 2);
404
405 eI = multipoleEnergy(mI).mul(0.5).add(eI);
406 yield eK.add(eI).mul(c * 0.5);
407 }
408 case QUADRUPOLE -> {
409
410 quadrupoleIPotentialAtK(mI, 1);
411
412 DoubleVector eK = polarizationEnergyS(mK);
413
414 quadrupoleKPotentialAtI(mK, 1);
415
416 DoubleVector eI = polarizationEnergyS(mI);
417 yield eK.add(eI).mul(c * 0.5);
418 }
419 };
420 }
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437 @Override
438 public DoubleVector polarizationEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
439 DoubleVector inductionMask, DoubleVector energyMask, DoubleVector mutualMask,
440 DoubleVector[] Gi, DoubleVector[] Ti, DoubleVector[] Tk) {
441 return switch (multipoleOrder) {
442 default -> monopolePolarizationEnergyAndGradient(mI, mK, Gi);
443 case DIPOLE -> dipolePolarizationEnergyAndGradient(mI, mK, mutualMask, Gi, Ti, Tk);
444 case QUADRUPOLE -> quadrupolePolarizationEnergyAndGradient(mI, mK, Gi, Ti, Tk);
445 };
446 }
447
448
449
450
451
452
453
454
455
456 public DoubleVector monopolePolarizationEnergyAndGradient(PolarizableMultipoleSIMD mI,
457 PolarizableMultipoleSIMD mK, DoubleVector[] Gi) {
458
459 chargeIPotentialAtK(mI, 2);
460
461 DoubleVector eK = polarizationEnergy(mK);
462
463 Gi[0] = mK.sx.mul(E200).add(mK.sy.mul(E110)).add(mK.sz.mul(E101)).neg();
464 Gi[1] = mK.sx.mul(E110).add(mK.sy.mul(E020)).add(mK.sz.mul(E011)).neg();
465 Gi[2] = mK.sx.mul(E101).add(mK.sy.mul(E011)).add(mK.sz.mul(E002)).neg();
466
467
468 chargeKPotentialAtI(mK, 2);
469
470 DoubleVector eI = polarizationEnergy(mI);
471
472 Gi[0] = Gi[0].add(mI.sx.mul(E200)).add(mI.sy.mul(E110)).add(mI.sz.mul(E101));
473 Gi[1] = Gi[1].add(mI.sx.mul(E110)).add(mI.sy.mul(E020)).add(mI.sz.mul(E011));
474 Gi[2] = Gi[2].add(mI.sx.mul(E101)).add(mI.sy.mul(E011)).add(mI.sz.mul(E002));
475
476 double scale = c * 0.5;
477 Gi[0] = Gi[0].mul(scale);
478 Gi[1] = Gi[1].mul(scale);
479 Gi[2] = Gi[2].mul(scale);
480
481
482 return eI.add(eK).mul(scale);
483 }
484
485
486
487
488
489
490
491
492
493
494
495
496 public DoubleVector dipolePolarizationEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
497 DoubleVector mutualMask, DoubleVector[] Gi,
498 DoubleVector[] Ti, DoubleVector[] Tk) {
499
500
501 dipoleIPotentialAtK(mI.dx, mI.dy, mI.dz, 2);
502
503 DoubleVector eK = polarizationEnergy(mK);
504
505 Gi[0] = mK.sx.mul(E200).add(mK.sy.mul(E110)).add(mK.sz.mul(E101)).neg();
506 Gi[1] = mK.sx.mul(E110).add(mK.sy.mul(E020)).add(mK.sz.mul(E011)).neg();
507 Gi[2] = mK.sx.mul(E101).add(mK.sy.mul(E011)).add(mK.sz.mul(E002)).neg();
508
509
510 dipoleIPotentialAtK(mI.sx, mI.sy, mI.sz, 2);
511 dipoleTorque(mK, Tk);
512
513
514 dipoleIPotentialAtK(mI.ux, mI.uy, mI.uz, 3);
515
516 eK = eK.add(multipoleEnergy(mK).mul(0.5));
517
518 DoubleVector[] G = new DoubleVector[3];
519 multipoleGradient(mK, G);
520 Gi[0] = Gi[0].sub(G[0]);
521 Gi[1] = Gi[1].sub(G[1]);
522 Gi[2] = Gi[2].sub(G[2]);
523 multipoleTorque(mK, Tk);
524
525
526 dipoleKPotentialAtI(mK.dx, mK.dy, mK.dz, 2);
527
528 DoubleVector eI = polarizationEnergy(mI);
529
530 Gi[0] = Gi[0].add(mI.sx.mul(E200)).add(mI.sy.mul(E110)).add(mI.sz.mul(E101));
531 Gi[1] = Gi[1].add(mI.sx.mul(E110)).add(mI.sy.mul(E020)).add(mI.sz.mul(E011));
532 Gi[2] = Gi[2].add(mI.sx.mul(E101)).add(mI.sy.mul(E011)).add(mI.sz.mul(E002));
533
534
535 dipoleKPotentialAtI(mK.sx, mK.sy, mK.sz, 2);
536 dipoleTorque(mI, Ti);
537
538
539 dipoleKPotentialAtI(mK.ux, mK.uy, mK.uz, 3);
540
541 eI = eI.add(multipoleEnergy(mI).mul(0.5));
542
543 multipoleGradient(mI, G);
544 Gi[0] = Gi[0].add(G[0]);
545 Gi[1] = Gi[1].add(G[1]);
546 Gi[2] = Gi[2].add(G[2]);
547 multipoleTorque(mI, Ti);
548
549
550
551 if (!mutualMask.eq(zero).allTrue()) {
552
553 dipoleIPotentialAtK(mI.ux, mI.uy, mI.uz, 2);
554 Gi[0] = Gi[0].sub((mK.px.mul(E200).add(mK.py.mul(E110)).add(mK.pz.mul(E101)).mul(mutualMask)));
555 Gi[1] = Gi[1].sub((mK.px.mul(E110).add(mK.py.mul(E020)).add(mK.pz.mul(E011)).mul(mutualMask)));
556 Gi[2] = Gi[2].sub((mK.px.mul(E101).add(mK.py.mul(E011)).add(mK.pz.mul(E002)).mul(mutualMask)));
557
558
559 dipoleKPotentialAtI(mK.ux, mK.uy, mK.uz, 2);
560 Gi[0] = Gi[0].sub((mI.px.mul(E200).add(mI.py.mul(E110)).add(mI.pz.mul(E101)).mul(mutualMask)));
561 Gi[1] = Gi[1].sub((mI.px.mul(E110).add(mI.py.mul(E020)).add(mI.pz.mul(E011)).mul(mutualMask)));
562 Gi[2] = Gi[2].sub((mI.px.mul(E101).add(mI.py.mul(E011)).add(mI.pz.mul(E002)).mul(mutualMask)));
563 }
564
565
566 double scale = c * 0.5;
567 DoubleVector energy = eI.add(eK).mul(scale);
568 Gi[0] = Gi[0].mul(scale);
569 Gi[1] = Gi[1].mul(scale);
570 Gi[2] = Gi[2].mul(scale);
571 Ti[0] = Ti[0].mul(scale);
572 Ti[1] = Ti[1].mul(scale);
573 Ti[2] = Ti[2].mul(scale);
574 Tk[0] = Tk[0].mul(scale);
575 Tk[1] = Tk[1].mul(scale);
576 Tk[2] = Tk[2].mul(scale);
577 return energy;
578 }
579
580
581
582
583
584
585
586
587
588
589
590 public DoubleVector quadrupolePolarizationEnergyAndGradient(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK,
591 DoubleVector[] Gi, DoubleVector[] Ti, DoubleVector[] Tk) {
592
593
594 quadrupoleIPotentialAtK(mI, 2);
595
596 DoubleVector eK = polarizationEnergy(mK);
597
598 Gi[0] = (mK.sx.mul(E200).add(mK.sy.mul(E110)).add(mK.sz.mul(E101))).neg();
599 Gi[1] = (mK.sx.mul(E110).add(mK.sy.mul(E020)).add(mK.sz.mul(E011))).neg();
600 Gi[2] = (mK.sx.mul(E101).add(mK.sy.mul(E011)).add(mK.sz.mul(E002))).neg();
601
602
603 quadrupoleKPotentialAtI(mK, 2);
604
605 DoubleVector eI = polarizationEnergy(mI);
606
607 Gi[0] = Gi[0].add(mI.sx.mul(E200)).add(mI.sy.mul(E110)).add(mI.sz.mul(E101));
608 Gi[1] = Gi[1].add(mI.sx.mul(E110)).add(mI.sy.mul(E020)).add(mI.sz.mul(E011));
609 Gi[2] = Gi[2].add(mI.sx.mul(E101)).add(mI.sy.mul(E011)).add(mI.sz.mul(E002));
610
611 double scale = c * 0.5;
612 Gi[0] = Gi[0].mul(scale);
613 Gi[1] = Gi[1].mul(scale);
614 Gi[2] = Gi[2].mul(scale);
615
616
617 dipoleIPotentialAtK(mI.sx.mul(scale), mI.sy.mul(scale), mI.sz.mul(scale), 2);
618 quadrupoleTorque(mK, Tk);
619
620
621 dipoleKPotentialAtI(mK.sx.mul(scale), mK.sy.mul(scale), mK.sz.mul(scale), 2);
622 quadrupoleTorque(mI, Ti);
623
624
625 return eI.add(eK).mul(scale);
626 }
627
628
629
630
631
632
633
634
635 public DoubleVector polarizationEnergyBornGrad(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
636 return polarizationEnergyBorn(mI, mK).mul(2.0);
637 }
638
639
640
641
642
643
644
645
646 public DoubleVector mutualPolarizationEnergyBornGrad(PolarizableMultipoleSIMD mI, PolarizableMultipoleSIMD mK) {
647 DoubleVector db = zero;
648 if (multipoleOrder == GKMultipoleOrder.DIPOLE) {
649
650 dipoleIPotentialAtK(mI.ux, mI.uy, mI.uz, 2);
651 db = mK.px.mul(E100).add(mK.py.mul(E010)).add(mK.pz.mul(E001)).mul(0.5);
652
653
654
655 dipoleKPotentialAtI(mK.ux, mK.uy, mK.uz, 2);
656 db = db.add(mI.px.mul(E100).add(mI.py.mul(E010)).add(mI.pz.mul(E001)).mul(0.5));
657
658 }
659 return db.mul(c);
660 }
661
662
663
664
665 @Override
666 protected void source(DoubleVector[] work) {
667 gkSource.source(work, multipoleOrder);
668 }
669
670 }