1 package ffx.numerics.multipole;
2
3 import java.util.Arrays;
4
5 import static java.lang.Math.abs;
6 import static org.apache.commons.math3.util.FastMath.exp;
7 import static org.apache.commons.math3.util.FastMath.pow;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 public class AmoebaPlusDampTensorGlobal extends CoulombTensorGlobal {
25
26 private double beta = 0.0;
27 private double alpha;
28 private double alpha2;
29 private static final double oneThird = 1.0 / 3.0;
30 private double[] ewaldSource;
31
32
33
34
35
36
37
38
39 public AmoebaPlusDampTensorGlobal(int order, double alpha1, double alpha2) {
40 super(order);
41 this.alpha = alpha1;
42 this.alpha2 = alpha2;
43 this.operator = abs(alpha - alpha2) < 1e-5 ?
44 Operator.AMOEBA_PLUS_SYM_DAMP_FIELD : Operator.AMOEBA_PLUS_DAMP_FIELD;
45 assert (order <= 3);
46 }
47
48
49
50
51
52
53
54
55
56 public AmoebaPlusDampTensorGlobal(int order, double alpha1, double alpha2, double ewaldA) {
57 this(order, alpha1, alpha2);
58 this.beta = ewaldA;
59 }
60
61
62
63
64
65
66
67 @Override
68 protected void source(double[] T000) {
69
70 super.source(T000);
71 double[] copy = Arrays.copyOf(T000, o1);
72
73 dampSource(alpha, R, T000);
74 if (beta > 1e-3) {
75 this.ewaldSource = new double[this.order + 1];
76 EwaldTensorGlobal.fillEwaldSource(this.order, beta,
77 EwaldTensorGlobal.initEwaldSource(this.order, beta, new double[o1]),
78 this.R, ewaldSource);
79
80 for (int i = 0; i < ewaldSource.length; i++) {
81 T000[i] += ewaldSource[i] - copy[i];
82 }
83 }
84 }
85
86
87
88
89
90
91
92
93 protected static void dampSource(double alpha, double R, double[] T000) {
94
95 double alphaR = alpha * R;
96 double alphaR2 = alphaR * alphaR;
97 double expAR = exp(-alphaR);
98
99 T000[0] *= 1 - expAR;
100 T000[1] *= 1 - (1 + alphaR) * expAR;
101 T000[2] *= 1 - (1.0 + alphaR + oneThird * alphaR2) * expAR;
102 T000[3] *= 1 - (1.0 + alphaR + .4 * alphaR2 + alphaR2 * alphaR / 15) * expAR;
103 }
104
105
106
107
108
109
110
111
112
113
114
115 public double coreInteraction(PolarizableMultipole mI, PolarizableMultipole mK) {
116
117 double energy = beta >= 1e-3 ? mK.Z * mI.Z * ewaldSource[0] : mK.Z * mI.Z / R;
118
119
120 multipoleIPotentialAtK(mI, 0);
121 energy += mK.Z * E000;
122 if (this.operator != Operator.AMOEBA_PLUS_SYM_DAMP_FIELD) {
123
124 double temp = this.alpha;
125 this.alpha = this.alpha2;
126 this.alpha2 = temp;
127 this.generateTensor();
128 temp = this.alpha;
129 this.alpha = this.alpha2;
130 this.alpha2 = temp;
131 }
132 multipoleKPotentialAtI(mK, 0);
133 energy += mI.Z * E000;
134
135 return energy;
136 }
137
138
139
140
141
142
143
144
145
146
147 public double coreInteractionAndGradient(PolarizableMultipole mI, PolarizableMultipole mK,
148 double[] Gi, double[] Gk) {
149
150 double energy = this.beta >= 1e-3 ? mK.Z * mI.Z * this.ewaldSource[0] : mK.Z * mI.Z / R;
151 double tensorElement = this.beta >= 1e-3 ? this.ewaldSource[1] : -pow(R, -3);
152 Gk[0] = mK.Z * mI.Z * x * tensorElement;
153 Gk[1] = mK.Z * mI.Z * y * tensorElement;
154 Gk[2] = mK.Z * mI.Z * z * tensorElement;
155
156
157 multipoleIPotentialAtK(mI, 1);
158 energy += mK.Z * E000;
159 Gk[0] += mK.Z * E100;
160 Gk[1] += mK.Z * E010;
161 Gk[2] += mK.Z * E001;
162 if (this.operator != Operator.AMOEBA_PLUS_SYM_DAMP_FIELD) {
163
164
165 double temp = this.alpha;
166 this.alpha = this.alpha2;
167 this.alpha2 = temp;
168 this.generateTensor();
169 temp = this.alpha;
170 this.alpha = this.alpha2;
171 this.alpha2 = temp;
172 }
173 multipoleKPotentialAtI(mK, 1);
174 energy += mI.Z * E000;
175
176 Gk[0] -= mI.Z * E100;
177 Gk[1] -= mI.Z * E010;
178 Gk[2] -= mI.Z * E001;
179
180 Gi[0] = -Gk[0];
181 Gi[1] = -Gk[1];
182 Gi[2] = -Gk[2];
183
184 return energy;
185 }
186
187 }