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.potential.nonbonded.implicit;
39
40 import edu.rit.pj.IntegerForLoop;
41 import edu.rit.pj.ParallelRegion;
42 import ffx.crystal.Crystal;
43 import ffx.crystal.SymOp;
44 import ffx.numerics.atomic.AtomicDoubleArray3D;
45 import ffx.potential.bonded.Atom;
46
47 import java.util.List;
48 import java.util.logging.Level;
49 import java.util.logging.Logger;
50
51 import static ffx.numerics.multipole.GKSource.cn;
52 import static org.apache.commons.math3.util.FastMath.exp;
53 import static org.apache.commons.math3.util.FastMath.sqrt;
54
55
56
57
58
59
60
61 public class InducedGKFieldRegion extends ParallelRegion {
62
63 private static final Logger logger = Logger.getLogger(InducedGKFieldRegion.class.getName());
64
65 private final double gkc;
66
67 private final double fd;
68
69 private final double fq;
70
71 private final InducedGKFieldLoop[] inducedGKFieldLoop;
72
73 protected Atom[] atoms;
74
75 private Crystal crystal;
76
77 private double[][][] inducedDipole;
78
79 private double[][][] inducedDipoleCR;
80
81 private double[][][] sXYZ;
82
83 private int[][][] neighborLists;
84
85 private boolean[] use = null;
86
87 private double cut2;
88
89 private double[] born;
90
91 private AtomicDoubleArray3D sharedGKField;
92
93 private AtomicDoubleArray3D sharedGKFieldCR;
94
95
96
97
98
99
100
101
102
103 public InducedGKFieldRegion(int nt, double soluteDieletric, double solventDieletric, double gkc) {
104
105 fd = cn(1, soluteDieletric, solventDieletric);
106 fq = cn(2, soluteDieletric, solventDieletric);
107 this.gkc = gkc;
108 inducedGKFieldLoop = new InducedGKFieldLoop[nt];
109 for (int i = 0; i < nt; i++) {
110 inducedGKFieldLoop[i] = new InducedGKFieldLoop();
111 }
112 }
113
114 public void init(
115 Atom[] atoms,
116 double[][][] inducedDipole,
117 double[][][] inducedDipoleCR,
118 Crystal crystal,
119 double[][][] sXYZ,
120 int[][][] neighborLists,
121 boolean[] use,
122 double cut2,
123 double[] born,
124 AtomicDoubleArray3D sharedGKField,
125 AtomicDoubleArray3D sharedGKFieldCR) {
126 this.atoms = atoms;
127 this.inducedDipole = inducedDipole;
128 this.inducedDipoleCR = inducedDipoleCR;
129 this.crystal = crystal;
130 this.sXYZ = sXYZ;
131 this.neighborLists = neighborLists;
132 this.use = use;
133 this.cut2 = cut2;
134 this.born = born;
135 this.sharedGKField = sharedGKField;
136 this.sharedGKFieldCR = sharedGKFieldCR;
137 }
138
139 @Override
140 public void run() {
141 try {
142 int nAtoms = atoms.length;
143 int threadIndex = getThreadIndex();
144 execute(0, nAtoms - 1, inducedGKFieldLoop[threadIndex]);
145 } catch (Exception e) {
146 String message = "Fatal exception computing GK field in thread " + getThreadIndex() + "\n";
147 logger.log(Level.SEVERE, message, e);
148 }
149 }
150
151
152
153
154
155
156 private class InducedGKFieldLoop extends IntegerForLoop {
157
158 private final double[][] a;
159 private final double[] gux;
160 private final double[] guy;
161 private final double[] guz;
162 private final double[] dx_local;
163 private int threadID;
164 private double xi, yi, zi;
165 private double uix, uiy, uiz;
166 private double uixCR, uiyCR, uizCR;
167 private double rbi;
168 private int iSymm;
169 private double[][] transOp;
170
171 InducedGKFieldLoop() {
172 a = new double[3][2];
173 gux = new double[5];
174 guy = new double[5];
175 guz = new double[5];
176 dx_local = new double[3];
177 transOp = new double[3][3];
178 }
179
180 @Override
181 public void run(int lb, int ub) {
182
183 threadID = getThreadIndex();
184
185 double[] x = sXYZ[0][0];
186 double[] y = sXYZ[0][1];
187 double[] z = sXYZ[0][2];
188
189 int nSymm = crystal.spaceGroup.symOps.size();
190 List<SymOp> symOps = crystal.spaceGroup.symOps;
191 for (iSymm = 0; iSymm < nSymm; iSymm++) {
192 SymOp symOp = symOps.get(iSymm);
193 crystal.getTransformationOperator(symOp, transOp);
194 for (int i = lb; i <= ub; i++) {
195 if (!use[i]) {
196 continue;
197 }
198 xi = x[i];
199 yi = y[i];
200 zi = z[i];
201 uix = inducedDipole[0][i][0];
202 uiy = inducedDipole[0][i][1];
203 uiz = inducedDipole[0][i][2];
204 uixCR = inducedDipoleCR[0][i][0];
205 uiyCR = inducedDipoleCR[0][i][1];
206 uizCR = inducedDipoleCR[0][i][2];
207 rbi = born[i];
208 int[] list = neighborLists[iSymm][i];
209 for (int k : list) {
210 if (!use[k]) {
211 continue;
212 }
213 inducedGKField(i, k);
214 }
215
216
217 if (iSymm == 0) {
218 inducedGKField(i, i);
219 }
220 }
221 }
222 }
223
224 private void inducedGKField(int i, int k) {
225 dx_local[0] = sXYZ[iSymm][0][k] - xi;
226 dx_local[1] = sXYZ[iSymm][1][k] - yi;
227 dx_local[2] = sXYZ[iSymm][2][k] - zi;
228 final double r2 = crystal.image(dx_local);
229 if (r2 > cut2) {
230 return;
231 }
232 double xr = dx_local[0];
233 double yr = dx_local[1];
234 double zr = dx_local[2];
235 double xr2 = xr * xr;
236 double yr2 = yr * yr;
237 double zr2 = zr * zr;
238 final double ukx = inducedDipole[iSymm][k][0];
239 final double uky = inducedDipole[iSymm][k][1];
240 final double ukz = inducedDipole[iSymm][k][2];
241 final double ukxCR = inducedDipoleCR[iSymm][k][0];
242 final double ukyCR = inducedDipoleCR[iSymm][k][1];
243 final double ukzCR = inducedDipoleCR[iSymm][k][2];
244 final double rbk = born[k];
245 final double rb2 = rbi * rbk;
246 final double expterm = exp(-r2 / (gkc * rb2));
247 final double expc = expterm / gkc;
248 final double expc1 = 1.0 - expc;
249 final double gf2 = 1.0 / (r2 + rb2 * expterm);
250 final double gf = sqrt(gf2);
251 final double gf3 = gf2 * gf;
252 final double gf5 = gf3 * gf2;
253
254
255 a[1][0] = -gf3;
256 a[2][0] = 3.0 * gf5;
257
258
259 a[1][1] = expc1 * a[2][0];
260
261
262 a[1][0] = fd * a[1][0];
263 a[1][1] = fd * a[1][1];
264 a[2][0] = fq * a[2][0];
265
266
267 gux[2] = a[1][0] + xr2 * a[1][1];
268 gux[3] = xr * yr * a[1][1];
269 gux[4] = xr * zr * a[1][1];
270 guy[2] = gux[3];
271 guy[3] = a[1][0] + yr2 * a[1][1];
272 guy[4] = yr * zr * a[1][1];
273 guz[2] = gux[4];
274 guz[3] = guy[4];
275 guz[4] = a[1][0] + zr2 * a[1][1];
276
277
278 double fix = ukx * gux[2] + uky * guy[2] + ukz * guz[2];
279 double fiy = ukx * gux[3] + uky * guy[3] + ukz * guz[3];
280 double fiz = ukx * gux[4] + uky * guy[4] + ukz * guz[4];
281 double fkx = uix * gux[2] + uiy * guy[2] + uiz * guz[2];
282 double fky = uix * gux[3] + uiy * guy[3] + uiz * guz[3];
283 double fkz = uix * gux[4] + uiy * guy[4] + uiz * guz[4];
284 double fixCR = ukxCR * gux[2] + ukyCR * guy[2] + ukzCR * guz[2];
285 double fiyCR = ukxCR * gux[3] + ukyCR * guy[3] + ukzCR * guz[3];
286 double fizCR = ukxCR * gux[4] + ukyCR * guy[4] + ukzCR * guz[4];
287 double fkxCR = uixCR * gux[2] + uiyCR * guy[2] + uizCR * guz[2];
288 double fkyCR = uixCR * gux[3] + uiyCR * guy[3] + uizCR * guz[3];
289 double fkzCR = uixCR * gux[4] + uiyCR * guy[4] + uizCR * guz[4];
290
291
292 if (i == k) {
293 fix *= 0.5;
294 fiy *= 0.5;
295 fiz *= 0.5;
296 fkx *= 0.5;
297 fky *= 0.5;
298 fkz *= 0.5;
299 fixCR *= 0.5;
300 fiyCR *= 0.5;
301 fizCR *= 0.5;
302 fkxCR *= 0.5;
303 fkyCR *= 0.5;
304 fkzCR *= 0.5;
305 }
306
307 double xc = fkx;
308 double yc = fky;
309 double zc = fkz;
310 fkx = xc * transOp[0][0] + yc * transOp[1][0] + zc * transOp[2][0];
311 fky = xc * transOp[0][1] + yc * transOp[1][1] + zc * transOp[2][1];
312 fkz = xc * transOp[0][2] + yc * transOp[1][2] + zc * transOp[2][2];
313 sharedGKField.add(threadID, i, fix, fiy, fiz);
314 sharedGKField.add(threadID, k, fkx, fky, fkz);
315
316 xc = fkxCR;
317 yc = fkyCR;
318 zc = fkzCR;
319 fkxCR = xc * transOp[0][0] + yc * transOp[1][0] + zc * transOp[2][0];
320 fkyCR = xc * transOp[0][1] + yc * transOp[1][1] + zc * transOp[2][1];
321 fkzCR = xc * transOp[0][2] + yc * transOp[1][2] + zc * transOp[2][2];
322 sharedGKFieldCR.add(threadID, i, fixCR, fiyCR, fizCR);
323 sharedGKFieldCR.add(threadID, k, fkxCR, fkyCR, fkzCR);
324 }
325 }
326 }