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