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;
39
40 import static java.lang.String.format;
41 import static java.util.Arrays.fill;
42 import static org.apache.commons.math3.util.FastMath.floor;
43
44 import edu.rit.pj.IntegerForLoop;
45 import edu.rit.pj.IntegerSchedule;
46 import edu.rit.pj.ParallelRegion;
47 import ffx.crystal.Crystal;
48 import ffx.potential.bonded.Atom;
49 import java.nio.DoubleBuffer;
50 import java.util.logging.Level;
51 import java.util.logging.Logger;
52
53
54
55
56
57
58
59 public class SpatialDensityRegion extends ParallelRegion {
60
61
62 protected static final Logger logger = Logger.getLogger(SpatialDensityRegion.class.getName());
63
64 public final int nThreads;
65 protected final int nSymm;
66 public int[] actualCount;
67 public int nAtoms;
68
69 protected int nA;
70
71 protected int nB;
72
73 protected int nC;
74
75
76
77 protected int actualWork;
78
79 protected double[][][] coordinates;
80 protected boolean[][] select;
81 protected Crystal crystal;
82 protected SpatialDensityLoop[] spatialDensityLoop;
83
84 int[] actualA;
85
86 int[] actualB;
87
88 int[] actualC;
89
90 int[][] cellList;
91
92 int[][] cellCount;
93
94 int[][] cellStart;
95
96 private int basisSize;
97
98 private int minWork;
99
100 private int nAB;
101
102 private int nCells;
103
104 private int nWork;
105
106 private int[][] cellIndex;
107
108 private int[] workA;
109
110 private int[] workB;
111
112 private int[] workC;
113
114
115
116
117 private int[][] cellOffset;
118
119 private double[] xf;
120 private double[] yf;
121 private double[] zf;
122 private int gridSize;
123 private double[] grid = null;
124 private DoubleBuffer gridBuffer;
125 private double initValue = 0.0;
126 private GridInitLoop gridInitLoop;
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143 public SpatialDensityRegion(
144 int gX,
145 int gY,
146 int gZ,
147 double[] grid,
148 int basisSize,
149 int nSymm,
150 int minWork,
151 int threadCount,
152 Crystal crystal,
153 Atom[] atoms,
154 double[][][] coordinates) {
155 this(gX, gY, gZ, basisSize, nSymm, minWork, threadCount, crystal, atoms, coordinates);
156 this.grid = grid;
157 if (grid != null) {
158 gridBuffer = DoubleBuffer.wrap(grid);
159 }
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178 private SpatialDensityRegion(
179 int gX,
180 int gY,
181 int gZ,
182 int basisSize,
183 int nSymm,
184 int minWork,
185 int threadCount,
186 Crystal crystal,
187 Atom[] atoms,
188 double[][][] coordinates) {
189 this.crystal = crystal.getUnitCell();
190 this.coordinates = coordinates;
191 this.nSymm = nSymm;
192 this.nAtoms = atoms.length;
193 this.nThreads = threadCount;
194 this.basisSize = basisSize;
195 this.minWork = minWork;
196 gridInitLoop = new GridInitLoop();
197 setCrystal(crystal.getUnitCell(), gX, gY, gZ);
198 }
199
200
201
202
203
204 public void assignAtomsToCells() {
205
206 selectAtoms();
207
208 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
209 final int[] cellIndexs = cellIndex[iSymm];
210 final int[] cellCounts = cellCount[iSymm];
211 final int[] cellStarts = cellStart[iSymm];
212 final int[] cellLists = cellList[iSymm];
213 final int[] cellOffsets = cellOffset[iSymm];
214 final boolean[] selected = select[iSymm];
215
216
217 for (int i = 0; i < nCells; i++) {
218 cellCounts[i] = 0;
219 }
220
221
222 final double[][] xyz = coordinates[iSymm];
223 final double[] x = xyz[0];
224 final double[] y = xyz[1];
225 final double[] z = xyz[2];
226 crystal.toFractionalCoordinates(nAtoms, x, y, z, xf, yf, zf);
227
228
229 for (int i = 0; i < nAtoms; i++) {
230 if (!selected[i]) {
231 continue;
232 }
233
234 final int index = getCellIndex(i);
235 cellIndexs[i] = index;
236
237
238 cellOffsets[i] = cellCounts[index]++;
239 }
240
241
242 cellStarts[0] = 0;
243 for (int i = 1; i < nCells; i++) {
244 final int i1 = i - 1;
245 cellStarts[i] = cellStarts[i1] + cellCounts[i1];
246 }
247
248
249 for (int i = 0; i < nAtoms; i++) {
250 if (!selected[i]) {
251 continue;
252 }
253 final int index = cellIndexs[i];
254 cellLists[cellStarts[index]++] = i;
255 }
256
257
258 cellStarts[0] = 0;
259 for (int i = 1; i < nCells; i++) {
260 final int i1 = i - 1;
261 cellStarts[i] = cellStarts[i1] + cellCounts[i1];
262 }
263 }
264
265
266 actualWork = 0;
267 for (int icell = 0; icell < nWork; icell++) {
268 int ia = workA[icell];
269 int ib = workB[icell];
270 int ic = workC[icell];
271 int ii = count(ia, ib, ic);
272
273 if (nC > 1) {
274 ii += count(ia, ib, ic + 1);
275
276 if (nB > 1) {
277 ii += count(ia, ib + 1, ic);
278 ii += count(ia, ib + 1, ic + 1);
279
280 if (nA > 1) {
281 ii += count(ia + 1, ib, ic);
282 ii += count(ia + 1, ib, ic + 1);
283 ii += count(ia + 1, ib + 1, ic);
284 ii += count(ia + 1, ib + 1, ic + 1);
285 }
286 }
287 }
288
289
290 if (ii > 0) {
291 actualA[actualWork] = ia;
292 actualB[actualWork] = ib;
293 actualC[actualWork] = ic;
294 actualCount[actualWork++] = ii;
295 }
296 }
297
298 if (logger.isLoggable(Level.FINEST)) {
299 logger.finest(format(" Empty chunks: %d out of %d.", nWork - actualWork, nWork));
300 }
301 }
302
303 private int getCellIndex(int i) {
304 double xu = xf[i];
305 double yu = yf[i];
306 double zu = zf[i];
307
308
309 while (xu >= 1.0) {
310 xu -= 1.0;
311 }
312 while (xu < 0.0) {
313 xu += 1.0;
314 }
315 while (yu >= 1.0) {
316 yu -= 1.0;
317 }
318 while (yu < 0.0) {
319 yu += 1.0;
320 }
321 while (zu >= 1.0) {
322 zu -= 1.0;
323 }
324 while (zu < 0.0) {
325 zu += 1.0;
326 }
327
328
329 int a = (int) floor(xu * nA);
330 int b = (int) floor(yu * nB);
331 int c = (int) floor(zu * nC);
332
333
334 if (a >= nA) {
335 a = nA - 1;
336 }
337 if (b >= nB) {
338 b = nB - 1;
339 }
340 if (c >= nC) {
341 c = nC - 1;
342 }
343
344
345 final int index = a + b * nA + c * nAB;
346 return index;
347 }
348
349
350
351
352
353
354 public double[] getGrid() {
355 return grid;
356 }
357
358
359
360
361
362
363 public int getNsymm() {
364 return nSymm;
365 }
366
367
368
369
370
371
372
373
374
375 public int index(int ia, int ib, int ic) {
376 return ia + ib * nA + ic * nAB;
377 }
378
379
380 @Override
381 public void run() {
382 int ti = getThreadIndex();
383 int actualWork1 = actualWork - 1;
384 SpatialDensityLoop loop = spatialDensityLoop[ti];
385
386
387 loop.setNsymm(nSymm);
388
389 try {
390 execute(0, gridSize - 1, gridInitLoop);
391 execute(0, actualWork1, loop.setOctant(0));
392
393 if (nC > 1) {
394 execute(0, actualWork1, loop.setOctant(1));
395
396 if (nB > 1) {
397 execute(0, actualWork1, loop.setOctant(2));
398 execute(0, actualWork1, loop.setOctant(3));
399
400 if (nA > 1) {
401 execute(0, actualWork1, loop.setOctant(4));
402 execute(0, actualWork1, loop.setOctant(5));
403 execute(0, actualWork1, loop.setOctant(6));
404 execute(0, actualWork1, loop.setOctant(7));
405 }
406 }
407 }
408 } catch (Exception e) {
409 String message = " Exception in SpatialDensityRegion.";
410 logger.log(Level.SEVERE, message, e);
411 }
412 }
413
414
415
416
417
418
419 public void selectAtoms() {}
420
421
422
423
424
425
426 public void setAtoms(Atom[] atoms) {
427 nAtoms = atoms.length;
428 if (select == null || select.length < nSymm || select[0].length < nAtoms) {
429 select = new boolean[nSymm][nAtoms];
430 for (int i = 0; i < nSymm; i++) {
431 fill(select[i], true);
432 }
433 cellList = new int[nSymm][nAtoms];
434 cellIndex = new int[nSymm][nAtoms];
435 cellOffset = new int[nSymm][nAtoms];
436 }
437 if (xf == null || xf.length < nAtoms) {
438 xf = new double[nAtoms];
439 yf = new double[nAtoms];
440 zf = new double[nAtoms];
441 }
442 }
443
444
445
446
447
448
449
450
451
452 public final void setCrystal(Crystal crystal, int gX, int gY, int gZ) {
453 this.crystal = crystal.getUnitCell();
454
455 if (xf == null || xf.length < nAtoms) {
456 xf = new double[nAtoms];
457 yf = new double[nAtoms];
458 zf = new double[nAtoms];
459 }
460
461 gridSize = gX * gY * gZ * 2;
462 int nX = gX / basisSize;
463 int nY = gY / basisSize;
464 int nZ = gZ / basisSize;
465 if (nThreads > 1 && nZ > 1) {
466 if (nZ % 2 != 0) {
467 nZ--;
468 }
469 nC = nZ;
470 int div = 2;
471 int currentWork = nC / div / nThreads;
472
473 if (currentWork >= minWork || nY < 2) {
474 nA = 1;
475 nB = 1;
476
477 while (currentWork >= 2 * minWork) {
478 nC -= 2;
479 currentWork = nC / div / nThreads;
480 }
481
482 } else {
483 if (nY % 2 != 0) {
484 nY--;
485 }
486 nB = nY;
487 div = 4;
488 currentWork = nB * nC / div / nThreads;
489
490 if (currentWork >= minWork || nX < 2) {
491 nA = 1;
492 while (currentWork >= 2 * minWork) {
493 nB -= 2;
494 currentWork = nB * nC / div / nThreads;
495 }
496 } else {
497 if (nX % 2 != 0) {
498 nX--;
499 }
500 nA = nX;
501 div = 8;
502 currentWork = nA * nB * nC / div / nThreads;
503 while (currentWork >= 2 * minWork) {
504 nA -= 2;
505 currentWork = nA * nB * nC / div / nThreads;
506 }
507 }
508 }
509 nAB = nA * nB;
510 nCells = nAB * nC;
511 nWork = nCells / div;
512 } else {
513 nA = 1;
514 nB = 1;
515 nC = 1;
516 nAB = 1;
517 nCells = 1;
518 nWork = 1;
519 }
520
521 logger.fine(format(" Spatial cells: (%3d,%3d,%3d)", nA, nB, nC));
522 logger.fine(format(" Spatial work: %4d", nWork));
523
524 if (workA == null || workA.length < nWork) {
525 workA = new int[nWork];
526 workB = new int[nWork];
527 workC = new int[nWork];
528 actualA = new int[nWork];
529 actualB = new int[nWork];
530 actualC = new int[nWork];
531 actualCount = new int[nWork];
532 int index = 0;
533 for (int h = 0; h < nA; h += 2) {
534 for (int k = 0; k < nB; k += 2) {
535 for (int l = 0; l < nC; l += 2) {
536 workA[index] = h;
537 workB[index] = k;
538 workC[index++] = l;
539 }
540 }
541 }
542 }
543 if (select == null || select.length < nSymm || select[0].length < nAtoms) {
544 select = new boolean[nSymm][nAtoms];
545 for (int i = 0; i < nSymm; i++) {
546 fill(select[i], true);
547 }
548 cellList = new int[nSymm][nAtoms];
549 cellIndex = new int[nSymm][nAtoms];
550 cellOffset = new int[nSymm][nAtoms];
551 }
552 if (cellStart == null || cellStart.length < nSymm || cellStart[0].length < nCells) {
553 cellStart = new int[nSymm][nCells];
554 cellCount = new int[nSymm][nCells];
555 }
556 }
557
558
559
560
561
562
563 public void setDensityLoop(SpatialDensityLoop[] loops) {
564 spatialDensityLoop = loops;
565 }
566
567
568
569
570
571
572 public void setInitValue(double initValue) {
573 this.initValue = initValue;
574 }
575
576
577
578
579
580
581 void setGridBuffer(DoubleBuffer grid) {
582 gridBuffer = grid;
583 }
584
585 private int count(int ia, int ib, int ic) {
586 int count = 0;
587 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
588 final int index = index(ia, ib, ic);
589 final int start = cellStart[iSymm][index];
590 final int stop = start + cellCount[iSymm][index];
591 count += (stop - start);
592 }
593 return count;
594 }
595
596 private class GridInitLoop extends IntegerForLoop {
597
598 private final IntegerSchedule schedule = IntegerSchedule.fixed();
599
600 @Override
601 public void run(int lb, int ub) {
602 if (gridBuffer != null) {
603
604 for (int i = lb; i <= ub; i++) {
605
606 gridBuffer.put(i, initValue);
607 }
608 }
609 }
610
611 @Override
612 public IntegerSchedule schedule() {
613 return schedule;
614 }
615 }
616 }