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.xray;
39
40 import edu.rit.pj.IntegerForLoop;
41 import edu.rit.pj.IntegerSchedule;
42 import edu.rit.pj.ParallelRegion;
43 import edu.rit.pj.ParallelTeam;
44 import edu.rit.pj.reduction.SharedIntegerArray;
45 import ffx.crystal.Crystal;
46 import ffx.crystal.HKL;
47 import ffx.crystal.ReflectionList;
48 import ffx.crystal.Resolution;
49 import ffx.crystal.SymOp;
50 import ffx.numerics.fft.Complex;
51 import ffx.numerics.fft.Complex3DParallel;
52 import ffx.numerics.math.ComplexNumber;
53 import ffx.potential.bonded.Atom;
54 import ffx.potential.nonbonded.RowLoop;
55 import ffx.potential.nonbonded.RowRegion;
56 import ffx.potential.nonbonded.SliceLoop;
57 import ffx.potential.nonbonded.SliceRegion;
58 import ffx.potential.nonbonded.SpatialDensityLoop;
59 import ffx.potential.nonbonded.SpatialDensityRegion;
60 import ffx.xray.parallel.GradientSchedule;
61 import ffx.xray.parallel.GridMethod;
62 import ffx.xray.parallel.RowSchedule;
63 import ffx.xray.parallel.SliceSchedule;
64 import ffx.xray.refine.RefinementMode;
65 import ffx.xray.scatter.FormFactor;
66 import ffx.xray.scatter.NeutronFormFactor;
67 import ffx.xray.scatter.SolventBinaryFormFactor;
68 import ffx.xray.scatter.SolventGaussFormFactor;
69 import ffx.xray.scatter.SolventPolyFormFactor;
70 import ffx.xray.scatter.XRayFormFactor;
71 import ffx.xray.solvent.BulkSolventDensityRegion;
72 import ffx.xray.solvent.BulkSolventRowRegion;
73 import ffx.xray.solvent.BulkSolventSliceRegion;
74 import ffx.xray.solvent.SolventModel;
75
76 import java.util.ArrayList;
77 import java.util.List;
78 import java.util.logging.Level;
79 import java.util.logging.Logger;
80
81 import static ffx.crystal.SymOp.applyTransSymRot;
82 import static ffx.numerics.fft.Complex3D.interleavedIndex;
83 import static ffx.numerics.math.ScalarMath.mod;
84 import static java.lang.String.format;
85 import static java.lang.System.arraycopy;
86 import static java.util.Arrays.fill;
87 import static org.apache.commons.math3.util.FastMath.abs;
88 import static org.apache.commons.math3.util.FastMath.exp;
89 import static org.apache.commons.math3.util.FastMath.floor;
90 import static org.apache.commons.math3.util.FastMath.max;
91 import static org.apache.commons.math3.util.FastMath.min;
92 import static org.apache.commons.math3.util.FastMath.pow;
93 import static org.apache.commons.math3.util.FastMath.sqrt;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public class CrystalReciprocalSpace {
118
119 private static final Logger logger = Logger.getLogger(CrystalReciprocalSpace.class.getName());
120 private static final double toSeconds = 1.0e-9;
121 private final boolean neutron;
122 private final double fftScale;
123 private final double[] densityGrid;
124 private final double[] solventGrid;
125 private final int nSymm;
126 private final int bulkNSymm;
127 private final int nScatteringAtoms;
128 private final int fftX, fftY, fftZ;
129 private final double ifftX, ifftY, ifftZ;
130 private final int halfFFTX;
131 private final int complexFFT3DSpace;
132 private final int threadCount;
133 private final int bufferSize = 3;
134
135 private final SharedIntegerArray optSliceWeightAtomic;
136 private final SharedIntegerArray optSliceWeightSolvent;
137 private final SharedIntegerArray optSliceWeightBulkSolvent;
138 private final int[] previousOptSliceWeightAtomic;
139 private final int[] previousOptSliceWeightSolvent;
140 private final int[] previousOptSliceWeightBulkSolvent;
141 private final SliceSchedule atomicSliceSchedule;
142 private final SliceSchedule solventSliceSchedule;
143 private final SliceSchedule bulkSolventSliceSchedule;
144
145 private final SharedIntegerArray optRowWeightAtomic;
146 private final SharedIntegerArray optRowWeightSolvent;
147 private final SharedIntegerArray optRowWeightBulkSolvent;
148 private final int[] previousOptRowWeightAtomic;
149 private final int[] previousOptRowWeightSolvent;
150 private final int[] previousOptRowWeightBulkSolvent;
151 private final RowSchedule atomicRowSchedule;
152 private final RowSchedule solventRowSchedule;
153 private final RowSchedule bulkSolventRowSchedule;
154
155 private final ParallelTeam parallelTeam;
156 private final Atom[] scatteringAtoms;
157 private final Crystal crystal;
158 private final ReflectionList reflectionList;
159 private final FormFactor[][] atomFormFactors;
160 private final FormFactor[][] solventFormFactors;
161 private final GridMethod gridMethod;
162 private final SharedIntegerArray optAtomicGradientWeight;
163 private final int[] previousOptAtomicGradientWeight;
164 private final GradientSchedule atomicGradientSchedule;
165
166
167
168
169 private final SpatialDensityRegion atomicDensityRegion;
170 private final SpatialDensityRegion solventDensityRegion;
171
172
173
174
175
176 private final SliceRegion atomicSliceRegion;
177 private final SliceRegion solventSliceRegion;
178 private final AtomicSliceLoop[] atomicSliceLoops;
179 private final SolventSliceLoop[] solventSliceLoops;
180 private final BulkSolventSliceLoop[] bulkSolventSliceLoops;
181
182
183
184
185 private final RowRegion atomicRowRegion;
186 private final RowRegion solventRowRegion;
187 private final AtomicRowLoop[] atomicRowLoops;
188 private final SolventRowLoop[] solventRowLoops;
189 private final BulkSolventRowLoop[] bulkSolventRowLoops;
190
191
192
193 private final InitRegion initRegion;
194 private final ExtractRegion extractRegion;
195 private final AtomicScaleRegion atomicScaleRegion;
196 private final AtomicGradientRegion atomicGradientRegion;
197
198
199
200 private final BabinetRegion babinetRegion;
201
202 private final SolventGridRegion solventGridRegion;
203 private final SolventScaleRegion solventScaleRegion;
204 private final SolventGradientRegion solventGradientRegion;
205 private final Complex3DParallel complexFFT3D;
206
207
208
209 private double bAdd;
210 boolean lambdaTerm = false;
211 private final SolventModel solventModel;
212 private final boolean solvent;
213 private double solventA;
214 private double solventB;
215
216 private boolean useThreeGaussians = true;
217
218 private final double[][][] coordinates;
219 private double weight = 1.0;
220 private final int aRadGrid;
221
222
223
224 private boolean nativeEnvironmentApproximation = false;
225
226
227
228
229
230
231
232
233
234
235
236 public CrystalReciprocalSpace(
237 ReflectionList reflectionList,
238 Atom[] scatteringAtoms,
239 ParallelTeam fftTeam,
240 ParallelTeam parallelTeam) {
241 this(
242 reflectionList,
243 scatteringAtoms,
244 fftTeam,
245 parallelTeam,
246 false,
247 false,
248 SolventModel.POLYNOMIAL,
249 GridMethod.SLICE);
250 }
251
252
253
254
255
256
257
258
259
260
261
262
263 public CrystalReciprocalSpace(
264 ReflectionList reflectionList,
265 Atom[] scatteringAtoms,
266 ParallelTeam fftTeam,
267 ParallelTeam parallelTeam,
268 boolean solventMask) {
269 this(
270 reflectionList,
271 scatteringAtoms,
272 fftTeam,
273 parallelTeam,
274 solventMask,
275 false,
276 SolventModel.POLYNOMIAL,
277 GridMethod.SLICE);
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294 public CrystalReciprocalSpace(
295 ReflectionList reflectionlist,
296 Atom[] scatteringAtoms,
297 ParallelTeam fftTeam,
298 ParallelTeam parallelTeam,
299 boolean solventMask,
300 boolean neutron,
301 SolventModel solventModel,
302 GridMethod gridMethod) {
303 this.reflectionList = reflectionlist;
304 this.scatteringAtoms = scatteringAtoms;
305 this.parallelTeam = parallelTeam;
306 this.solvent = solventMask;
307 this.neutron = neutron;
308 this.solventModel = solventModel;
309 this.gridMethod = gridMethod;
310
311 nScatteringAtoms = scatteringAtoms.length;
312 crystal = reflectionlist.crystal;
313 nSymm = 1;
314 threadCount = parallelTeam.getThreadCount();
315
316
317 bulkNSymm = crystal.spaceGroup.symOps.size();
318 Resolution resolution = reflectionlist.resolution;
319 double gridFactor = resolution.samplingLimit() / 2.0;
320 double gridStep = resolution.resolutionLimit() * gridFactor;
321
322 int nX = (int) Math.floor(crystal.a / gridStep) + 1;
323 int nY = (int) Math.floor(crystal.b / gridStep) + 1;
324 int nZ = (int) Math.floor(crystal.c / gridStep) + 1;
325 if (nX % 2 != 0) {
326 nX += 1;
327 }
328
329 while (!Complex.preferredDimension(nX)) {
330 nX += 2;
331 }
332 while (!Complex.preferredDimension(nY)) {
333 nY += 1;
334 }
335 while (!Complex.preferredDimension(nZ)) {
336 nZ += 1;
337 }
338
339 fftX = nX;
340 fftY = nY;
341 fftZ = nZ;
342 halfFFTX = nX / 2;
343 ifftX = 1.0 / (double) fftX;
344 ifftY = 1.0 / (double) fftY;
345 ifftZ = 1.0 / (double) fftZ;
346 fftScale = crystal.volume;
347 complexFFT3DSpace = fftX * fftY * fftZ * 2;
348 densityGrid = new double[complexFFT3DSpace];
349
350
351 optSliceWeightAtomic = new SharedIntegerArray(fftZ);
352 optSliceWeightSolvent = new SharedIntegerArray(fftZ);
353 optSliceWeightBulkSolvent = new SharedIntegerArray(fftZ);
354 previousOptSliceWeightAtomic = new int[fftZ];
355 previousOptSliceWeightSolvent = new int[fftZ];
356 previousOptSliceWeightBulkSolvent = new int[fftZ];
357
358 atomicSliceSchedule = new SliceSchedule(threadCount, fftZ);
359 solventSliceSchedule = new SliceSchedule(threadCount, fftZ);
360 bulkSolventSliceSchedule = new SliceSchedule(threadCount, fftZ);
361
362
363 optRowWeightAtomic = new SharedIntegerArray(fftZ * fftY);
364 optRowWeightSolvent = new SharedIntegerArray(fftZ * fftY);
365 optRowWeightBulkSolvent = new SharedIntegerArray(fftZ * fftY);
366 previousOptRowWeightAtomic = new int[fftZ * fftY];
367 previousOptRowWeightSolvent = new int[fftZ * fftY];
368 previousOptRowWeightBulkSolvent = new int[fftZ * fftY];
369 atomicRowSchedule = new RowSchedule(threadCount, fftZ, fftY);
370 solventRowSchedule = new RowSchedule(threadCount, fftZ, fftY);
371 bulkSolventRowSchedule = new RowSchedule(threadCount, fftZ, fftY);
372
373 optAtomicGradientWeight = new SharedIntegerArray(nScatteringAtoms);
374 previousOptAtomicGradientWeight = new int[nScatteringAtoms];
375 atomicGradientSchedule = new GradientSchedule(threadCount, nScatteringAtoms);
376
377 if (solvent) {
378 bAdd = 0.0;
379 atomFormFactors = null;
380 double vdwr;
381 switch (solventModel) {
382 case BINARY:
383
384 solventA = 1.0;
385 solventB = 1.0;
386 solventGrid = new double[complexFFT3DSpace];
387 solventFormFactors = new SolventBinaryFormFactor[bulkNSymm][nScatteringAtoms];
388 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
389 for (int i = 0; i < nScatteringAtoms; i++) {
390 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
391 solventFormFactors[iSymm][i] = new SolventBinaryFormFactor(scatteringAtoms[i], vdwr + solventA);
392 }
393 }
394 break;
395 case GAUSSIAN:
396
397
398
399
400
401
402
403
404
405
406 solventA = 11.5;
407 solventB = 0.55;
408 solventGrid = new double[complexFFT3DSpace];
409 solventFormFactors = new SolventGaussFormFactor[bulkNSymm][nScatteringAtoms];
410 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
411 for (int i = 0; i < nScatteringAtoms; i++) {
412 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
413 solventFormFactors[iSymm][i] = new SolventGaussFormFactor(scatteringAtoms[i], vdwr * solventB);
414 }
415 }
416 break;
417 case POLYNOMIAL:
418
419
420
421
422
423
424
425
426
427
428 solventA = 0.0;
429 solventB = 0.8;
430 solventGrid = new double[complexFFT3DSpace];
431 solventFormFactors = new SolventPolyFormFactor[bulkNSymm][nScatteringAtoms];
432 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
433 for (int i = 0; i < nScatteringAtoms; i++) {
434 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
435 solventFormFactors[iSymm][i] =
436 new SolventPolyFormFactor(scatteringAtoms[i], vdwr + solventA, solventB);
437 }
438 }
439 break;
440 case NONE:
441 default:
442 solventGrid = null;
443 solventFormFactors = null;
444 break;
445 }
446 } else {
447 bAdd = 2.0;
448 if (neutron) {
449 atomFormFactors = new NeutronFormFactor[bulkNSymm][nScatteringAtoms];
450 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
451 for (int i = 0; i < nScatteringAtoms; i++) {
452 atomFormFactors[iSymm][i] = new NeutronFormFactor(scatteringAtoms[i], bAdd);
453
454 }
455 }
456 } else {
457 atomFormFactors = new XRayFormFactor[bulkNSymm][nScatteringAtoms];
458 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
459 for (int i = 0; i < nScatteringAtoms; i++) {
460 atomFormFactors[iSymm][i] = new XRayFormFactor(scatteringAtoms[i], useThreeGaussians, bAdd);
461 }
462 }
463 }
464 solventGrid = null;
465 solventFormFactors = null;
466 }
467
468
469 double aRad = getaRad(scatteringAtoms, solventModel);
470 aRadGrid = (int) Math.floor(aRad * nX / crystal.a) + 1;
471
472
473 coordinates = new double[bulkNSymm][3][nScatteringAtoms];
474 List<SymOp> symops = crystal.spaceGroup.symOps;
475 double[] xyz = new double[3];
476 for (int i = 0; i < bulkNSymm; i++) {
477 double[] x = coordinates[i][0];
478 double[] y = coordinates[i][1];
479 double[] z = coordinates[i][2];
480 for (int j = 0; j < nScatteringAtoms; j++) {
481 Atom aj = scatteringAtoms[j];
482 crystal.applySymOp(aj.getXYZ(null), xyz, symops.get(i));
483 x[j] = xyz[0];
484 y[j] = xyz[1];
485 z[j] = xyz[2];
486 }
487 }
488
489 if (logger.isLoggable(Level.INFO)) {
490 StringBuilder sb = new StringBuilder();
491 if (solvent) {
492 sb.append(" Bulk Solvent Grid\n");
493 sb.append(format(" Bulk solvent model type: %8s\n", solventModel));
494 } else {
495 sb.append(" Atomic Scattering Grid\n");
496 }
497 sb.append(format(" Form factor grid points: %8d\n", aRadGrid * 2));
498 sb.append(format(" Form factor grid diameter: %8.3f\n", aRad * 2));
499 sb.append(format(" Grid density: %8.3f\n", 1.0 / gridStep));
500 sb.append(format(" Grid dimensions: (%3d,%3d,%3d)\n", fftX, fftY, fftZ));
501 sb.append(format(" Grid method: %8s\n", gridMethod));
502 logger.info(sb.toString());
503 }
504
505 if (solvent) {
506 int minWork = nSymm;
507 if (solventModel != SolventModel.NONE) {
508 solventGradientRegion =
509 new SolventGradientRegion(RefinementMode.COORDINATES_AND_BFACTORS_AND_OCCUPANCIES);
510
511 atomicGradientRegion = null;
512 atomicSliceLoops = null;
513 atomicRowLoops = null;
514 switch (gridMethod) {
515 case SPATIAL:
516 atomicDensityRegion = new SpatialDensityRegion(fftX, fftY, fftZ, densityGrid,
517 (aRadGrid + 2) * 2, nSymm, minWork, threadCount, crystal,
518 scatteringAtoms, coordinates);
519 solventDensityRegion = new BulkSolventDensityRegion(fftX, fftY, fftZ, solventGrid,
520 (aRadGrid + 2) * 2, bulkNSymm, minWork, threadCount, crystal,
521 scatteringAtoms, coordinates, 4.0, parallelTeam);
522 if (solventModel == SolventModel.GAUSSIAN) {
523 atomicDensityRegion.setInitValue(0.0);
524 } else {
525 atomicDensityRegion.setInitValue(1.0);
526 }
527 SolventDensityLoop[] solventDensityLoops = new SolventDensityLoop[threadCount];
528 SolventDensityLoop[] bulkSolventDensityLoops = new SolventDensityLoop[threadCount];
529 for (int i = 0; i < threadCount; i++) {
530 solventDensityLoops[i] = new SolventDensityLoop(atomicDensityRegion);
531 bulkSolventDensityLoops[i] = new SolventDensityLoop(solventDensityRegion);
532 }
533 atomicDensityRegion.setDensityLoop(solventDensityLoops);
534 solventDensityRegion.setDensityLoop(bulkSolventDensityLoops);
535
536 atomicSliceRegion = null;
537 solventSliceRegion = null;
538 bulkSolventSliceLoops = null;
539 solventSliceLoops = null;
540
541 atomicRowRegion = null;
542 solventRowRegion = null;
543 bulkSolventRowLoops = null;
544 solventRowLoops = null;
545 break;
546 case ROW:
547 atomicRowRegion = new RowRegion(fftX, fftY, fftZ, densityGrid, nSymm, threadCount,
548 scatteringAtoms, coordinates);
549 solventRowRegion = new BulkSolventRowRegion(fftX, fftY, fftZ, solventGrid, bulkNSymm,
550 threadCount, crystal, scatteringAtoms, coordinates, 4.0, parallelTeam);
551 if (solventModel == SolventModel.GAUSSIAN) {
552 atomicRowRegion.setInitValue(0.0);
553 } else {
554 atomicRowRegion.setInitValue(1.0);
555 }
556 solventRowLoops = new SolventRowLoop[threadCount];
557 bulkSolventRowLoops = new BulkSolventRowLoop[threadCount];
558 for (int i = 0; i < threadCount; i++) {
559 solventRowLoops[i] = new SolventRowLoop(atomicRowRegion);
560 bulkSolventRowLoops[i] = new BulkSolventRowLoop(solventRowRegion);
561 }
562 atomicRowRegion.setDensityLoop(solventRowLoops);
563 solventRowRegion.setDensityLoop(bulkSolventRowLoops);
564 atomicDensityRegion = null;
565 solventDensityRegion = null;
566 atomicSliceRegion = null;
567 solventSliceRegion = null;
568 bulkSolventSliceLoops = null;
569 solventSliceLoops = null;
570 break;
571 case SLICE:
572 default:
573 atomicSliceRegion = new SliceRegion(fftX, fftY, fftZ, densityGrid, nSymm,
574 threadCount, scatteringAtoms, coordinates);
575 solventSliceRegion = new BulkSolventSliceRegion(fftX, fftY, fftZ, solventGrid,
576 bulkNSymm, threadCount, crystal, scatteringAtoms, coordinates, 4.0,
577 parallelTeam);
578 if (solventModel == SolventModel.GAUSSIAN) {
579 atomicSliceRegion.setInitValue(0.0);
580 } else {
581 atomicSliceRegion.setInitValue(1.0);
582 }
583 solventSliceLoops = new SolventSliceLoop[threadCount];
584 bulkSolventSliceLoops = new BulkSolventSliceLoop[threadCount];
585 for (int i = 0; i < threadCount; i++) {
586 solventSliceLoops[i] = new SolventSliceLoop(atomicSliceRegion);
587 bulkSolventSliceLoops[i] = new BulkSolventSliceLoop(solventSliceRegion);
588 }
589 atomicSliceRegion.setDensityLoop(solventSliceLoops);
590 solventSliceRegion.setDensityLoop(bulkSolventSliceLoops);
591
592 atomicDensityRegion = null;
593 solventDensityRegion = null;
594 atomicRowRegion = null;
595 solventRowRegion = null;
596 bulkSolventRowLoops = null;
597 solventRowLoops = null;
598 }
599 } else {
600 atomicDensityRegion = null;
601 solventDensityRegion = null;
602 atomicGradientRegion = null;
603 solventGradientRegion = null;
604 atomicSliceRegion = null;
605 atomicSliceLoops = null;
606 solventSliceRegion = null;
607 bulkSolventSliceLoops = null;
608 solventSliceLoops = null;
609 atomicRowRegion = null;
610 atomicRowLoops = null;
611 solventRowRegion = null;
612 bulkSolventRowLoops = null;
613 solventRowLoops = null;
614 }
615 } else {
616 atomicGradientRegion =
617 new AtomicGradientRegion(RefinementMode.COORDINATES_AND_BFACTORS_AND_OCCUPANCIES);
618
619
620 solventDensityRegion = null;
621 solventSliceRegion = null;
622 solventSliceLoops = null;
623 bulkSolventSliceLoops = null;
624 solventRowRegion = null;
625 solventRowLoops = null;
626 bulkSolventRowLoops = null;
627 solventGradientRegion = null;
628
629
630
631
632
633 switch (gridMethod) {
634 case SPATIAL:
635 int minWork = nSymm;
636 atomicDensityRegion =
637 new SpatialDensityRegion(
638 fftX,
639 fftY,
640 fftZ,
641 densityGrid,
642 (aRadGrid + 2) * 2,
643 nSymm,
644 minWork,
645 threadCount,
646 crystal,
647 scatteringAtoms,
648 coordinates);
649 atomicDensityRegion.setInitValue(0.0);
650 AtomicDensityLoop[] atomicDensityLoops = new AtomicDensityLoop[threadCount];
651 for (int i = 0; i < threadCount; i++) {
652 atomicDensityLoops[i] = new AtomicDensityLoop(atomicDensityRegion);
653 }
654 atomicDensityRegion.setDensityLoop(atomicDensityLoops);
655 atomicSliceRegion = null;
656 atomicSliceLoops = null;
657 atomicRowRegion = null;
658 atomicRowLoops = null;
659 break;
660
661 case ROW:
662 atomicRowRegion =
663 new RowRegion(fftX, fftY, fftZ, densityGrid, nSymm, threadCount, scatteringAtoms, coordinates);
664 atomicRowRegion.setInitValue(0.0);
665 atomicRowLoops = new AtomicRowLoop[threadCount];
666 for (int i = 0; i < threadCount; i++) {
667 atomicRowLoops[i] = new AtomicRowLoop(atomicRowRegion);
668 }
669 atomicRowRegion.setDensityLoop(atomicRowLoops);
670 atomicDensityRegion = null;
671 atomicSliceRegion = null;
672 atomicSliceLoops = null;
673 break;
674
675 case SLICE:
676 default:
677 atomicSliceRegion =
678 new SliceRegion(
679 fftX, fftY, fftZ, densityGrid, nSymm, threadCount, scatteringAtoms, coordinates);
680 atomicSliceRegion.setInitValue(0.0);
681 atomicSliceLoops = new AtomicSliceLoop[threadCount];
682 for (int i = 0; i < threadCount; i++) {
683 atomicSliceLoops[i] = new AtomicSliceLoop(atomicSliceRegion);
684 }
685 atomicSliceRegion.setDensityLoop(atomicSliceLoops);
686 atomicDensityRegion = null;
687 atomicRowRegion = null;
688 atomicRowLoops = null;
689 }
690 }
691
692 extractRegion = new ExtractRegion(threadCount);
693 babinetRegion = new BabinetRegion(threadCount);
694 solventGridRegion = new SolventGridRegion(threadCount);
695 initRegion = new InitRegion(threadCount);
696 solventScaleRegion = new SolventScaleRegion(threadCount);
697 atomicScaleRegion = new AtomicScaleRegion(threadCount);
698 complexFFT3D = new Complex3DParallel(fftX, fftY, fftZ, fftTeam);
699 }
700
701 private double getaRad(Atom[] atoms, SolventModel solventModel) {
702 double aRad = -1.0;
703 for (Atom a : atoms) {
704 double vdwr = a.getVDWType().radius * 0.5;
705 if (!solvent) {
706 aRad = Math.max(aRad, a.getFormFactorWidth());
707 } else {
708 switch (solventModel) {
709 case BINARY:
710 aRad = Math.max(aRad, vdwr + solventA + 0.2);
711 break;
712 case GAUSSIAN:
713 aRad = Math.max(aRad, vdwr * solventB + 2.0);
714 break;
715 case POLYNOMIAL:
716 aRad = Math.max(aRad, vdwr + solventB + 0.2);
717 break;
718 case NONE:
719 default:
720 aRad = 0.0;
721 }
722 }
723 }
724 return aRad;
725 }
726
727
728
729
730
731
732
733
734
735
736
737 public void computeAtomicGradients(
738 double[][] hklData, int[] freer, int flag, RefinementMode refinementMode) {
739 computeAtomicGradients(hklData, freer, flag, refinementMode, false);
740 }
741
742
743
744
745
746
747
748 public void computeSolventDensity(double[][] hklData) {
749 computeSolventDensity(hklData, false);
750 }
751
752
753
754
755
756
757
758
759 public void densityNorm(double[] data, double[] meansd, boolean norm) {
760 double mean = 0.0;
761 double sd = 0.0;
762 int n = 0;
763 for (int k = 0; k < fftZ; k++) {
764 for (int j = 0; j < fftY; j++) {
765 for (int i = 0; i < fftX; i++) {
766 int index = interleavedIndex(i, j, k, fftX, fftY);
767 n++;
768 mean += (data[index] - mean) / n;
769 }
770 }
771 }
772
773 n = 0;
774 for (int k = 0; k < fftZ; k++) {
775 for (int j = 0; j < fftY; j++) {
776 for (int i = 0; i < fftX; i++) {
777 int index = interleavedIndex(i, j, k, fftX, fftY);
778 sd += pow(data[index] - mean, 2);
779 n++;
780 }
781 }
782 }
783 sd = sqrt(sd / n);
784
785 if (meansd != null) {
786 meansd[0] = mean;
787 meansd[1] = sd;
788 }
789
790 if (norm) {
791 double isd = 1.0 / sd;
792 for (int k = 0; k < fftZ; k++) {
793 for (int j = 0; j < fftY; j++) {
794 for (int i = 0; i < fftX; i++) {
795 int index = interleavedIndex(i, j, k, fftX, fftY);
796 data[index] = (data[index] - mean) * isd;
797 }
798 }
799 }
800 }
801 }
802
803
804
805
806
807
808 public double[] getDensityGrid() {
809 return densityGrid;
810 }
811
812
813
814
815
816
817 public double getWeight() {
818 return weight;
819 }
820
821
822
823
824
825
826 public void setWeight(double weight) {
827 this.weight = weight;
828 }
829
830
831
832
833
834
835 public double getXDim() {
836 return fftX;
837 }
838
839
840
841
842
843
844 public double getYDim() {
845 return fftY;
846 }
847
848
849
850
851
852
853 public double getZDim() {
854 return fftZ;
855 }
856
857
858
859
860 public void updateCoordinates() {
861 List<SymOp> symops = crystal.spaceGroup.symOps;
862 double[] xyz = new double[3];
863 double[] symXYZ = new double[3];
864 for (int i = 0; i < nScatteringAtoms; i++) {
865 Atom atom = scatteringAtoms[i];
866 if (atom.isActive()) {
867 atom.getXYZ(xyz);
868 for (int j = 0; j < nSymm; j++) {
869 crystal.applySymOp(xyz, symXYZ, symops.get(j));
870 coordinates[j][0][i] = symXYZ[0];
871 coordinates[j][1][i] = symXYZ[1];
872 coordinates[j][2][i] = symXYZ[2];
873 }
874 }
875 }
876 }
877
878
879
880
881
882
883 void setNativeEnvironmentApproximation(boolean nativeEnvironmentApproximation) {
884 this.nativeEnvironmentApproximation = nativeEnvironmentApproximation;
885 }
886
887
888
889
890
891
892 double[] getSolventGrid() {
893 return solventGrid;
894 }
895
896
897
898
899
900
901 void setLambdaTerm(boolean lambdaTerm) {
902 this.lambdaTerm = lambdaTerm;
903 }
904
905
906
907
908
909
910 SolventModel getSolventModel() {
911 return solventModel;
912 }
913
914
915
916
917 void setDefaultSolventAB() {
918 switch (solventModel) {
919 case BINARY ->
920
921 setSolventAB(1.0, 1.0);
922 case GAUSSIAN ->
923
924
925
926
927
928
929
930
931
932
933 setSolventAB(11.5, 0.55);
934 case POLYNOMIAL ->
935
936
937
938
939
940
941
942
943
944
945 setSolventAB(0.0, 0.8);
946 default -> {
947
948 }
949 }
950 }
951
952
953
954
955
956
957
958 void setSolventAB(double a, double b) {
959 double vdwr;
960 this.solventA = a;
961 this.solventB = b;
962 if (!solvent) {
963 return;
964 }
965 switch (solventModel) {
966 case BINARY:
967 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
968 for (int i = 0; i < nScatteringAtoms; i++) {
969 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
970 solventFormFactors[iSymm][i] = new SolventBinaryFormFactor(scatteringAtoms[i], vdwr + solventA);
971 }
972 }
973 break;
974 case GAUSSIAN:
975 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
976 for (int i = 0; i < nScatteringAtoms; i++) {
977 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
978 solventFormFactors[iSymm][i] = new SolventGaussFormFactor(scatteringAtoms[i], vdwr * solventB);
979 }
980 }
981 break;
982 case POLYNOMIAL:
983 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
984 for (int i = 0; i < nScatteringAtoms; i++) {
985 vdwr = scatteringAtoms[i].getVDWType().radius * 0.5;
986 solventFormFactors[iSymm][i] =
987 new SolventPolyFormFactor(scatteringAtoms[i], vdwr + solventA, solventB);
988 }
989 }
990 break;
991 }
992 }
993
994
995
996
997
998
999 double getSolventA() {
1000 return solventA;
1001 }
1002
1003
1004
1005
1006
1007
1008 double getSolventB() {
1009 return solventB;
1010 }
1011
1012
1013
1014
1015
1016
1017 void setUse3G(boolean useThreeGaussians) {
1018 this.useThreeGaussians = useThreeGaussians;
1019 if (solvent || neutron) {
1020 return;
1021 }
1022 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
1023 for (int i = 0; i < nScatteringAtoms; i++) {
1024 atomFormFactors[iSymm][i] = new XRayFormFactor(scatteringAtoms[i], useThreeGaussians, bAdd);
1025 }
1026 }
1027 }
1028
1029
1030
1031
1032
1033
1034
1035 void deltaX(int n, double delta) {
1036 List<SymOp> symops = crystal.spaceGroup.symOps;
1037 double[] xyz = new double[3];
1038 double[] symxyz = new double[3];
1039 scatteringAtoms[n].getXYZ(xyz);
1040 xyz[0] += delta;
1041 for (int i = 0; i < nSymm; i++) {
1042 crystal.applySymOp(xyz, symxyz, symops.get(i));
1043 coordinates[i][0][n] = symxyz[0];
1044 }
1045 }
1046
1047
1048
1049
1050
1051
1052
1053 void deltaY(int n, double delta) {
1054 List<SymOp> symops = crystal.spaceGroup.symOps;
1055 double[] xyz = new double[3];
1056 double[] symxyz = new double[3];
1057 scatteringAtoms[n].getXYZ(xyz);
1058 xyz[1] += delta;
1059 for (int i = 0; i < nSymm; i++) {
1060 crystal.applySymOp(xyz, symxyz, symops.get(i));
1061 coordinates[i][1][n] = symxyz[1];
1062 }
1063 }
1064
1065
1066
1067
1068
1069
1070
1071 void deltaZ(int n, double delta) {
1072 List<SymOp> symops = crystal.spaceGroup.symOps;
1073 double[] xyz = new double[3];
1074 double[] symxyz = new double[3];
1075 scatteringAtoms[n].getXYZ(xyz);
1076 xyz[2] += delta;
1077 for (int i = 0; i < nSymm; i++) {
1078 crystal.applySymOp(xyz, symxyz, symops.get(i));
1079 coordinates[i][2][n] = symxyz[2];
1080 }
1081 }
1082
1083
1084
1085
1086
1087
1088
1089 void computeDensity(double[][] hklData) {
1090 computeDensity(hklData, false);
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100 void computeDensity(double[][] hklData, boolean print) {
1101 if (solvent) {
1102 if (solventModel != SolventModel.NONE) {
1103 computeSolventDensity(hklData, print);
1104 }
1105 } else {
1106 computeAtomicDensity(hklData, print);
1107 }
1108 }
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121 void computeAtomicGradients(double[][] hklData, int[] freer, int flag,
1122 RefinementMode refinementMode, boolean print) {
1123
1124 if (solvent && solventModel == SolventModel.NONE) {
1125 return;
1126 }
1127
1128
1129 for (int i = 0; i < complexFFT3DSpace; i++) {
1130 densityGrid[i] = 0.0;
1131 }
1132
1133 int nfree = 0;
1134 StringBuilder sb = new StringBuilder();
1135 long symtime = -System.nanoTime();
1136 int nsym = crystal.spaceGroup.symOps.size();
1137
1138 List<SymOp> symops = crystal.spaceGroup.symOps;
1139 ComplexNumber c = new ComplexNumber();
1140 ComplexNumber cj = new ComplexNumber();
1141 HKL ij = new HKL();
1142 for (HKL ih : reflectionList.hklList) {
1143 double[] fc = hklData[ih.getIndex()];
1144 if (Double.isNaN(fc[0])) {
1145 continue;
1146 }
1147
1148
1149 if (freer != null) {
1150 if (freer[ih.getIndex()] == flag) {
1151 nfree++;
1152 continue;
1153 }
1154 }
1155
1156 c.re(fc[0]);
1157 c.im(fc[1]);
1158
1159 c.timesIP(2.0 / fftScale);
1160
1161
1162 for (int j = 0; j < nsym; j++) {
1163 cj.copy(c);
1164 SymOp symOp = symops.get(j);
1165 applyTransSymRot(ih, ij, symOp);
1166 double shift = symOp.symPhaseShift(ih);
1167
1168 int h = mod(ij.getH(), fftX);
1169 int k = mod(ij.getK(), fftY);
1170 int l = mod(ij.getL(), fftZ);
1171
1172 if (h < halfFFTX + 1) {
1173 final int ii = interleavedIndex(h, k, l, fftX, fftY);
1174 cj.phaseShiftIP(shift);
1175 densityGrid[ii] += cj.re();
1176
1177
1178 densityGrid[ii + 1] += (-cj.im());
1179 } else {
1180 h = (fftX - h) % fftX;
1181 k = (fftY - k) % fftY;
1182 l = (fftZ - l) % fftZ;
1183 final int ii = interleavedIndex(h, k, l, fftX, fftY);
1184 cj.phaseShiftIP(shift);
1185 densityGrid[ii] += cj.re();
1186 densityGrid[ii + 1] += cj.im();
1187 }
1188 }
1189 }
1190 symtime += System.nanoTime();
1191
1192 long startTime = System.nanoTime();
1193 complexFFT3D.ifft(densityGrid);
1194 long fftTime = System.nanoTime() - startTime;
1195
1196
1197
1198
1199
1200 startTime = System.nanoTime();
1201 long permanentDensityTime = 0;
1202 try {
1203 if (solvent) {
1204 solventGradientRegion.setRefinementMode(refinementMode);
1205 parallelTeam.execute(solventGradientRegion);
1206 } else {
1207 for (int i = 0; i < nScatteringAtoms; i++) {
1208 optAtomicGradientWeight.set(i, 0);
1209 }
1210 atomicGradientSchedule.updateWeights(previousOptAtomicGradientWeight);
1211 atomicGradientRegion.setRefinementMode(refinementMode);
1212 parallelTeam.execute(atomicGradientRegion);
1213 for (int i = 0; i < nScatteringAtoms; i++) {
1214 previousOptAtomicGradientWeight[i] = optAtomicGradientWeight.get(i);
1215 }
1216 }
1217 permanentDensityTime = System.nanoTime() - startTime;
1218 } catch (Exception e) {
1219 String message = "Exception computing atomic gradients.";
1220 logger.log(Level.SEVERE, message, e);
1221 }
1222
1223 if (solvent) {
1224 sb.append(format(" Solvent Symmetry: %8.4f\n", symtime * toSeconds));
1225 sb.append(format(" Solvent Inverse FFT: %8.4f\n", fftTime * toSeconds));
1226 sb.append(format(" Solvent Gradient from Grid: %8.4f", permanentDensityTime * toSeconds));
1227 } else {
1228 sb.append(format(" Atomic Symmetry: %8.4f\n", symtime * toSeconds));
1229 sb.append(format(" Atomic Inverse FFT: %8.4f\n", fftTime * toSeconds));
1230 sb.append(format(" Atomic Gradient from Grid: %8.4f", permanentDensityTime * toSeconds));
1231 }
1232
1233 if (logger.isLoggable(Level.INFO) && print) {
1234 logger.info(sb.toString());
1235 }
1236 }
1237
1238
1239
1240
1241
1242
1243
1244 void computeAtomicDensity(double[][] hklData) {
1245 computeAtomicDensity(hklData, false);
1246 }
1247
1248
1249
1250
1251
1252
1253
1254
1255 private void computeAtomicDensity(double[][] hklData, boolean print) {
1256
1257 long initTime = -System.nanoTime();
1258 try {
1259 initRegion.setHKL(hklData);
1260 parallelTeam.execute(initRegion);
1261 } catch (Exception e) {
1262 String message = "Fatal exception zeroing out reflection data.";
1263 logger.log(Level.SEVERE, message, e);
1264 }
1265 initTime += System.nanoTime();
1266
1267
1268 long atomicGridTime = -System.nanoTime();
1269 try {
1270 switch (gridMethod) {
1271 case SPATIAL:
1272 atomicDensityRegion.assignAtomsToCells();
1273 parallelTeam.execute(atomicDensityRegion);
1274 break;
1275 case ROW:
1276 for (int i = 0; i < fftZ * fftY; i++) {
1277 optRowWeightAtomic.set(i, 0);
1278 }
1279 atomicRowSchedule.updateWeights(previousOptRowWeightAtomic);
1280 parallelTeam.execute(atomicRowRegion);
1281 for (int i = 0; i < fftZ * fftY; i++) {
1282 previousOptRowWeightAtomic[i] = optRowWeightAtomic.get(i);
1283 }
1284 break;
1285 case SLICE:
1286 default:
1287 for (int i = 0; i < fftZ; i++) {
1288 optSliceWeightAtomic.set(i, 0);
1289 }
1290 atomicSliceSchedule.updateWeights(previousOptSliceWeightAtomic);
1291 parallelTeam.execute(atomicSliceRegion);
1292 for (int i = 0; i < fftZ; i++) {
1293 previousOptSliceWeightAtomic[i] = optSliceWeightAtomic.get(i);
1294 }
1295 break;
1296 }
1297 } catch (Exception e) {
1298 String message = "Fatal exception evaluating atomic electron density.";
1299 logger.log(Level.SEVERE, message, e);
1300 }
1301 atomicGridTime += System.nanoTime();
1302
1303
1304 long startTime = System.nanoTime();
1305 complexFFT3D.fft(densityGrid);
1306 long fftTime = System.nanoTime() - startTime;
1307
1308
1309 long symTime = -System.nanoTime();
1310 try {
1311 extractRegion.setHKL(hklData);
1312 parallelTeam.execute(extractRegion);
1313 double scale = (fftScale) / (fftX * fftY * fftZ);
1314 atomicScaleRegion.setHKL(hklData);
1315 atomicScaleRegion.setScale(scale);
1316 parallelTeam.execute(atomicScaleRegion);
1317 } catch (Exception e) {
1318 String message = "Fatal exception extracting structure factors.";
1319 logger.log(Level.SEVERE, message, e);
1320 }
1321 symTime += System.nanoTime();
1322
1323 if (logger.isLoggable(Level.INFO) && print) {
1324 StringBuilder sb = new StringBuilder();
1325 sb.append(format("\n Atomic Fc Initialization: %8.4f\n", initTime * toSeconds));
1326 sb.append(format(" Atomic Grid Density: %8.4f\n", atomicGridTime * toSeconds));
1327 sb.append(format(" Atomic FFT: %8.4f\n", fftTime * toSeconds));
1328 sb.append(format(" Atomic Symmetry & Scaling: %8.4f", symTime * toSeconds));
1329 logger.info(sb.toString());
1330
1331 StringBuilder ASB = new StringBuilder();
1332 switch (gridMethod) {
1333 case ROW:
1334 double atomicRowTotal = 0;
1335 double atomicRowMin = atomicRowLoops[0].getThreadTime();
1336 double atomicRowMax = 0;
1337 double atomicRowWeightTotal = 0;
1338
1339 for (int i = 0; i < threadCount; i++) {
1340 atomicRowTotal += atomicRowLoops[i].getThreadTime();
1341 atomicRowMax = max(atomicRowLoops[i].getThreadTime(), atomicRowMax);
1342 atomicRowMin = min(atomicRowLoops[i].getThreadTime(), atomicRowMin);
1343 atomicRowWeightTotal += atomicRowLoops[i].getThreadWeight();
1344 }
1345
1346
1347 ASB.append(format("\n RowLoop (Atomic): %7.5f (sec) | Total Weight: %7.0f\n",
1348 atomicGridTime * toSeconds, atomicRowWeightTotal));
1349 ASB.append(" Thread LoopTime Balance(%) Normalized | Rows Weight Balance(%) Normalized\n");
1350
1351
1352 if (atomicRowWeightTotal == 0) {
1353 atomicRowWeightTotal = 1;
1354 }
1355
1356 for (int i = 0; i < threadCount; i++) {
1357 ASB.append(
1358 format(
1359 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1360 i, atomicRowLoops[i].getThreadTime() * toSeconds,
1361 ((atomicRowLoops[i].getThreadTime()) / (atomicRowTotal)) * 100.00,
1362 ((atomicRowLoops[i].getThreadTime()) / (atomicRowTotal)) * (100.00
1363 * threadCount),
1364 atomicRowLoops[i].getNumberofSlices(),
1365 atomicRowLoops[i].getThreadWeight(),
1366 100.00 * (atomicRowLoops[i].getThreadWeight() / atomicRowWeightTotal),
1367 (100.00 * threadCount) * (atomicRowLoops[i].getThreadWeight()
1368 / atomicRowWeightTotal)));
1369 }
1370 ASB.append(format(" Min %7.5f\n", atomicRowMin * toSeconds));
1371 ASB.append(format(" Max %7.5f\n", atomicRowMax * toSeconds));
1372 ASB.append(format(" Delta %7.5f\n", (atomicRowMax - atomicRowMin) * toSeconds));
1373 logger.info(ASB.toString());
1374
1375 break;
1376 case SPATIAL:
1377 break;
1378 case SLICE:
1379 double atomicSliceTotal = 0;
1380 double atomicSliceMin = atomicSliceLoops[0].getThreadTime();
1381 double atomicSliceMax = 0;
1382 double atomicSliceWeightTotal = 0;
1383
1384 for (int i = 0; i < threadCount; i++) {
1385 atomicSliceTotal += atomicSliceLoops[i].getThreadTime();
1386 atomicSliceMax = max(atomicSliceLoops[i].getThreadTime(), atomicSliceMax);
1387 atomicSliceMin = min(atomicSliceLoops[i].getThreadTime(), atomicSliceMin);
1388 atomicSliceWeightTotal += atomicSliceLoops[i].getThreadWeight();
1389 }
1390
1391
1392 ASB.append(format("\n SliceLoop (Atomic): %7.5f (sec) | Total Weight: %7.0f\n",
1393 atomicGridTime * toSeconds, atomicSliceWeightTotal));
1394 ASB.append(" Thread LoopTime Balance(%) Normalized | Slices Weight Balance(%) Normalized\n");
1395
1396
1397 if (atomicSliceWeightTotal == 0) {
1398 atomicSliceWeightTotal = 1;
1399 }
1400
1401 for (int i = 0; i < threadCount; i++) {
1402 ASB.append(
1403 format(
1404 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1405 i,
1406 atomicSliceLoops[i].getThreadTime() * toSeconds,
1407 ((atomicSliceLoops[i].getThreadTime()) / (atomicSliceTotal)) * 100.00,
1408 ((atomicSliceLoops[i].getThreadTime()) / (atomicSliceTotal)) * (100.00
1409 * threadCount),
1410 atomicSliceLoops[i].getNumberofSlices(),
1411 atomicSliceLoops[i].getThreadWeight(),
1412 100.00 * (atomicSliceLoops[i].getThreadWeight() / atomicSliceWeightTotal),
1413 (100.00 * threadCount) * (atomicSliceLoops[i].getThreadWeight()
1414 / atomicSliceWeightTotal)));
1415 }
1416 ASB.append(format(" Min %7.5f\n", atomicSliceMin * toSeconds));
1417 ASB.append(format(" Max %7.5f\n", atomicSliceMax * toSeconds));
1418 ASB.append(format(" Delta %7.5f\n", (atomicSliceMax - atomicSliceMin) * toSeconds));
1419 logger.info(ASB.toString());
1420 break;
1421 default:
1422 }
1423 }
1424 }
1425
1426
1427
1428
1429
1430
1431
1432
1433 private void computeSolventDensity(double[][] hklData, boolean print) {
1434
1435 long initTime = -System.nanoTime();
1436 try {
1437 initRegion.setHKL(hklData);
1438 parallelTeam.execute(initRegion);
1439 } catch (Exception e) {
1440 String message = "Fatal exception initializing structure factors.";
1441 logger.log(Level.SEVERE, message, e);
1442 }
1443 initTime += System.nanoTime();
1444
1445 long solventGridTime = -System.nanoTime();
1446 try {
1447 switch (gridMethod) {
1448 case SPATIAL:
1449 atomicDensityRegion.assignAtomsToCells();
1450 parallelTeam.execute(atomicDensityRegion);
1451 break;
1452 case ROW:
1453 for (int i = 0; i < fftZ * fftY; i++) {
1454 optRowWeightSolvent.set(i, 0);
1455 }
1456 solventRowSchedule.updateWeights(previousOptRowWeightSolvent);
1457 parallelTeam.execute(atomicRowRegion);
1458 for (int i = 0; i < fftZ * fftY; i++) {
1459 previousOptRowWeightSolvent[i] = optRowWeightSolvent.get(i);
1460 }
1461 break;
1462 case SLICE:
1463 default:
1464 for (int i = 0; i < fftZ; i++) {
1465 optSliceWeightSolvent.set(i, 0);
1466 }
1467 solventSliceSchedule.updateWeights(previousOptSliceWeightSolvent);
1468 parallelTeam.execute(atomicSliceRegion);
1469 for (int i = 0; i < fftZ; i++) {
1470 previousOptSliceWeightSolvent[i] = optSliceWeightSolvent.get(i);
1471 }
1472 break;
1473 }
1474 } catch (Exception e) {
1475 String message = "Fatal exception evaluating solvent electron density.";
1476 logger.log(Level.SEVERE, message, e);
1477 }
1478 solventGridTime += System.nanoTime();
1479
1480 long expTime = -System.nanoTime();
1481 if (solventModel == SolventModel.BINARY) {
1482
1483
1484
1485
1486 int nmap = densityGrid.length;
1487 arraycopy(densityGrid, 0, solventGrid, 0, nmap);
1488
1489 double[] xyz = {solventB, solventB, solventB};
1490 double[] uvw = new double[3];
1491 crystal.toFractionalCoordinates(xyz, uvw);
1492 final double frx = fftX * uvw[0];
1493 final int ifrx = (int) frx;
1494 final double fry = fftY * uvw[1];
1495 final int ifry = (int) fry;
1496 final double frz = fftZ * uvw[2];
1497 final int ifrz = (int) frz;
1498 for (int k = 0; k < fftZ; k++) {
1499 for (int j = 0; j < fftY; j++) {
1500 for (int i = 0; i < fftX; i++) {
1501 final int ii = interleavedIndex(i, j, k, fftX, fftY);
1502 if (densityGrid[ii] == 1.0) {
1503 continue;
1504 }
1505 outerLoop:
1506 for (int iz = k - ifrz; iz <= k + ifrz; iz++) {
1507 int giz = mod(iz, fftZ);
1508 for (int iy = j - ifry; iy <= j + ifry; iy++) {
1509 int giy = mod(iy, fftY);
1510 for (int ix = i - ifrx; ix <= i + ifrx; ix++) {
1511 int gix = mod(ix, fftX);
1512 final int jj = interleavedIndex(gix, giy, giz, fftX, fftY);
1513 if (densityGrid[jj] == 1.0) {
1514 solventGrid[ii] = 1.0;
1515 break outerLoop;
1516 }
1517 }
1518 }
1519 }
1520 }
1521 }
1522 }
1523
1524
1525 arraycopy(solventGrid, 0, densityGrid, 0, nmap);
1526 }
1527
1528
1529 ArrayCopyRegion arrayCopyRegion = new ArrayCopyRegion();
1530 try {
1531 parallelTeam.execute(arrayCopyRegion);
1532 } catch (Exception e) {
1533 logger.info(e.toString());
1534 }
1535
1536
1537 try {
1538 parallelTeam.execute(babinetRegion);
1539 } catch (Exception e) {
1540 String message = "Fatal exception Babinet Principle.";
1541 logger.log(Level.SEVERE, message, e);
1542 }
1543 expTime += System.nanoTime();
1544
1545 long fftTime = -System.nanoTime();
1546 complexFFT3D.fft(densityGrid);
1547 fftTime += System.nanoTime();
1548
1549
1550 long symTime = -System.nanoTime();
1551 try {
1552 extractRegion.setHKL(hklData);
1553 parallelTeam.execute(extractRegion);
1554 final double scale = (fftScale) / (fftX * fftY * fftZ);
1555 solventScaleRegion.setHKL(hklData);
1556 solventScaleRegion.setScale(scale);
1557 parallelTeam.execute(solventScaleRegion);
1558 } catch (Exception e) {
1559 String message = "Fatal exception extracting structure factors.";
1560 logger.log(Level.SEVERE, message, e);
1561 }
1562 symTime += System.nanoTime();
1563
1564
1565 long solventDensityTime = -System.nanoTime();
1566 try {
1567 switch (gridMethod) {
1568 case SPATIAL:
1569 solventDensityRegion.assignAtomsToCells();
1570 parallelTeam.execute(solventDensityRegion);
1571 break;
1572
1573 case ROW:
1574 for (int i = 0; i < (fftZ * fftY); i++) {
1575 optRowWeightBulkSolvent.set(i, 0);
1576 }
1577 bulkSolventRowSchedule.updateWeights(previousOptRowWeightBulkSolvent);
1578 parallelTeam.execute(solventRowRegion);
1579 for (int i = 0; i < fftZ * fftY; i++) {
1580 previousOptRowWeightBulkSolvent[i] = optRowWeightBulkSolvent.get(i);
1581 }
1582 break;
1583 case SLICE:
1584 default:
1585 for (int i = 0; i < (fftZ); i++) {
1586 optSliceWeightBulkSolvent.set(i, 0);
1587 }
1588
1589 bulkSolventSliceSchedule.updateWeights(previousOptSliceWeightBulkSolvent);
1590 parallelTeam.execute(solventSliceRegion);
1591 for (int i = 0; i < fftZ; i++) {
1592 previousOptSliceWeightBulkSolvent[i] = optSliceWeightBulkSolvent.get(i);
1593 }
1594 break;
1595 }
1596 } catch (Exception e) {
1597 String message = "Fatal exception evaluating solvent electron density.";
1598 logger.log(Level.SEVERE, message, e);
1599 }
1600 solventDensityTime += System.nanoTime();
1601
1602 long solventExpTime = 0;
1603 if (solventModel == SolventModel.GAUSSIAN) {
1604 solventExpTime = -System.nanoTime();
1605 try {
1606 parallelTeam.execute(solventGridRegion);
1607 } catch (Exception e) {
1608 String message = "Fatal exception solvent grid region.";
1609 logger.log(Level.SEVERE, message, e);
1610 }
1611 solventExpTime += System.nanoTime();
1612 }
1613
1614 if (logger.isLoggable(Level.INFO) && print) {
1615 StringBuilder sb = new StringBuilder();
1616 sb.append(format(" Solvent Fc Initialization: %8.4f\n", initTime * toSeconds));
1617 sb.append(format(" Solvent Grid Density: %8.4f\n", solventGridTime * toSeconds));
1618 sb.append(format(" Bulk Solvent Exponentiation: %8.4f\n", expTime * toSeconds));
1619 sb.append(format(" Solvent FFT: %8.4f\n", fftTime * toSeconds));
1620 sb.append(format(" Solvent Symmetry & Scaling: %8.4f\n", symTime * toSeconds));
1621 sb.append(format(" Solvent Grid Expansion: %8.4f", solventDensityTime * toSeconds));
1622
1623 if (solventModel == SolventModel.GAUSSIAN) {
1624 sb.append(format("\n Gaussian grid exponentiation:%8.4f", solventExpTime * toSeconds));
1625 }
1626 logger.info(sb.toString());
1627 StringBuilder solventSB = new StringBuilder();
1628 StringBuilder bulkSB = new StringBuilder();
1629 switch (gridMethod) {
1630 case ROW:
1631 double solventRowTotal = 0;
1632 double solventRowMin = solventRowLoops[0].getThreadTime();
1633 double solventRowMax = 0;
1634 double solventRowWeightTotal = 0;
1635
1636 double bulkSolventRowTotal = 0;
1637 double bulkSolventRowMin = bulkSolventRowLoops[0].getTimePerThread();
1638 double bulkSolventRowMax = 0;
1639 double bulkSolventRowWeightTotal = 0;
1640
1641 for (int i = 0; i < threadCount; i++) {
1642 solventRowTotal += solventRowLoops[i].getThreadTime();
1643 solventRowMax = max(solventRowLoops[i].getThreadTime(), solventRowMax);
1644 solventRowMin = min(solventRowLoops[i].getThreadTime(), solventRowMin);
1645 solventRowWeightTotal += solventRowLoops[i].getThreadWeight();
1646
1647 bulkSolventRowTotal += bulkSolventRowLoops[i].getTimePerThread();
1648 bulkSolventRowMax = max(bulkSolventRowLoops[i].getTimePerThread(), bulkSolventRowMax);
1649 bulkSolventRowMin = min(bulkSolventRowLoops[i].getTimePerThread(), bulkSolventRowMin);
1650 bulkSolventRowWeightTotal += bulkSolventRowLoops[i].getWeightPerThread()[i];
1651 }
1652
1653
1654 solventSB.append(format("\n RowLoop (Solvent): %7.5f (sec) | Total Weight: %7.0f\n",
1655 solventGridTime * toSeconds, solventRowWeightTotal));
1656 solventSB.append(" Thread LoopTime Balance(%) Normalized | Rows Weight Balance(%) Normalized\n");
1657
1658
1659 if (solventRowWeightTotal == 0) {
1660 solventRowWeightTotal = 1;
1661 }
1662
1663 for (int i = 0; i < threadCount; i++) {
1664 solventSB.append(
1665 format(
1666 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1667 i, solventRowLoops[i].getThreadTime() * toSeconds,
1668 ((solventRowLoops[i].getThreadTime()) / (solventRowTotal)) * 100.00,
1669 ((solventRowLoops[i].getThreadTime()) / (solventRowTotal))
1670 * (100.00 * threadCount),
1671 solventRowLoops[i].getNumberofSlices(),
1672 solventRowLoops[i].getThreadWeight(),
1673 100.00 * (solventRowLoops[i].getThreadWeight() / solventRowWeightTotal),
1674 (100.00 * threadCount)
1675 * (solventRowLoops[i].getThreadWeight() / solventRowWeightTotal)));
1676 }
1677 solventSB.append(format(" Min %7.5f\n", solventRowMin * toSeconds));
1678 solventSB.append(format(" Max %7.5f\n", solventRowMax * toSeconds));
1679 solventSB.append(format(" Delta %7.5f\n", (solventRowMax - solventRowMin) * toSeconds));
1680 logger.info(solventSB.toString());
1681
1682
1683 bulkSB.append(format("\n RowLoop (Bulk Solvent): %7.5f (sec) | Total Weight: %7.0f\n",
1684 bulkSolventRowTotal * toSeconds, bulkSolventRowWeightTotal));
1685 bulkSB.append(" Thread LoopTime Balance(%) Normalized | Rows Weight Balance(%) Normalized\n");
1686
1687
1688 if (bulkSolventRowWeightTotal == 0) {
1689 bulkSolventRowWeightTotal = 1;
1690 }
1691
1692 for (int i = 0; i < threadCount; i++) {
1693 bulkSB.append(
1694 format(
1695 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1696 i, bulkSolventRowLoops[i].getTimePerThread() * toSeconds,
1697 ((bulkSolventRowLoops[i].getTimePerThread()) / (bulkSolventRowTotal)) * 100.00,
1698 ((bulkSolventRowLoops[i].getTimePerThread()) / (bulkSolventRowTotal))
1699 * (100.00 * threadCount),
1700 bulkSolventRowLoops[i].getBoundsPerThread()[i],
1701 bulkSolventRowLoops[i].getWeightPerThread()[i],
1702 100.00
1703 * (bulkSolventRowLoops[i].getWeightPerThread()[i]
1704 / bulkSolventRowWeightTotal),
1705 (100.00 * threadCount)
1706 * (bulkSolventRowLoops[i].getWeightPerThread()[i]
1707 / bulkSolventRowWeightTotal)));
1708 }
1709 bulkSB.append(format(" Min %7.5f\n", bulkSolventRowMin * toSeconds));
1710 bulkSB.append(format(" Max %7.5f\n", bulkSolventRowMax * toSeconds));
1711 bulkSB.append(format(" Delta %7.5f\n", (bulkSolventRowMax - bulkSolventRowMin) * toSeconds));
1712 logger.info(bulkSB.toString());
1713 break;
1714 case SPATIAL:
1715 break;
1716 case SLICE:
1717 double solventSliceTotal = 0;
1718 double solventSliceMin = solventSliceLoops[0].getThreadTime();
1719 double solventSliceMax = 0;
1720 double solventSliceWeightTotal = 0;
1721
1722 double bulkSolventSliceTotal = 0;
1723 double bulkSolventSliceMin = bulkSolventSliceLoops[0].getTimePerThread();
1724 double bulkSolventSliceMax = 0;
1725 double bulkSolventSliceWeightTotal = 0;
1726
1727 for (int i = 0; i < threadCount; i++) {
1728 solventSliceTotal += solventSliceLoops[i].getThreadTime();
1729 solventSliceMax = max(solventSliceLoops[i].getThreadTime(), solventSliceMax);
1730 solventSliceMin = min(solventSliceLoops[i].getThreadTime(), solventSliceMin);
1731 solventSliceWeightTotal += solventSliceLoops[i].getThreadWeight();
1732
1733 bulkSolventSliceTotal += bulkSolventSliceLoops[i].getTimePerThread();
1734 bulkSolventSliceMax =
1735 max(bulkSolventSliceLoops[i].getTimePerThread(), bulkSolventSliceMax);
1736 bulkSolventSliceMin =
1737 min(bulkSolventSliceLoops[i].getTimePerThread(), bulkSolventSliceMin);
1738 bulkSolventSliceWeightTotal += bulkSolventSliceLoops[i].getWeightPerThread()[i];
1739 }
1740
1741
1742 solventSB.append(format("\n SliceLoop (Solvent): %7.5f (sec) | Total Weight: %7.0f\n",
1743 solventGridTime * toSeconds, solventSliceWeightTotal));
1744 solventSB.append(" Thread LoopTime Balance(%) Normalized | Slices Weight Balance(%) Normalized\n");
1745
1746
1747 if (solventSliceWeightTotal == 0) {
1748 solventSliceWeightTotal = 1;
1749 }
1750
1751 for (int i = 0; i < threadCount; i++) {
1752 solventSB.append(
1753 format(
1754 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1755 i, solventSliceLoops[i].getThreadTime() * toSeconds,
1756 ((solventSliceLoops[i].getThreadTime()) / (solventSliceTotal)) * 100.00,
1757 ((solventSliceLoops[i].getThreadTime()) / (solventSliceTotal))
1758 * (100.00 * threadCount),
1759 solventSliceLoops[i].getNumberofSlices(),
1760 solventSliceLoops[i].getThreadWeight(),
1761 100.00 * (solventSliceLoops[i].getThreadWeight() / solventSliceWeightTotal),
1762 (100.00 * threadCount)
1763 * (solventSliceLoops[i].getThreadWeight() / solventSliceWeightTotal)));
1764 }
1765 solventSB.append(format(" Min %7.5f\n", solventSliceMin * toSeconds));
1766 solventSB.append(format(" Max %7.5f\n", solventSliceMax * toSeconds));
1767 solventSB.append(format(" Delta %7.5f\n", (solventSliceMax - solventSliceMin) * toSeconds));
1768 logger.info(solventSB.toString());
1769
1770
1771 bulkSB.append(format(" SliceLoop (Bulk Solvent): %7.5f (sec) | Total Weight: %7.0f\n",
1772 bulkSolventSliceTotal * toSeconds, bulkSolventSliceWeightTotal));
1773 bulkSB.append(" Thread LoopTime Balance(%) Normalized | Slices Weight Balance(%) Normalized\n");
1774
1775
1776 if (bulkSolventSliceWeightTotal == 0) {
1777 bulkSolventSliceWeightTotal = 1;
1778 }
1779
1780 for (int i = 0; i < threadCount; i++) {
1781 bulkSB.append(
1782 format(
1783 " %3d %7.5f %7.1f %7.1f | %7d %7d %7.1f %7.1f\n",
1784 i, bulkSolventSliceLoops[i].getTimePerThread() * toSeconds,
1785 ((bulkSolventSliceLoops[i].getTimePerThread()) / (bulkSolventSliceTotal))
1786 * 100.00,
1787 ((bulkSolventSliceLoops[i].getTimePerThread()) / (bulkSolventSliceTotal))
1788 * (100.00 * threadCount),
1789 bulkSolventSliceLoops[i].getBoundsPerThread()[i],
1790 bulkSolventSliceLoops[i].getWeightPerThread()[i],
1791 100.00
1792 * (bulkSolventSliceLoops[i].getWeightPerThread()[i]
1793 / bulkSolventSliceWeightTotal),
1794 (100.00 * threadCount)
1795 * (bulkSolventSliceLoops[i].getWeightPerThread()[i]
1796 / bulkSolventSliceWeightTotal)));
1797 }
1798 bulkSB.append(format(" Min %7.5f\n", bulkSolventSliceMin * toSeconds));
1799 bulkSB.append(format(" Max %7.5f\n", bulkSolventSliceMax * toSeconds));
1800 bulkSB.append(format(" Delta %7.5f\n", (bulkSolventSliceMax - bulkSolventSliceMin) * toSeconds));
1801 logger.info(bulkSB.toString());
1802 break;
1803 default:
1804 }
1805 }
1806 }
1807
1808 private class AtomicDensityLoop extends SpatialDensityLoop {
1809
1810 final double[] xyz = new double[3];
1811 final double[] uvw = new double[3];
1812 final double[] xc = new double[3];
1813 final double[] xf = new double[3];
1814 final double[] grid;
1815
1816 AtomicDensityLoop(SpatialDensityRegion region) {
1817 super(region, region.getNsymm(), region.actualCount);
1818 grid = region.getGrid();
1819 }
1820
1821 @Override
1822 public void gridDensity(int iSymm, int n) {
1823 if (!scatteringAtoms[n].getUse() && !nativeEnvironmentApproximation) {
1824 return;
1825 }
1826
1827 if (lambdaTerm && scatteringAtoms[n].applyLambda()) {
1828 return;
1829 }
1830
1831 xyz[0] = coordinates[iSymm][0][n];
1832 xyz[1] = coordinates[iSymm][1][n];
1833 xyz[2] = coordinates[iSymm][2][n];
1834 FormFactor atomff = atomFormFactors[iSymm][n];
1835 crystal.toFractionalCoordinates(xyz, uvw);
1836 final int frad = Math.min(
1837 aRadGrid, (int) Math.floor(scatteringAtoms[n].getFormFactorWidth() * fftX / crystal.a) + 1);
1838
1839
1840 final double frx = fftX * uvw[0];
1841 final int ifrx = (int) frx;
1842 final int ifrxu = ifrx + frad;
1843
1844 final double fry = fftY * uvw[1];
1845 final int ifry = (int) fry;
1846 final int ifryu = ifry + frad;
1847
1848 final double frz = fftZ * uvw[2];
1849 final int ifrz = (int) frz;
1850 final int ifrzu = ifrz + frad;
1851
1852 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
1853 int giz = mod(iz, fftZ);
1854 xf[2] = iz * ifftZ;
1855 for (int iy = ifry - frad; iy <= ifryu; iy++) {
1856 int giy = mod(iy, fftY);
1857 xf[1] = iy * ifftY;
1858 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
1859 int gix = mod(ix, fftX);
1860 xf[0] = ix * ifftX;
1861 crystal.toCartesianCoordinates(xf, xc);
1862 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
1863 grid[ii] = atomff.rho(grid[ii], 1.0, xc);
1864 }
1865 }
1866 }
1867 }
1868 }
1869
1870 private class SolventDensityLoop extends SpatialDensityLoop {
1871
1872 final double[] xyz = new double[3];
1873 final double[] uvw = new double[3];
1874 final double[] xc = new double[3];
1875 final double[] xf = new double[3];
1876 final double[] grid;
1877
1878 SolventDensityLoop(SpatialDensityRegion region) {
1879 super(region, region.getNsymm(), region.actualCount);
1880 grid = region.getGrid();
1881 }
1882
1883 @Override
1884 public void gridDensity(int iSymm, int n) {
1885 if (!scatteringAtoms[n].getUse() && !nativeEnvironmentApproximation) {
1886 return;
1887 }
1888
1889 if (lambdaTerm && scatteringAtoms[n].applyLambda()) {
1890 return;
1891 }
1892
1893 xyz[0] = coordinates[iSymm][0][n];
1894 xyz[1] = coordinates[iSymm][1][n];
1895 xyz[2] = coordinates[iSymm][2][n];
1896 FormFactor solventff = solventFormFactors[iSymm][n];
1897 crystal.toFractionalCoordinates(xyz, uvw);
1898 double vdwr = scatteringAtoms[n].getVDWType().radius * 0.5;
1899 int frad = aRadGrid;
1900 switch (solventModel) {
1901 case BINARY:
1902 frad =
1903 Math.min(aRadGrid, (int) Math.floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
1904 break;
1905 case GAUSSIAN:
1906 frad =
1907 Math.min(aRadGrid, (int) Math.floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
1908 break;
1909 case POLYNOMIAL:
1910 frad =
1911 Math.min(aRadGrid, (int) Math.floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
1912 break;
1913 case NONE:
1914 default:
1915 return;
1916 }
1917
1918
1919 final double frx = fftX * uvw[0];
1920 final int ifrx = (int) frx;
1921 final int ifrxu = ifrx + frad;
1922
1923 final double fry = fftY * uvw[1];
1924 final int ifry = (int) fry;
1925 final int ifryu = ifry + frad;
1926
1927 final double frz = fftZ * uvw[2];
1928 final int ifrz = (int) frz;
1929 final int ifrzu = ifrz + frad;
1930
1931 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
1932 int giz = mod(iz, fftZ);
1933 xf[2] = iz * ifftZ;
1934 for (int iy = ifry - frad; iy <= ifryu; iy++) {
1935 int giy = mod(iy, fftY);
1936 xf[1] = iy * ifftY;
1937 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
1938 int gix = mod(ix, fftX);
1939 xf[0] = ix * ifftX;
1940 crystal.toCartesianCoordinates(xf, xc);
1941 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
1942 grid[ii] = solventff.rho(grid[ii], 1.0, xc);
1943 }
1944 }
1945 }
1946 }
1947 }
1948
1949 private class AtomicRowLoop extends RowLoop {
1950
1951 final double[] xyz = new double[3];
1952 final double[] uvw = new double[3];
1953 final double[] xc = new double[3];
1954 final double[] xf = new double[3];
1955 final double[] grid;
1956 final int[] optLocal;
1957 long timer;
1958 int previousUB, previousLB;
1959 int actualWeight;
1960
1961 AtomicRowLoop(RowRegion region) {
1962 super(region.getNatoms(), region.getNsymm(), region);
1963 grid = region.getGrid();
1964 optLocal = new int[fftZ * fftY];
1965 }
1966
1967 public void buildList(int iSymm, int iAtom, int lb, int ub) {
1968 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
1969 return;
1970 }
1971 xyz[0] = coordinates[iSymm][0][iAtom];
1972 xyz[1] = coordinates[iSymm][1][iAtom];
1973 xyz[2] = coordinates[iSymm][2][iAtom];
1974 crystal.toFractionalCoordinates(xyz, uvw);
1975 final int frad =
1976 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
1977
1978 final double frz = fftZ * uvw[2];
1979 final int ifrz = (int) frz;
1980 final int ifrzu = ifrz + frad;
1981 final int ifrzl = ifrz - frad;
1982
1983 final double fry = fftY * uvw[1];
1984 final int ifry = (int) fry;
1985 final int ifryu = ifry + frad;
1986 final int ifryl = ifry - frad;
1987
1988
1989
1990
1991 int buff = bufferSize;
1992
1993 int lbZ = rowRegion.zFromRowIndex(lb);
1994 int ubZ = rowRegion.zFromRowIndex(ub);
1995
1996 for (int iz = ifrzl - buff; iz <= ifrzu + buff; iz++) {
1997 int giz = mod(iz, fftZ);
1998 if (lbZ > giz || giz > ubZ) {
1999 continue;
2000 }
2001 int rowLB = rowRegion.rowIndexForYZ(mod(ifryl - buff, fftY), giz);
2002 int rowUB = rowRegion.rowIndexForYZ(mod(ifryu + buff, fftY), giz);
2003 if (lb >= rowLB || rowUB <= ub) {
2004 buildListA.add(iAtom);
2005 buildListS.add(iSymm);
2006 break;
2007 }
2008 }
2009 }
2010
2011 @Override
2012 public boolean checkList(int[][][] zyAtListBuild, int buff) {
2013 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2014 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2015 if (rowRegion.select[iSymm][iAtom]) {
2016 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2017 continue;
2018 }
2019 xyz[0] = coordinates[iSymm][0][iAtom];
2020 xyz[1] = coordinates[iSymm][1][iAtom];
2021 xyz[2] = coordinates[iSymm][2][iAtom];
2022 crystal.toFractionalCoordinates(xyz, uvw);
2023 final double frz = fftZ * uvw[2];
2024 final int ifrz = (int) frz;
2025 final int previousZ = zyAtListBuild[iSymm][iAtom][0];
2026
2027 final double fry = fftY * uvw[1];
2028 final int ifry = (int) fry;
2029 final int previousY = zyAtListBuild[iSymm][iAtom][1];
2030 if (abs(ifrz - previousZ) >= buff || abs(ifry - previousY) >= buff) {
2031 return true;
2032 }
2033 }
2034 }
2035 }
2036 return false;
2037 }
2038
2039 @Override
2040 public void finish() {
2041 for (int i = 0; i < fftZ * fftY; i++) {
2042 optRowWeightAtomic.addAndGet(i, optLocal[i]);
2043 }
2044 timer += System.nanoTime();
2045 }
2046
2047 @Override
2048 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
2049 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2050 return;
2051 }
2052
2053 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
2054 return;
2055 }
2056
2057 int lbZ = rowRegion.zFromRowIndex(lb);
2058 int ubZ = rowRegion.zFromRowIndex(ub);
2059
2060 xyz[0] = coordinates[iSymm][0][iAtom];
2061 xyz[1] = coordinates[iSymm][1][iAtom];
2062 xyz[2] = coordinates[iSymm][2][iAtom];
2063 FormFactor atomff = atomFormFactors[iSymm][iAtom];
2064 crystal.toFractionalCoordinates(xyz, uvw);
2065 final int frad =
2066 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
2067
2068
2069 final double frx = fftX * uvw[0];
2070 final int ifrx = (int) frx;
2071 final int ifrxu = ifrx + frad;
2072
2073 final double fry = fftY * uvw[1];
2074 final int ifry = (int) fry;
2075 final int ifryu = ifry + frad;
2076
2077 final double frz = fftZ * uvw[2];
2078 final int ifrz = (int) frz;
2079 final int ifrzu = ifrz + frad;
2080
2081 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
2082 int giz = mod(iz, fftZ);
2083 if (lbZ > giz || giz > ubZ) {
2084 continue;
2085 }
2086 xf[2] = iz * ifftZ;
2087 for (int iy = ifry - frad; iy <= ifryu; iy++) {
2088 int giy = mod(iy, fftY);
2089 int rowIndex = rowRegion.rowIndexForYZ(giy, giz);
2090 if (lb > rowIndex || rowIndex > ub) {
2091 continue;
2092 }
2093 xf[1] = iy * ifftY;
2094 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
2095 int gix = mod(ix, fftX);
2096 xf[0] = ix * ifftX;
2097 crystal.toCartesianCoordinates(xf, xc);
2098 optLocal[rowIndex]++;
2099 actualWeight++;
2100 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
2101 grid[ii] = atomff.rho(grid[ii], 1.0, xc);
2102 }
2103 }
2104 }
2105 }
2106
2107 @Override
2108 public void run(int lb, int ub) throws Exception {
2109 boolean boundsChange = false;
2110 if (previousLB != lb || previousUB != ub) {
2111 boundsChange = true;
2112 }
2113 previousLB = lb;
2114 previousUB = ub;
2115 if (rebuildList || boundsChange) {
2116 buildListA = new ArrayList<>();
2117 buildListS = new ArrayList<>();
2118 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2119 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2120 if (rowRegion.select[iSymm][iAtom]) {
2121 buildList(iSymm, iAtom, lb, ub);
2122 }
2123 }
2124 }
2125 }
2126 for (int i = 0; i < buildListA.size(); i++) {
2127 if (rowRegion.select[buildListS.get(i)][buildListA.get(i)]) {
2128 gridDensity(buildListS.get(i), buildListA.get(i), lb, ub);
2129 }
2130 }
2131 }
2132
2133 @Override
2134 public void saveZYValues(int[][][] zyAtListBuild) {
2135 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2136 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2137 zyAtListBuild[iSymm][iAtom][0] = 0;
2138 zyAtListBuild[iSymm][iAtom][1] = 0;
2139 if (rowRegion.select[iSymm][iAtom]) {
2140 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2141 continue;
2142 }
2143 xyz[0] = coordinates[iSymm][0][iAtom];
2144 xyz[1] = coordinates[iSymm][1][iAtom];
2145 xyz[2] = coordinates[iSymm][2][iAtom];
2146 crystal.toFractionalCoordinates(xyz, uvw);
2147 final double frz = fftZ * uvw[2];
2148 final int ifrz = (int) frz;
2149
2150 final double fry = fftY * uvw[1];
2151 final int ifry = (int) fry;
2152 zyAtListBuild[iSymm][iAtom][0] = ifrz;
2153 zyAtListBuild[iSymm][iAtom][1] = ifry;
2154 }
2155 }
2156 }
2157 }
2158
2159 @Override
2160 public IntegerSchedule schedule() {
2161 return atomicRowSchedule;
2162 }
2163
2164 @Override
2165 public void start() {
2166 fill(optLocal, 0);
2167 actualWeight = 0;
2168 timer = -System.nanoTime();
2169 }
2170
2171 double getThreadTime() {
2172 return timer;
2173 }
2174
2175 int getNumberofSlices() {
2176 return (previousUB - previousLB + 1);
2177 }
2178
2179 int getThreadWeight() {
2180 return actualWeight;
2181 }
2182 }
2183
2184 private class SolventRowLoop extends RowLoop {
2185
2186 final double[] xyz = new double[3];
2187 final double[] uvw = new double[3];
2188 final double[] xc = new double[3];
2189 final double[] xf = new double[3];
2190 final double[] grid;
2191 final int[] optLocal;
2192 long timer;
2193 int previousUB, previousLB;
2194 int actualWeight;
2195
2196 public SolventRowLoop(RowRegion region) {
2197 super(region.getNatoms(), region.getNsymm(), region);
2198 grid = region.getGrid();
2199 optLocal = new int[fftZ * fftY];
2200 }
2201
2202 public void buildList(int iSymm, int iAtom, int lb, int ub) {
2203 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2204 return;
2205 }
2206 xyz[0] = coordinates[iSymm][0][iAtom];
2207 xyz[1] = coordinates[iSymm][1][iAtom];
2208 xyz[2] = coordinates[iSymm][2][iAtom];
2209 crystal.toFractionalCoordinates(xyz, uvw);
2210 final int frad =
2211 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
2212
2213 final double frz = fftZ * uvw[2];
2214 final int ifrz = (int) frz;
2215 final int ifrzu = ifrz + frad;
2216 final int ifrzl = ifrz - frad;
2217
2218 final double fry = fftY * uvw[1];
2219 final int ifry = (int) fry;
2220 final int ifryu = ifry + frad;
2221 final int ifryl = ifry - frad;
2222
2223
2224
2225
2226 int buff = bufferSize;
2227
2228 int lbZ = rowRegion.zFromRowIndex(lb);
2229 int ubZ = rowRegion.zFromRowIndex(ub);
2230
2231 for (int iz = ifrzl - buff; iz <= ifrzu + buff; iz++) {
2232 int giz = mod(iz, fftZ);
2233 if (lbZ > giz || giz > ubZ) {
2234 continue;
2235 }
2236 int rowLB = rowRegion.rowIndexForYZ(mod(ifryl - buff, fftY), giz);
2237 int rowUB = rowRegion.rowIndexForYZ(mod(ifryu + buff, fftY), giz);
2238 if (lb >= rowLB || rowUB <= ub) {
2239 buildListA.add(iAtom);
2240 buildListS.add(iSymm);
2241 break;
2242 }
2243 }
2244 }
2245
2246 @Override
2247 public boolean checkList(int[][][] zyAtListBuild, int buff) {
2248 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2249 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2250 if (rowRegion.select[iSymm][iAtom]) {
2251 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2252 continue;
2253 }
2254 xyz[0] = coordinates[iSymm][0][iAtom];
2255 xyz[1] = coordinates[iSymm][1][iAtom];
2256 xyz[2] = coordinates[iSymm][2][iAtom];
2257 crystal.toFractionalCoordinates(xyz, uvw);
2258 final double frz = fftZ * uvw[2];
2259 final int ifrz = (int) frz;
2260 final int previousZ = zyAtListBuild[iSymm][iAtom][0];
2261
2262 final double fry = fftY * uvw[1];
2263 final int ifry = (int) fry;
2264 final int previousY = zyAtListBuild[iSymm][iAtom][1];
2265 if (abs(ifrz - previousZ) >= buff || abs(ifry - previousY) >= buff) {
2266 return true;
2267 }
2268 }
2269 }
2270 }
2271 return false;
2272 }
2273
2274 @Override
2275 public void finish() {
2276 timer += System.nanoTime();
2277 for (int i = 0; i < fftZ * fftY; i++) {
2278 optRowWeightSolvent.addAndGet(i, optLocal[i]);
2279 }
2280 }
2281
2282 public int getNumberofSlices() {
2283 return (previousUB - previousLB + 1);
2284 }
2285
2286 public double getThreadTime() {
2287 return timer;
2288 }
2289
2290 public int getThreadWeight() {
2291 return actualWeight;
2292 }
2293
2294 @Override
2295 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
2296
2297 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2298 return;
2299 }
2300
2301 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
2302 return;
2303 }
2304
2305 xyz[0] = coordinates[iSymm][0][iAtom];
2306 xyz[1] = coordinates[iSymm][1][iAtom];
2307 xyz[2] = coordinates[iSymm][2][iAtom];
2308 FormFactor formFactor = solventFormFactors[iSymm][iAtom];
2309 crystal.toFractionalCoordinates(xyz, uvw);
2310 double vdwr = scatteringAtoms[iAtom].getVDWType().radius * 0.5;
2311 int frad = aRadGrid;
2312 switch (solventModel) {
2313 case BINARY:
2314 frad = min(aRadGrid, (int) floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
2315 break;
2316 case GAUSSIAN:
2317 frad = min(aRadGrid, (int) floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
2318 break;
2319 case POLYNOMIAL:
2320 frad = min(aRadGrid, (int) floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
2321 break;
2322 case NONE:
2323 default:
2324 return;
2325 }
2326
2327 int ubZ = rowRegion.zFromRowIndex(ub);
2328 int lbZ = rowRegion.zFromRowIndex(lb);
2329
2330
2331 final double frx = fftX * uvw[0];
2332 final int ifrx = (int) frx;
2333 final int ifrxu = ifrx + frad;
2334
2335 final double fry = fftY * uvw[1];
2336 final int ifry = (int) fry;
2337 final int ifryu = ifry + frad;
2338
2339 final double frz = fftZ * uvw[2];
2340 final int ifrz = (int) frz;
2341 final int ifrzu = ifrz + frad;
2342
2343 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
2344 int giz = mod(iz, fftZ);
2345 if (lbZ > giz || giz > ubZ) {
2346 continue;
2347 }
2348 xf[2] = iz * ifftZ;
2349 for (int iy = ifry - frad; iy <= ifryu; iy++) {
2350 int giy = mod(iy, fftY);
2351 int rowIndex = rowRegion.rowIndexForYZ(giy, giz);
2352 if (lb > rowIndex || rowIndex > ub) {
2353 continue;
2354 }
2355 xf[1] = iy * ifftY;
2356 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
2357 int gix = mod(ix, fftX);
2358 xf[0] = ix * ifftX;
2359 crystal.toCartesianCoordinates(xf, xc);
2360 optLocal[rowIndex]++;
2361 actualWeight++;
2362 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
2363 grid[ii] = formFactor.rho(grid[ii], 1.0, xc);
2364 }
2365 }
2366 }
2367 }
2368
2369 @Override
2370 public void run(int lb, int ub) throws Exception {
2371 boolean boundsChange = false;
2372 if (previousLB != lb || previousUB != ub) {
2373 boundsChange = true;
2374 }
2375 previousLB = lb;
2376 previousUB = ub;
2377 if (rebuildList || boundsChange) {
2378 buildListA = new ArrayList<>();
2379 buildListS = new ArrayList<>();
2380 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2381 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2382 if (rowRegion.select[iSymm][iAtom]) {
2383 buildList(iSymm, iAtom, lb, ub);
2384 }
2385 }
2386 }
2387 }
2388 for (int i = 0; i < buildListA.size(); i++) {
2389 if (rowRegion.select[buildListS.get(i)][buildListA.get(i)]) {
2390 gridDensity(buildListS.get(i), buildListA.get(i), lb, ub);
2391 }
2392 }
2393 }
2394
2395 @Override
2396 public void saveZYValues(int[][][] zyAtListBuild) {
2397 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2398 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2399 zyAtListBuild[iSymm][iAtom][0] = 0;
2400 zyAtListBuild[iSymm][iAtom][1] = 0;
2401 if (rowRegion.select[iSymm][iAtom]) {
2402 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2403 continue;
2404 }
2405 xyz[0] = coordinates[iSymm][0][iAtom];
2406 xyz[1] = coordinates[iSymm][1][iAtom];
2407 xyz[2] = coordinates[iSymm][2][iAtom];
2408 crystal.toFractionalCoordinates(xyz, uvw);
2409 final double frz = fftZ * uvw[2];
2410 final int ifrz = (int) frz;
2411
2412 final double fry = fftY * uvw[1];
2413 final int ifry = (int) fry;
2414 zyAtListBuild[iSymm][iAtom][0] = ifrz;
2415 zyAtListBuild[iSymm][iAtom][1] = ifry;
2416 }
2417 }
2418 }
2419 }
2420
2421 @Override
2422 public IntegerSchedule schedule() {
2423 return solventRowSchedule;
2424 }
2425
2426 @Override
2427 public void start() {
2428 fill(optLocal, 0);
2429 timer = -System.nanoTime();
2430 }
2431 }
2432
2433 private class BulkSolventRowLoop extends RowLoop {
2434
2435 final double[] xyz = new double[3];
2436 final double[] uvw = new double[3];
2437 final double[] xc = new double[3];
2438 final double[] xf = new double[3];
2439 final double[] grid;
2440 final int[] optLocal;
2441 long timer;
2442 int[] threadWeights;
2443 int[] threadBounds;
2444
2445 public BulkSolventRowLoop(RowRegion region) {
2446 super(region.getNatoms(), region.getNsymm(), region);
2447 grid = region.getGrid();
2448 optLocal = new int[fftZ * fftY];
2449 }
2450
2451 @Override
2452 public void finish() {
2453 for (int i = 0; i < fftZ * fftY; i++) {
2454 optRowWeightBulkSolvent.addAndGet(i, optLocal[i]);
2455 }
2456 timer += System.nanoTime();
2457 threadBounds = bulkSolventRowSchedule.getLowerBounds().clone();
2458 threadWeights = bulkSolventRowSchedule.getThreadWeights().clone();
2459 for (int i = threadCount - 1; i > 0; i--) {
2460 threadWeights[i] -= threadWeights[i - 1];
2461 }
2462 }
2463
2464 public int[] getBoundsPerThread() {
2465 return threadBounds;
2466 }
2467
2468 public double getTimePerThread() {
2469 return timer;
2470 }
2471
2472 public int[] getWeightPerThread() {
2473 return optLocal;
2474 }
2475
2476 @Override
2477 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
2478 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2479 return;
2480 }
2481
2482 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
2483 return;
2484 }
2485
2486 xyz[0] = coordinates[iSymm][0][iAtom];
2487 xyz[1] = coordinates[iSymm][1][iAtom];
2488 xyz[2] = coordinates[iSymm][2][iAtom];
2489 FormFactor formFactor = solventFormFactors[iSymm][iAtom];
2490 crystal.toFractionalCoordinates(xyz, uvw);
2491 double vdwr = scatteringAtoms[iAtom].getVDWType().radius * 0.5;
2492 int frad = aRadGrid;
2493 switch (solventModel) {
2494 case BINARY:
2495 frad = min(aRadGrid, (int) floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
2496 break;
2497 case GAUSSIAN:
2498 frad = min(aRadGrid, (int) floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
2499 break;
2500 case POLYNOMIAL:
2501 frad = min(aRadGrid, (int) floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
2502 break;
2503 case NONE:
2504 default:
2505 return;
2506 }
2507
2508 int ubZ = rowRegion.zFromRowIndex(ub);
2509 int lbZ = rowRegion.zFromRowIndex(lb);
2510
2511
2512 final double frx = fftX * uvw[0];
2513 final int ifrx = (int) frx;
2514 final int ifrxu = ifrx + frad;
2515
2516 final double fry = fftY * uvw[1];
2517 final int ifry = (int) fry;
2518 final int ifryu = ifry + frad;
2519
2520 final double frz = fftZ * uvw[2];
2521 final int ifrz = (int) frz;
2522 final int ifrzu = ifrz + frad;
2523
2524 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
2525 int giz = mod(iz, fftZ);
2526 if (lbZ > giz || giz > ubZ) {
2527 continue;
2528 }
2529 xf[2] = iz * ifftZ;
2530 for (int iy = ifry - frad; iy <= ifryu; iy++) {
2531 int giy = mod(iy, fftY);
2532 int rowIndex = rowRegion.rowIndexForYZ(giy, giz);
2533 if (lb > rowIndex || rowIndex > ub) {
2534 continue;
2535 }
2536 xf[1] = iy * ifftY;
2537 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
2538 int gix = mod(ix, fftX);
2539 xf[0] = ix * ifftX;
2540 crystal.toCartesianCoordinates(xf, xc);
2541 optLocal[rowIndex]++;
2542 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
2543 grid[ii] = formFactor.rho(grid[ii], 1.0, xc);
2544 }
2545 }
2546 }
2547 }
2548
2549 @Override
2550 public IntegerSchedule schedule() {
2551 return bulkSolventRowSchedule;
2552 }
2553
2554 @Override
2555 public void start() {
2556 timer = -System.nanoTime();
2557 fill(optLocal, 0);
2558 }
2559 }
2560
2561 private class AtomicSliceLoop extends SliceLoop {
2562
2563 final double[] xyz = new double[3];
2564 final double[] uvw = new double[3];
2565 final double[] xc = new double[3];
2566 final double[] xf = new double[3];
2567 final double[] grid;
2568 final int[] optLocal;
2569 long timer;
2570 int previousUB, previousLB;
2571 int actualWeight;
2572
2573 public AtomicSliceLoop(SliceRegion region) {
2574 super(region.getNatoms(), region.getNsymm(), region);
2575 grid = region.getGrid();
2576 optLocal = new int[fftZ];
2577 }
2578
2579 public void buildList(int iSymm, int iAtom, int lb, int ub) {
2580 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2581 return;
2582 }
2583 xyz[0] = coordinates[iSymm][0][iAtom];
2584 xyz[1] = coordinates[iSymm][1][iAtom];
2585 xyz[2] = coordinates[iSymm][2][iAtom];
2586 crystal.toFractionalCoordinates(xyz, uvw);
2587 final int frad =
2588 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
2589 final double frz = fftZ * uvw[2];
2590 final int ifrz = (int) frz;
2591 final int ifrzu = ifrz + frad;
2592 final int ifrzl = ifrz - frad;
2593
2594
2595
2596 int buff = bufferSize;
2597 for (int iz = ifrzl - buff; iz <= ifrzu + buff; iz++) {
2598 int giz = mod(iz, fftZ);
2599 if (giz >= lb && giz <= ub) {
2600 buildListA.add(iAtom);
2601 buildListS.add(iSymm);
2602 break;
2603 }
2604 }
2605 }
2606
2607 @Override
2608 public boolean checkList(int[][] zAtListBuild, int buff) {
2609 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2610 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2611 if (sliceRegion.select[iSymm][iAtom]) {
2612 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2613 continue;
2614 }
2615 xyz[0] = coordinates[iSymm][0][iAtom];
2616 xyz[1] = coordinates[iSymm][1][iAtom];
2617 xyz[2] = coordinates[iSymm][2][iAtom];
2618 crystal.toFractionalCoordinates(xyz, uvw);
2619 final double frz = fftZ * uvw[2];
2620 final int ifrz = (int) frz;
2621 final int previousZ = zAtListBuild[iSymm][iAtom];
2622 if (abs(ifrz - previousZ) >= buff) {
2623 return true;
2624 }
2625 }
2626 }
2627 }
2628 return false;
2629 }
2630
2631 @Override
2632 public void finish() {
2633 for (int i = 0; i < fftZ; i++) {
2634 optSliceWeightAtomic.addAndGet(i, optLocal[i]);
2635 }
2636 timer += System.nanoTime();
2637 }
2638
2639 public int getNumberofSlices() {
2640 return (previousUB - previousLB + 1);
2641 }
2642
2643 public double getThreadTime() {
2644 return timer;
2645 }
2646
2647 public int getThreadWeight() {
2648 return actualWeight;
2649 }
2650
2651 @Override
2652 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
2653 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2654 return;
2655 }
2656
2657 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
2658 return;
2659 }
2660
2661 xyz[0] = coordinates[iSymm][0][iAtom];
2662 xyz[1] = coordinates[iSymm][1][iAtom];
2663 xyz[2] = coordinates[iSymm][2][iAtom];
2664 FormFactor atomff = atomFormFactors[iSymm][iAtom];
2665 crystal.toFractionalCoordinates(xyz, uvw);
2666 final int frad =
2667 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
2668
2669
2670 final double frx = fftX * uvw[0];
2671 final int ifrx = (int) frx;
2672 final int ifrxu = ifrx + frad;
2673
2674 final double fry = fftY * uvw[1];
2675 final int ifry = (int) fry;
2676 final int ifryu = ifry + frad;
2677
2678 final double frz = fftZ * uvw[2];
2679 final int ifrz = (int) frz;
2680 final int ifrzu = ifrz + frad;
2681
2682 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
2683 int giz = mod(iz, fftZ);
2684 if (lb > giz || giz > ub) {
2685 continue;
2686 }
2687 xf[2] = iz * ifftZ;
2688 for (int iy = ifry - frad; iy <= ifryu; iy++) {
2689 int giy = mod(iy, fftY);
2690 xf[1] = iy * ifftY;
2691 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
2692 int gix = mod(ix, fftX);
2693 xf[0] = ix * ifftX;
2694 crystal.toCartesianCoordinates(xf, xc);
2695 optLocal[giz]++;
2696 actualWeight++;
2697 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
2698 grid[ii] = atomff.rho(grid[ii], 1.0, xc);
2699 }
2700 }
2701 }
2702 }
2703
2704 @Override
2705 public void run(int lb, int ub) throws Exception {
2706 boolean boundsChange = false;
2707 if (previousLB != lb || previousUB != ub) {
2708 boundsChange = true;
2709 }
2710 previousLB = lb;
2711 previousUB = ub;
2712 if (rebuildList || boundsChange) {
2713 buildListA = new ArrayList<>();
2714 buildListS = new ArrayList<>();
2715 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2716 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2717 if (sliceRegion.select[iSymm][iAtom]) {
2718 buildList(iSymm, iAtom, lb, ub);
2719 }
2720 }
2721 }
2722 }
2723 for (int i = 0; i < buildListA.size(); i++) {
2724 if (sliceRegion.select[buildListS.get(i)][buildListA.get(i)]) {
2725 gridDensity(buildListS.get(i), buildListA.get(i), lb, ub);
2726 }
2727 }
2728 }
2729
2730 @Override
2731 public void saveZValues(int[][] zAtListBuild) {
2732 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2733 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2734 zAtListBuild[iSymm][iAtom] = 0;
2735 if (sliceRegion.select[iSymm][iAtom]) {
2736 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2737 continue;
2738 }
2739 xyz[0] = coordinates[iSymm][0][iAtom];
2740 xyz[1] = coordinates[iSymm][1][iAtom];
2741 xyz[2] = coordinates[iSymm][2][iAtom];
2742 crystal.toFractionalCoordinates(xyz, uvw);
2743 final double frz = fftZ * uvw[2];
2744 final int ifrz = (int) frz;
2745 zAtListBuild[iSymm][iAtom] = ifrz;
2746 }
2747 }
2748 }
2749 }
2750
2751 @Override
2752 public IntegerSchedule schedule() {
2753 return atomicSliceSchedule;
2754 }
2755
2756 @Override
2757 public void start() {
2758 fill(optLocal, 0);
2759 actualWeight = 0;
2760 timer = -System.nanoTime();
2761 }
2762 }
2763
2764 private class SolventSliceLoop extends SliceLoop {
2765
2766 final double[] xyz = new double[3];
2767 final double[] uvw = new double[3];
2768 final double[] xc = new double[3];
2769 final double[] xf = new double[3];
2770 final double[] grid;
2771 final int[] optLocal;
2772 long timer;
2773 int previousUB, previousLB;
2774 int actualWeight;
2775
2776 public SolventSliceLoop(SliceRegion region) {
2777 super(region.getNatoms(), region.getNsymm(), region);
2778 grid = region.getGrid();
2779 optLocal = new int[fftZ];
2780 }
2781
2782 public void buildList(int iSymm, int iAtom, int lb, int ub) {
2783 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2784 return;
2785 }
2786 xyz[0] = coordinates[iSymm][0][iAtom];
2787 xyz[1] = coordinates[iSymm][1][iAtom];
2788 xyz[2] = coordinates[iSymm][2][iAtom];
2789 crystal.toFractionalCoordinates(xyz, uvw);
2790 final int frad =
2791 min(aRadGrid, (int) floor(scatteringAtoms[iAtom].getFormFactorWidth() * fftX / crystal.a) + 1);
2792 final double frz = fftZ * uvw[2];
2793 final int ifrz = (int) frz;
2794 final int ifrzu = ifrz + frad;
2795 final int ifrzl = ifrz - frad;
2796
2797
2798
2799 int buff = bufferSize;
2800 for (int iz = ifrzl - buff; iz <= ifrzu + buff; iz++) {
2801 int giz = mod(iz, fftZ);
2802 if (giz >= lb && giz <= ub) {
2803 buildListA.add(iAtom);
2804 buildListS.add(iSymm);
2805 break;
2806 }
2807 }
2808 }
2809
2810 @Override
2811 public boolean checkList(int[][] zAtListBuild, int buff) {
2812 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2813 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2814 if (sliceRegion.select[iSymm][iAtom]) {
2815 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2816 continue;
2817 }
2818 xyz[0] = coordinates[iSymm][0][iAtom];
2819 xyz[1] = coordinates[iSymm][1][iAtom];
2820 xyz[2] = coordinates[iSymm][2][iAtom];
2821 crystal.toFractionalCoordinates(xyz, uvw);
2822 final double frz = fftZ * uvw[2];
2823 final int ifrz = (int) frz;
2824 final int previousZ = zAtListBuild[iSymm][iAtom];
2825 if (abs(ifrz - previousZ) >= buff) {
2826 return true;
2827 }
2828 }
2829 }
2830 }
2831 return false;
2832 }
2833
2834 @Override
2835 public void finish() {
2836 timer += System.nanoTime();
2837 for (int i = 0; i < fftZ; i++) {
2838 optSliceWeightSolvent.addAndGet(i, optLocal[i]);
2839 }
2840 }
2841
2842 public int getNumberofSlices() {
2843 return (previousUB - previousLB + 1);
2844 }
2845
2846 public double getThreadTime() {
2847 return timer;
2848 }
2849
2850 public int getThreadWeight() {
2851 return actualWeight;
2852 }
2853
2854 @Override
2855 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
2856 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2857 return;
2858 }
2859
2860 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
2861 return;
2862 }
2863
2864 xyz[0] = coordinates[iSymm][0][iAtom];
2865 xyz[1] = coordinates[iSymm][1][iAtom];
2866 xyz[2] = coordinates[iSymm][2][iAtom];
2867 FormFactor formFactor = solventFormFactors[iSymm][iAtom];
2868 crystal.toFractionalCoordinates(xyz, uvw);
2869 double vdwr = scatteringAtoms[iAtom].getVDWType().radius * 0.5;
2870 int frad = aRadGrid;
2871 switch (solventModel) {
2872 case BINARY:
2873 frad = min(aRadGrid, (int) floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
2874 break;
2875 case GAUSSIAN:
2876 frad = min(aRadGrid, (int) floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
2877 break;
2878 case POLYNOMIAL:
2879 frad = min(aRadGrid, (int) floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
2880 break;
2881 case NONE:
2882 default:
2883 return;
2884 }
2885
2886
2887 final double frx = fftX * uvw[0];
2888 final int ifrx = (int) frx;
2889 final int ifrxu = ifrx + frad;
2890
2891 final double fry = fftY * uvw[1];
2892 final int ifry = (int) fry;
2893 final int ifryu = ifry + frad;
2894
2895 final double frz = fftZ * uvw[2];
2896 final int ifrz = (int) frz;
2897 final int ifrzu = ifrz + frad;
2898
2899 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
2900 int giz = mod(iz, fftZ);
2901 if (lb > giz || giz > ub) {
2902 continue;
2903 }
2904 xf[2] = iz * ifftZ;
2905 for (int iy = ifry - frad; iy <= ifryu; iy++) {
2906 int giy = mod(iy, fftY);
2907 xf[1] = iy * ifftY;
2908 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
2909 int gix = mod(ix, fftX);
2910 xf[0] = ix * ifftX;
2911 crystal.toCartesianCoordinates(xf, xc);
2912 optLocal[giz]++;
2913 actualWeight++;
2914 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
2915 grid[ii] = formFactor.rho(grid[ii], 1.0, xc);
2916 }
2917 }
2918 }
2919 }
2920
2921 @Override
2922 public void run(int lb, int ub) throws Exception {
2923 boolean boundsChange = false;
2924 if (previousLB != lb || previousUB != ub) {
2925 boundsChange = true;
2926 }
2927 previousLB = lb;
2928 previousUB = ub;
2929 if (rebuildList || boundsChange) {
2930 buildListA = new ArrayList<>();
2931 buildListS = new ArrayList<>();
2932 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2933 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2934 if (sliceRegion.select[iSymm][iAtom]) {
2935 buildList(iSymm, iAtom, lb, ub);
2936 }
2937 }
2938 }
2939 }
2940 for (int i = 0; i < buildListA.size(); i++) {
2941 if (sliceRegion.select[buildListS.get(i)][buildListA.get(i)]) {
2942 gridDensity(buildListS.get(i), buildListA.get(i), lb, ub);
2943 }
2944 }
2945 }
2946
2947 @Override
2948 public void saveZValues(int[][] zAtListBuild) {
2949 for (int iSymm = 0; iSymm < nSymm; iSymm++) {
2950 for (int iAtom = 0; iAtom < nScatteringAtoms; iAtom++) {
2951 zAtListBuild[iSymm][iAtom] = 0;
2952 if (sliceRegion.select[iSymm][iAtom]) {
2953 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
2954 continue;
2955 }
2956 xyz[0] = coordinates[iSymm][0][iAtom];
2957 xyz[1] = coordinates[iSymm][1][iAtom];
2958 xyz[2] = coordinates[iSymm][2][iAtom];
2959 crystal.toFractionalCoordinates(xyz, uvw);
2960 final double frz = fftZ * uvw[2];
2961 final int ifrz = (int) frz;
2962 zAtListBuild[iSymm][iAtom] = ifrz;
2963 }
2964 }
2965 }
2966 }
2967
2968 @Override
2969 public IntegerSchedule schedule() {
2970 return solventSliceSchedule;
2971 }
2972
2973 @Override
2974 public void start() {
2975 fill(optLocal, 0);
2976 actualWeight = 0;
2977 timer = -System.nanoTime();
2978 }
2979 }
2980
2981 private class BulkSolventSliceLoop extends SliceLoop {
2982
2983 final double[] xyz = new double[3];
2984 final double[] uvw = new double[3];
2985 final double[] xc = new double[3];
2986 final double[] xf = new double[3];
2987 final double[] grid;
2988 final int[] optLocal;
2989 long timer;
2990 int[] threadBounds;
2991 int[] threadWeights;
2992
2993 public BulkSolventSliceLoop(SliceRegion region) {
2994 super(region.getNatoms(), region.getNsymm(), region);
2995 grid = region.getGrid();
2996 optLocal = new int[fftZ];
2997 }
2998
2999 @Override
3000 public void finish() {
3001 timer += System.nanoTime();
3002 for (int i = 0; i < fftZ; i++) {
3003 optSliceWeightBulkSolvent.addAndGet(i, optLocal[i]);
3004 }
3005 threadBounds = bulkSolventSliceSchedule.getLowerBounds().clone();
3006 threadWeights = bulkSolventSliceSchedule.getThreadWeights().clone();
3007 for (int i = threadBounds.length - 1; i > 0; i--) {
3008 threadBounds[i] -= threadBounds[i - 1];
3009 }
3010 }
3011
3012 public int[] getBoundsPerThread() {
3013 return threadBounds;
3014 }
3015
3016 public double getTimePerThread() {
3017 return timer;
3018 }
3019
3020 public int[] getWeightPerThread() {
3021 return threadWeights;
3022 }
3023
3024 @Override
3025 public void gridDensity(int iSymm, int iAtom, int lb, int ub) {
3026 if (!scatteringAtoms[iAtom].getUse() && !nativeEnvironmentApproximation) {
3027 return;
3028 }
3029
3030 if (lambdaTerm && scatteringAtoms[iAtom].applyLambda()) {
3031 return;
3032 }
3033
3034 xyz[0] = coordinates[iSymm][0][iAtom];
3035 xyz[1] = coordinates[iSymm][1][iAtom];
3036 xyz[2] = coordinates[iSymm][2][iAtom];
3037 FormFactor formFactor = solventFormFactors[iSymm][iAtom];
3038 crystal.toFractionalCoordinates(xyz, uvw);
3039 double vdwr = scatteringAtoms[iAtom].getVDWType().radius * 0.5;
3040 int frad = aRadGrid;
3041 switch (solventModel) {
3042 case BINARY:
3043 frad = min(aRadGrid, (int) floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
3044 break;
3045 case GAUSSIAN:
3046 frad = min(aRadGrid, (int) floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
3047 break;
3048 case POLYNOMIAL:
3049 frad = min(aRadGrid, (int) floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
3050 break;
3051 case NONE:
3052 default:
3053 return;
3054 }
3055
3056
3057 final double frx = fftX * uvw[0];
3058 final int ifrx = (int) frx;
3059 final int ifrxu = ifrx + frad;
3060
3061 final double fry = fftY * uvw[1];
3062 final int ifry = (int) fry;
3063 final int ifryu = ifry + frad;
3064
3065 final double frz = fftZ * uvw[2];
3066 final int ifrz = (int) frz;
3067 final int ifrzu = ifrz + frad;
3068
3069 for (int iz = ifrz - frad; iz <= ifrzu; iz++) {
3070 int giz = mod(iz, fftZ);
3071 if (lb > giz || giz > ub) {
3072 continue;
3073 }
3074 xf[2] = iz * ifftZ;
3075 for (int iy = ifry - frad; iy <= ifryu; iy++) {
3076 int giy = mod(iy, fftY);
3077 xf[1] = iy * ifftY;
3078 for (int ix = ifrx - frad; ix <= ifrxu; ix++) {
3079 int gix = mod(ix, fftX);
3080 xf[0] = ix * ifftX;
3081 crystal.toCartesianCoordinates(xf, xc);
3082 optLocal[giz]++;
3083 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
3084 grid[ii] = formFactor.rho(grid[ii], 1.0, xc);
3085 }
3086 }
3087 }
3088 }
3089
3090 @Override
3091 public IntegerSchedule schedule() {
3092 return bulkSolventSliceSchedule;
3093 }
3094
3095 @Override
3096 public void start() {
3097 fill(optLocal, 0);
3098 timer = -System.nanoTime();
3099 }
3100 }
3101
3102 private class AtomicGradientRegion extends ParallelRegion {
3103
3104 private final AtomicGradientLoop[] atomicGradientLoop;
3105 private RefinementMode refinementmode;
3106
3107 public AtomicGradientRegion(RefinementMode refinementmode) {
3108 this.refinementmode = refinementmode;
3109 atomicGradientLoop = new AtomicGradientLoop[threadCount];
3110 for (int i = 0; i < threadCount; i++) {
3111 atomicGradientLoop[i] = new AtomicGradientLoop();
3112 }
3113 }
3114
3115 public RefinementMode getRefinementMode() {
3116 return refinementmode;
3117 }
3118
3119 public void setRefinementMode(RefinementMode refinementmode) {
3120 this.refinementmode = refinementmode;
3121 }
3122
3123 @Override
3124 public void run() {
3125 try {
3126 execute(0, nScatteringAtoms - 1, atomicGradientLoop[getThreadIndex()]);
3127 } catch (Exception e) {
3128 logger.severe(e.toString());
3129 }
3130 }
3131
3132 private class AtomicGradientLoop extends IntegerForLoop {
3133
3134 final double[] xyz = new double[3];
3135 final double[] uvw = new double[3];
3136 final double[] xc = new double[3];
3137 final double[] xf = new double[3];
3138 final int[] optLocal = new int[nScatteringAtoms];
3139 long timer;
3140
3141 @Override
3142 public void finish() {
3143 timer += System.nanoTime();
3144 for (int i = 0; i < nScatteringAtoms; i++) {
3145 optAtomicGradientWeight.addAndGet(i, optLocal[i]);
3146 }
3147 }
3148
3149 @Override
3150 public void run(final int lb, final int ub) {
3151 for (int n = lb; n <= ub; n++) {
3152 if (!scatteringAtoms[n].getUse() && !nativeEnvironmentApproximation) {
3153 continue;
3154 }
3155 if (lambdaTerm && scatteringAtoms[n].applyLambda()) {
3156 continue;
3157 }
3158
3159 xyz[0] = coordinates[0][0][n];
3160 xyz[1] = coordinates[0][1][n];
3161 xyz[2] = coordinates[0][2][n];
3162 FormFactor atomff = atomFormFactors[0][n];
3163 atomff.update(xyz, 0.0);
3164 crystal.toFractionalCoordinates(xyz, uvw);
3165 final int dfrad = Math.min(aRadGrid, (int) Math.floor(scatteringAtoms[n].getFormFactorWidth() * fftX / crystal.a) + 1);
3166
3167
3168 final double frx = fftX * uvw[0];
3169 final int ifrx = (int) frx;
3170
3171 final double fry = fftY * uvw[1];
3172 final int ifry = (int) fry;
3173
3174 final double frz = fftZ * uvw[2];
3175 final int ifrz = (int) frz;
3176
3177 for (int ix = ifrx - dfrad; ix <= ifrx + dfrad; ix++) {
3178 int gix = mod(ix, fftX);
3179 xf[0] = ix * ifftX;
3180 for (int iy = ifry - dfrad; iy <= ifry + dfrad; iy++) {
3181 int giy = mod(iy, fftY);
3182 xf[1] = iy * ifftY;
3183 for (int iz = ifrz - dfrad; iz <= ifrz + dfrad; iz++) {
3184 int giz = mod(iz, fftZ);
3185 xf[2] = iz * ifftZ;
3186 crystal.toCartesianCoordinates(xf, xc);
3187 optLocal[n]++;
3188 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
3189 atomff.rhoGrad(xc, weight * getDensityGrid()[ii], refinementmode);
3190 }
3191 }
3192 }
3193 }
3194 }
3195
3196 @Override
3197 public IntegerSchedule schedule() {
3198 return atomicGradientSchedule;
3199 }
3200
3201 @Override
3202 public void start() {
3203 fill(optLocal, 0);
3204 timer = -System.nanoTime();
3205 }
3206 }
3207 }
3208
3209 private class SolventGradientRegion extends ParallelRegion {
3210
3211 private final SolventGradientLoop[] solventGradientLoop;
3212 private RefinementMode refinementmode;
3213
3214 public SolventGradientRegion(RefinementMode refinementmode) {
3215 this.refinementmode = refinementmode;
3216 solventGradientLoop = new SolventGradientLoop[threadCount];
3217 for (int i = 0; i < threadCount; i++) {
3218 solventGradientLoop[i] = new SolventGradientLoop();
3219 }
3220 }
3221
3222 public RefinementMode getRefinementMode() {
3223 return refinementmode;
3224 }
3225
3226 public void setRefinementMode(RefinementMode refinementmode) {
3227 this.refinementmode = refinementmode;
3228 }
3229
3230 @Override
3231 public void run() {
3232 try {
3233 execute(0, nScatteringAtoms - 1, solventGradientLoop[getThreadIndex()]);
3234 } catch (Exception e) {
3235 logger.severe(e.toString());
3236 }
3237 }
3238
3239 private class SolventGradientLoop extends IntegerForLoop {
3240
3241 double[] xyz = new double[3];
3242 double[] uvw = new double[3];
3243 double[] xc = new double[3];
3244 double[] xf = new double[3];
3245
3246 @Override
3247 public void run(final int lb, final int ub) {
3248 for (int n = lb; n <= ub; n++) {
3249 if (!scatteringAtoms[n].getUse() && !nativeEnvironmentApproximation) {
3250 continue;
3251 }
3252 if (lambdaTerm && scatteringAtoms[n].applyLambda()) {
3253 continue;
3254 }
3255 xyz[0] = coordinates[0][0][n];
3256 xyz[1] = coordinates[0][1][n];
3257 xyz[2] = coordinates[0][2][n];
3258 FormFactor solventff = solventFormFactors[0][n];
3259 solventff.update(xyz);
3260 crystal.toFractionalCoordinates(xyz, uvw);
3261 double vdwr = scatteringAtoms[n].getVDWType().radius * 0.5;
3262 double dfcmult = 1.0;
3263 int dfrad = aRadGrid;
3264 switch (solventModel) {
3265 case BINARY:
3266 dfrad =
3267 Math.min(
3268 aRadGrid, (int) Math.floor((vdwr + solventA + 0.2) * fftX / crystal.a) + 1);
3269 break;
3270 case GAUSSIAN:
3271 dfrad =
3272 Math.min(
3273 aRadGrid, (int) Math.floor((vdwr * solventB + 2.0) * fftX / crystal.a) + 1);
3274 dfcmult = solventA;
3275 break;
3276 case POLYNOMIAL:
3277 dfrad =
3278 Math.min(
3279 aRadGrid, (int) Math.floor((vdwr + solventB + 0.2) * fftX / crystal.a) + 1);
3280 break;
3281 case NONE:
3282 return;
3283 }
3284
3285
3286 final double frx = fftX * uvw[0];
3287 final int ifrx = (int) frx;
3288 final int ifrxu = ifrx + dfrad;
3289
3290 final double fry = fftY * uvw[1];
3291 final int ifry = (int) fry;
3292 final int ifryu = ifry + dfrad;
3293
3294 final double frz = fftZ * uvw[2];
3295 final int ifrz = (int) frz;
3296 final int ifrzu = ifrz + dfrad;
3297
3298 for (int ix = ifrx - dfrad; ix <= ifrxu; ix++) {
3299 int gix = mod(ix, fftX);
3300 xf[0] = ix * ifftX;
3301 for (int iy = ifry - dfrad; iy <= ifryu; iy++) {
3302 int giy = mod(iy, fftY);
3303 xf[1] = iy * ifftY;
3304 for (int iz = ifrz - dfrad; iz <= ifrzu; iz++) {
3305 int giz = mod(iz, fftZ);
3306 xf[2] = iz * ifftZ;
3307 crystal.toCartesianCoordinates(xf, xc);
3308 final int ii = interleavedIndex(gix, giy, giz, fftX, fftY);
3309 solventff.rhoGrad(
3310 xc,
3311 weight * getDensityGrid()[ii] * dfcmult * getSolventGrid()[ii],
3312 refinementmode);
3313 }
3314 }
3315 }
3316 }
3317 }
3318 }
3319 }
3320
3321 private class BabinetRegion extends ParallelRegion {
3322
3323 BabinetLoop[] babinetLoops;
3324
3325 public BabinetRegion(int nThreads) {
3326 babinetLoops = new BabinetLoop[nThreads];
3327 }
3328
3329 @Override
3330 public void run() {
3331 int ti = getThreadIndex();
3332
3333 if (babinetLoops[ti] == null) {
3334 babinetLoops[ti] = new BabinetLoop();
3335 }
3336
3337 try {
3338 execute(0, fftZ - 1, babinetLoops[ti]);
3339 } catch (Exception e) {
3340 logger.info(e.toString());
3341 }
3342 }
3343
3344 private class BabinetLoop extends IntegerForLoop {
3345
3346 @Override
3347 public void run(int lb, int ub) {
3348 switch (solventModel) {
3349 case BINARY:
3350 case POLYNOMIAL:
3351 for (int k = lb; k <= ub; k++) {
3352 for (int j = 0; j < fftY; j++) {
3353 for (int i = 0; i < fftX; i++) {
3354 final int ii = interleavedIndex(i, j, k, fftX, fftY);
3355 densityGrid[ii] = 1.0 - getDensityGrid()[ii];
3356 }
3357 }
3358 }
3359 break;
3360 case GAUSSIAN:
3361 for (int k = lb; k <= ub; k++) {
3362 for (int j = 0; j < fftY; j++) {
3363 for (int i = 0; i < fftX; i++) {
3364 final int ii = interleavedIndex(i, j, k, fftX, fftY);
3365 densityGrid[ii] = 1.0 - exp(-solventA * getDensityGrid()[ii]);
3366 }
3367 }
3368 }
3369 break;
3370 default:
3371 }
3372 }
3373 }
3374 }
3375
3376 private class SolventGridRegion extends ParallelRegion {
3377
3378 SolventGridLoop[] solventGridLoops;
3379
3380 public SolventGridRegion(int nThreads) {
3381 solventGridLoops = new SolventGridLoop[nThreads];
3382 }
3383
3384 @Override
3385 public void run() {
3386 int ti = getThreadIndex();
3387
3388 if (solventGridLoops[ti] == null) {
3389 solventGridLoops[ti] = new SolventGridLoop();
3390 }
3391
3392 try {
3393 execute(0, fftZ - 1, solventGridLoops[ti]);
3394 } catch (Exception e) {
3395 logger.info(e.toString());
3396 }
3397 }
3398
3399 private class SolventGridLoop extends IntegerForLoop {
3400
3401 @Override
3402 public void run(int lb, int ub) {
3403
3404 for (int k = lb; k <= ub; k++) {
3405 for (int j = 0; j < fftY; j++) {
3406 for (int i = 0; i < fftX; i++) {
3407 final int ii = interleavedIndex(i, j, k, fftX, fftY);
3408 solventGrid[ii] = exp(-solventA * getSolventGrid()[ii]);
3409 }
3410 }
3411 }
3412 }
3413 }
3414 }
3415
3416 private class InitRegion extends ParallelRegion {
3417
3418 InitLoop[] initLoops;
3419 FormFactorUpdateLoop[] formFactorUpdateLoops;
3420 int nHKL = reflectionList.hklList.size();
3421 double[][] hkldata = null;
3422
3423 public InitRegion(int nThreads) {
3424 initLoops = new InitLoop[nThreads];
3425 formFactorUpdateLoops = new FormFactorUpdateLoop[nThreads];
3426 }
3427
3428 @Override
3429 public void run() {
3430 int ti = getThreadIndex();
3431
3432 if (initLoops[ti] == null) {
3433 initLoops[ti] = new InitLoop();
3434 formFactorUpdateLoops[ti] = new FormFactorUpdateLoop();
3435 }
3436
3437 try {
3438 execute(0, nHKL - 1, initLoops[ti]);
3439 execute(0, nScatteringAtoms - 1, formFactorUpdateLoops[ti]);
3440 } catch (Exception e) {
3441 logger.info(e.toString());
3442 }
3443 }
3444
3445 public void setHKL(double[][] hkldata) {
3446 this.hkldata = hkldata;
3447 }
3448
3449 private class InitLoop extends IntegerForLoop {
3450
3451 @Override
3452 public void run(int lb, int ub) {
3453 for (int i = lb; i <= ub; i++) {
3454 hkldata[i][0] = 0.0;
3455 hkldata[i][1] = 0.0;
3456 }
3457 }
3458 }
3459
3460 private class FormFactorUpdateLoop extends IntegerForLoop {
3461
3462 private final double[] xyz = new double[3];
3463
3464 @Override
3465 public void run(int lb, int ub) {
3466 for (int iSymm = 0; iSymm < bulkNSymm; iSymm++) {
3467 for (int i = lb; i <= ub; i++) {
3468 xyz[0] = coordinates[iSymm][0][i];
3469 xyz[1] = coordinates[iSymm][1][i];
3470 xyz[2] = coordinates[iSymm][2][i];
3471 if (solventFormFactors != null) {
3472 solventFormFactors[iSymm][i].update(xyz);
3473 }
3474 if (atomFormFactors != null) {
3475 atomFormFactors[iSymm][i].update(xyz, bAdd);
3476 }
3477 }
3478 }
3479 }
3480 }
3481 }
3482
3483 private class AtomicScaleRegion extends ParallelRegion {
3484
3485 AtomicScaleLoop[] atomicScaleLoops;
3486 int nHKL = reflectionList.hklList.size();
3487 double[][] hklData = null;
3488 double scale;
3489
3490 public AtomicScaleRegion(int nThreads) {
3491 atomicScaleLoops = new AtomicScaleLoop[nThreads];
3492 }
3493
3494 @Override
3495 public void run() throws Exception {
3496 int ti = getThreadIndex();
3497
3498 if (atomicScaleLoops[ti] == null) {
3499 atomicScaleLoops[ti] = new AtomicScaleLoop();
3500 }
3501
3502 try {
3503 execute(0, nHKL - 1, atomicScaleLoops[ti]);
3504 } catch (Exception e) {
3505 logger.info(e.toString());
3506 }
3507 }
3508
3509 public void setHKL(double[][] hkldata) {
3510 this.hklData = hkldata;
3511 }
3512
3513 public void setScale(double scale) {
3514 this.scale = scale;
3515 }
3516
3517 private class AtomicScaleLoop extends IntegerForLoop {
3518
3519 ComplexNumber c;
3520
3521 public AtomicScaleLoop() {
3522 c = new ComplexNumber();
3523 }
3524
3525 @Override
3526 public void run(int lb, int ub) {
3527 for (int i = lb; i <= ub; i++) {
3528 HKL ih = reflectionList.hklList.get(i);
3529 double[] fc = hklData[ih.getIndex()];
3530 c.re(fc[0]);
3531 c.im(fc[1]);
3532
3533 double s = crystal.invressq(ih);
3534 c.timesIP(scale * exp(0.25 * bAdd * s));
3535 c.conjugateIP();
3536 fc[0] = c.re();
3537 fc[1] = c.im();
3538 }
3539 }
3540 }
3541 }
3542
3543 private class SolventScaleRegion extends ParallelRegion {
3544
3545 SolventScaleLoop[] solventScaleLoops;
3546 int nHKL = reflectionList.hklList.size();
3547 double[][] hkldata = null;
3548 double scale;
3549
3550 public SolventScaleRegion(int nThreads) {
3551 solventScaleLoops = new SolventScaleLoop[nThreads];
3552 }
3553
3554 @Override
3555 public void run() throws Exception {
3556 int ti = getThreadIndex();
3557
3558 if (solventScaleLoops[ti] == null) {
3559 solventScaleLoops[ti] = new SolventScaleLoop();
3560 }
3561
3562 try {
3563 execute(0, nHKL - 1, solventScaleLoops[ti]);
3564 } catch (Exception e) {
3565 logger.info(e.toString());
3566 }
3567 }
3568
3569 public void setHKL(double[][] hkldata) {
3570 this.hkldata = hkldata;
3571 }
3572
3573 public void setScale(double scale) {
3574 this.scale = scale;
3575 }
3576
3577 private class SolventScaleLoop extends IntegerForLoop {
3578
3579 ComplexNumber c;
3580
3581 public SolventScaleLoop() {
3582 c = new ComplexNumber();
3583 }
3584
3585 @Override
3586 public void run(int lb, int ub) throws Exception {
3587 for (int i = lb; i <= ub; i++) {
3588 HKL ih = reflectionList.hklList.get(i);
3589 double[] fc = hkldata[ih.getIndex()];
3590 c.re(fc[0]);
3591 c.im(fc[1]);
3592 c.timesIP(scale);
3593 c.conjugateIP();
3594
3595 fc[0] = -c.re();
3596 fc[1] = -c.im();
3597 }
3598 }
3599 }
3600 }
3601
3602 private class ExtractRegion extends ParallelRegion {
3603
3604 ExtractLoop[] extractLoops;
3605 int nHKL = reflectionList.hklList.size();
3606 double[][] hkldata = null;
3607
3608 public ExtractRegion(int nThreads) {
3609 extractLoops = new ExtractLoop[nThreads];
3610 }
3611
3612 @Override
3613 public void run() throws Exception {
3614 int ti = getThreadIndex();
3615
3616 if (extractLoops[ti] == null) {
3617 extractLoops[ti] = new ExtractLoop();
3618 }
3619
3620 try {
3621 execute(0, nHKL - 1, extractLoops[ti]);
3622 } catch (Exception e) {
3623 logger.info(e.toString());
3624 }
3625 }
3626
3627 public void setHKL(double[][] hkldata) {
3628 this.hkldata = hkldata;
3629 }
3630
3631 private class ExtractLoop extends IntegerForLoop {
3632
3633 ComplexNumber c;
3634 int nsym;
3635 List<SymOp> symops;
3636 HKL ij;
3637
3638 public ExtractLoop() {
3639 c = new ComplexNumber();
3640 nsym = crystal.spaceGroup.symOps.size();
3641 symops = crystal.spaceGroup.symOps;
3642 ij = new HKL();
3643 }
3644
3645 @Override
3646 public void run(int lb, int ub) throws Exception {
3647 for (int i = lb; i <= ub; i++) {
3648 HKL ih = reflectionList.hklList.get(i);
3649 double[] fc = hkldata[ih.getIndex()];
3650
3651 for (int j = 0; j < nsym; j++) {
3652 SymOp symOp = symops.get(j);
3653 applyTransSymRot(ih, ij, symOp);
3654 double shift = symOp.symPhaseShift(ih);
3655 int h = mod(ij.getH(), fftX);
3656 int k = mod(ij.getK(), fftY);
3657 int l = mod(ij.getL(), fftZ);
3658 if (h < halfFFTX + 1) {
3659 final int ii = interleavedIndex(h, k, l, fftX, fftY);
3660 c.re(getDensityGrid()[ii]);
3661 c.im(getDensityGrid()[ii + 1]);
3662 } else {
3663 h = (fftX - h) % fftX;
3664 k = (fftY - k) % fftY;
3665 l = (fftZ - l) % fftZ;
3666 final int ii = interleavedIndex(h, k, l, fftX, fftY);
3667 c.re(getDensityGrid()[ii]);
3668 c.im(-getDensityGrid()[ii + 1]);
3669 }
3670 c.phaseShiftIP(shift);
3671 fc[0] += c.re();
3672 fc[1] += c.im();
3673 }
3674 }
3675 }
3676 }
3677 }
3678
3679 private class ArrayCopyRegion extends ParallelRegion {
3680
3681 ArrayCopyLoop[] arrayCopyLoops;
3682
3683 public ArrayCopyRegion() {
3684 arrayCopyLoops = new ArrayCopyLoop[threadCount];
3685 }
3686
3687 @Override
3688 public void run() {
3689 int ti = getThreadIndex();
3690
3691 if (arrayCopyLoops[ti] == null) {
3692 arrayCopyLoops[ti] = new ArrayCopyLoop();
3693 }
3694
3695 try {
3696 execute(0, complexFFT3DSpace - 1, arrayCopyLoops[ti]);
3697 } catch (Exception e) {
3698 logger.info(e.toString());
3699 }
3700 }
3701
3702 private class ArrayCopyLoop extends IntegerForLoop {
3703
3704 @Override
3705 public void run(int lb, int ub) {
3706 int length = ub - lb + 1;
3707 arraycopy(getDensityGrid(), lb, getSolventGrid(), lb, length);
3708 }
3709 }
3710 }
3711 }