1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.potential.nonbonded.implicit;
39
40 import static ffx.numerics.math.DoubleMath.X;
41 import static ffx.numerics.math.DoubleMath.dist;
42 import static ffx.numerics.math.DoubleMath.dist2;
43 import static ffx.numerics.math.DoubleMath.dot;
44 import static ffx.numerics.math.DoubleMath.length;
45 import static ffx.numerics.math.DoubleMath.normalize;
46 import static java.lang.String.format;
47 import static java.lang.System.arraycopy;
48 import static java.util.Arrays.fill;
49 import static org.apache.commons.math3.util.FastMath.PI;
50 import static org.apache.commons.math3.util.FastMath.abs;
51 import static org.apache.commons.math3.util.FastMath.acos;
52 import static org.apache.commons.math3.util.FastMath.asin;
53 import static org.apache.commons.math3.util.FastMath.atan2;
54 import static org.apache.commons.math3.util.FastMath.cos;
55 import static org.apache.commons.math3.util.FastMath.max;
56 import static org.apache.commons.math3.util.FastMath.min;
57 import static org.apache.commons.math3.util.FastMath.sin;
58 import static org.apache.commons.math3.util.FastMath.sqrt;
59
60 import edu.rit.pj.IntegerForLoop;
61 import edu.rit.pj.ParallelRegion;
62 import edu.rit.pj.ParallelTeam;
63 import edu.rit.pj.reduction.SharedDouble;
64 import ffx.potential.bonded.Atom;
65 import ffx.potential.utils.EnergyException;
66
67 import java.util.logging.Level;
68 import java.util.logging.Logger;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public class ConnollyRegion extends ParallelRegion {
93
94
95
96
97 public static final double DEFAULT_WIGGLE = 1.0e-8;
98
99 private static final Logger logger = Logger.getLogger(ConnollyRegion.class.getName());
100
101
102
103 private static final int MAXCUBE = 40;
104
105
106
107 private static final int MAXCYEP = 30;
108
109
110
111 private static final int MAXFPCY = 10;
112
113
114
115 private final int nAtoms;
116
117
118
119 private final double[] baseRadius;
120
121
122
123 private final double[] radius;
124
125
126
127 private final boolean[] skip;
128
129
130
131 private final double[][] volumeGradient;
132
133 private final int[] itab;
134 private final ParallelTeam parallelTeam;
135 private final VolumeLoop[] volumeLoop;
136 private final SharedDouble sharedVolume;
137 private final SharedDouble sharedArea;
138
139
140
141 private final int maxSaddleFace;
142
143
144
145 private final int maxConvexEdges;
146
147
148
149 private final int maxAtomPairs;
150
151
152
153 private final int maxCircles;
154
155
156
157 private final int maxTori;
158
159
160
161 private final int maxTempTori;
162
163
164
165 private final int maxConcaveEdges;
166
167
168
169 private final int maxVertices;
170
171
172
173 private final int maxProbePositions;
174
175
176
177 private final int maxConcaveFaces;
178
179
180
181 private final int maxConvexFaces;
182
183
184
185 private final int maxCycles;
186
187
188
189 private final double[][] atomCoords;
190
191 private final double[] x, y, z;
192
193
194
195 private final boolean[] noFreeSurface;
196
197
198
199 private final boolean[] atomFreeOfNeighbors;
200
201
202
203 private final boolean[] atomBuried;
204
205
206
207 private final int[][] atomNeighborPointers;
208
209
210
211 private final int[] neighborAtomNumbers;
212
213
214
215 private final int[] neighborToTorus;
216
217
218
219 private final int[][] tempToriAtomNumbers;
220
221
222
223 private final int[] tempToriFirstEdge;
224
225
226
227 private final int[] tempToriLastEdge;
228
229
230
231 private final int[] tempToriNextEdge;
232
233
234
235 private final boolean[] tempToriBuried;
236
237
238
239 private final boolean[] tempToriFree;
240
241
242
243 private final double[][] torusCenter;
244
245
246
247 private final double[] torusRadius;
248
249
250
251 private final double[][] torusAxis;
252
253
254
255 private final int[][] torusAtomNumber;
256
257
258
259 private final int[] torusFirstEdge;
260
261
262
263 private final boolean[] torusNeighborFreeEdge;
264
265
266
267 private final double[][] probeCoords;
268
269
270
271 private final int[][] probeAtomNumbers;
272
273
274
275 private final double[][] vertexCoords;
276
277
278
279 private final int[] vertexAtomNumbers;
280
281
282
283 private final int[] vertexProbeNumber;
284
285
286
287 private final int[][] concaveEdgeVertexNumbers;
288
289
290
291 private final int[][] concaveFaceEdgeNumbers;
292
293
294
295 private final double[][] circleCenter;
296
297
298
299 private final double[] circleRadius;
300
301
302
303 private final int[] circleAtomNumber;
304
305
306
307 private final int[] circleTorusNumber;
308
309
310
311 private final int[] convexEdgeCircleNumber;
312
313
314
315 private final int[][] convexEdgeVertexNumber;
316
317
318
319 private final int[] convexEdgeFirst;
320
321
322
323 private final int[] convexEdgeLast;
324
325
326
327 private final int[] convexEdgeNext;
328
329
330
331 private final int[][] saddleConcaveEdgeNumbers;
332
333
334
335 private final int[][] saddleConvexEdgeNumbers;
336
337
338
339 private final int[] convexEdgeCycleNum;
340
341
342
343 private final int[][] convexEdgeCycleNumbers;
344
345
346
347 private final int[] convexFaceAtomNumber;
348
349
350
351 private final int[][] convexFaceCycleNumbers;
352
353
354
355 private final int[] convexFaceNumCycles;
356
357
358
359 private final boolean[] activeCube;
360
361
362
363 private final boolean[] activeAdjacentCube;
364
365
366
367 private final int[] firstAtomPointer;
368
369
370
371 private final int[][] cubeCoordinates;
372
373
374
375 private final int[] nextAtomPointer;
376
377
378
379 private Atom[] atoms;
380
381
382
383 private boolean gradient = false;
384
385
386
387 private double probe = 0.0;
388
389
390
391 private double exclude = 1.4;
392
393
394
395 private double wiggle = DEFAULT_WIGGLE;
396
397
398
399 private int nTempTori;
400
401
402
403 private int nTori;
404
405
406
407 private int nProbePositions;
408
409
410
411 private int nConcaveFaces;
412
413
414
415 private int nConcaveVerts;
416
417
418
419 private int nConcaveEdges;
420
421
422
423
424
425 private int nCircles;
426
427
428
429 private int nConvexEdges;
430
431
432
433 private int nSaddleFaces;
434
435
436
437 private int nCycles;
438
439
440
441 private int nConvexFaces;
442
443
444
445
446
447
448
449
450 public ConnollyRegion(Atom[] atoms, double[] baseRadius, int nThreads) {
451 this.atoms = atoms;
452 this.nAtoms = atoms.length;
453 this.baseRadius = baseRadius;
454
455
456 parallelTeam = new ParallelTeam(1);
457 volumeLoop = new VolumeLoop[nThreads];
458 for (int i = 0; i < nThreads; i++) {
459 volumeLoop[i] = new VolumeLoop();
460 }
461 sharedVolume = new SharedDouble();
462 sharedArea = new SharedDouble();
463
464
465 radius = new double[nAtoms];
466 skip = new boolean[nAtoms];
467 atomCoords = new double[3][nAtoms];
468 x = atomCoords[0];
469 y = atomCoords[1];
470 z = atomCoords[2];
471 noFreeSurface = new boolean[nAtoms];
472 atomFreeOfNeighbors = new boolean[nAtoms];
473 atomBuried = new boolean[nAtoms];
474 atomNeighborPointers = new int[2][nAtoms];
475
476
477 maxAtomPairs = 240 * nAtoms;
478 neighborAtomNumbers = new int[maxAtomPairs];
479 neighborToTorus = new int[maxAtomPairs];
480
481
482 maxTempTori = 120 * nAtoms;
483 maxConcaveEdges = 12 * nAtoms;
484 tempToriAtomNumbers = new int[2][maxTempTori];
485 tempToriFirstEdge = new int[maxTempTori];
486 tempToriLastEdge = new int[maxTempTori];
487 tempToriBuried = new boolean[maxTempTori];
488 tempToriFree = new boolean[maxTempTori];
489 tempToriNextEdge = new int[maxConcaveEdges];
490
491
492 maxTori = 4 * nAtoms;
493 torusCenter = new double[3][maxTori];
494 torusRadius = new double[maxTori];
495 torusAxis = new double[3][maxTori];
496 torusAtomNumber = new int[2][maxTori];
497 torusFirstEdge = new int[maxTori];
498 torusNeighborFreeEdge = new boolean[maxTori];
499
500
501 maxProbePositions = 4 * nAtoms;
502 probeCoords = new double[3][maxProbePositions];
503 probeAtomNumbers = new int[3][maxProbePositions];
504
505
506 maxVertices = 12 * nAtoms;
507 vertexCoords = new double[3][maxVertices];
508 vertexAtomNumbers = new int[maxVertices];
509 vertexProbeNumber = new int[maxVertices];
510
511
512 maxConcaveFaces = 4 * nAtoms;
513 concaveFaceEdgeNumbers = new int[3][maxConcaveFaces];
514 concaveEdgeVertexNumbers = new int[2][maxConcaveEdges];
515
516
517 maxCircles = 8 * nAtoms;
518 circleCenter = new double[3][maxCircles];
519 circleRadius = new double[maxCircles];
520 circleAtomNumber = new int[maxCircles];
521 circleTorusNumber = new int[maxCircles];
522
523
524 maxConvexEdges = 12 * nAtoms;
525 maxConvexFaces = 2 * nAtoms;
526 maxCycles = 3 * nAtoms;
527 convexEdgeCircleNumber = new int[maxConvexEdges];
528 convexEdgeVertexNumber = new int[2][maxConvexEdges];
529 convexEdgeFirst = new int[nAtoms];
530 convexEdgeLast = new int[nAtoms];
531 convexEdgeNext = new int[maxConvexEdges];
532 convexEdgeCycleNum = new int[maxCycles];
533 convexEdgeCycleNumbers = new int[MAXCYEP][maxCycles];
534 convexFaceAtomNumber = new int[maxConvexFaces];
535 convexFaceNumCycles = new int[maxConvexFaces];
536 convexFaceCycleNumbers = new int[MAXFPCY][maxConvexFaces];
537
538
539 maxSaddleFace = 6 * nAtoms;
540 saddleConcaveEdgeNumbers = new int[2][maxSaddleFace];
541 saddleConvexEdgeNumbers = new int[2][maxSaddleFace];
542
543
544 activeCube = new boolean[MAXCUBE * MAXCUBE * MAXCUBE];
545 activeAdjacentCube = new boolean[MAXCUBE * MAXCUBE * MAXCUBE];
546 firstAtomPointer = new int[MAXCUBE * MAXCUBE * MAXCUBE];
547 cubeCoordinates = new int[3][nAtoms];
548 nextAtomPointer = new int[nAtoms];
549
550
551 volumeGradient = new double[3][nAtoms];
552 itab = new int[nAtoms];
553 }
554
555 public double getExclude() {
556 return exclude;
557 }
558
559 public void setExclude(double exclude) {
560 this.exclude = exclude;
561 }
562
563 public double getProbe() {
564 return probe;
565 }
566
567 public void setProbe(double probe) {
568 this.probe = probe;
569 }
570
571 public double getSurfaceArea() {
572 return sharedArea.get();
573 }
574
575 public double getVolume() {
576 return sharedVolume.get();
577 }
578
579 public double[][] getVolumeGradient() {
580 return volumeGradient;
581 }
582
583
584
585
586
587
588
589
590
591 public void init(Atom[] atoms, boolean gradient) {
592 this.atoms = atoms;
593 this.gradient = gradient;
594 }
595
596 @Override
597 public void run() {
598 try {
599 execute(0, nAtoms - 1, volumeLoop[getThreadIndex()]);
600 } catch (Exception e) {
601 String message =
602 "Fatal exception computing Volume energy in thread " + getThreadIndex() + "\n";
603 logger.log(Level.SEVERE, message, e);
604 }
605 }
606
607
608
609
610 public void runVolume() {
611 try {
612 parallelTeam.execute(this);
613 } catch (Exception e) {
614 String message = " Fatal exception computing the Connolly surface area and volume.";
615 logger.log(Level.SEVERE, message, e);
616 }
617 }
618
619
620
621
622
623
624
625 public void setWiggle(double wiggle) {
626 this.wiggle = wiggle;
627 }
628
629 @Override
630 public void start() {
631 sharedVolume.set(0.0);
632 sharedArea.set(0.0);
633 double[] vector = new double[3];
634 for (int i = 0; i < nAtoms; i++) {
635 getRandomVector(vector);
636 Atom atom = atoms[i];
637 atomCoords[0][i] = atom.getX() + (wiggle * vector[0]);
638 atomCoords[1][i] = atom.getY() + (wiggle * vector[1]);
639 atomCoords[2][i] = atom.getZ() + (wiggle * vector[2]);
640 }
641 }
642
643
644
645
646
647
648 private void getRandomVector(double[] vector) {
649 double x, y, s;
650 x = 0;
651 y = 0;
652
653
654 s = 2.0;
655 while (s >= 1.0) {
656 x = (2.0 * Math.random()) - 1.0;
657 y = (2.0 * Math.random()) - 1.0;
658 s = (x * x) + (y * y);
659 }
660
661
662 vector[2] = 1.0 - 2.0 * s;
663 s = 2.0 * sqrt(1.0 - s);
664 vector[1] = s * y;
665 vector[0] = s * x;
666 }
667
668
669
670
671
672
673 private class VolumeLoop extends IntegerForLoop {
674
675
676
677 private static final int MXCUBE = 30;
678
679
680
681 private static final int MAXARC = 1000;
682
683
684
685 private static final int MAXMNB = 500;
686
687 private double localVolume;
688 private double localSurfaceArea;
689
690 @Override
691 public void finish() {
692 sharedVolume.addAndGet(localVolume);
693 sharedArea.addAndGet(localSurfaceArea);
694 }
695
696 @Override
697 public void run(int lb, int ub) {
698 setRadius();
699 computeVolumeAndArea();
700 if (gradient) {
701 computeVolumeGradient();
702 }
703 }
704
705 @Override
706 public void start() {
707 localVolume = 0.0;
708 localSurfaceArea = 0.0;
709 if (gradient) {
710 fill(volumeGradient[0], 0.0);
711 fill(volumeGradient[1], 0.0);
712 fill(volumeGradient[2], 0.0);
713 }
714 }
715
716
717
718
719
720 private void setRadius() {
721 for (int i = 0; i < nAtoms; i++) {
722 if (baseRadius[i] == 0.0) {
723 radius[i] = 0.0;
724 skip[i] = true;
725 } else {
726 skip[i] = false;
727 radius[i] = baseRadius[i] + exclude;
728 }
729 }
730 }
731
732
733
734
735 private void computeVolumeAndArea() {
736 nearby();
737 torus();
738 place();
739 compress();
740 saddles();
741 contact();
742 vam();
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756 private boolean getTorus(
757 int ia, int ja, double[] torusCenter, double[] torusRadius, double[] torusAxis) {
758 boolean foundTorus = false;
759
760
761 double[] ai = new double[3];
762 double[] aj = new double[3];
763 getVector(ai, atomCoords, ia);
764 getVector(aj, atomCoords, ja);
765 double dij = dist(ai, aj);
766
767
768 double[] vij = new double[3];
769 double[] uij = new double[3];
770 for (int k = 0; k < 3; k++) {
771 vij[k] = atomCoords[k][ja] - atomCoords[k][ia];
772 uij[k] = vij[k] / dij;
773 }
774
775
776 double temp =
777 1.0
778 + ((radius[ia] + probe) * (radius[ia] + probe)
779 - (radius[ja] + probe) * (radius[ja] + probe))
780 / (dij * dij);
781 double[] bij = new double[3];
782 for (int k = 0; k < 3; k++) {
783 bij[k] = atomCoords[k][ia] + 0.5 * vij[k] * temp;
784 }
785
786
787 double temp1 =
788 (radius[ia] + radius[ja] + 2.0 * probe) * (radius[ia] + radius[ja] + 2.0 * probe)
789 - dij * dij;
790 if (temp1 >= 0.0) {
791
792
793 double temp2 = dij * dij - (radius[ia] - radius[ja]) * (radius[ia] - radius[ja]);
794 if (temp2 >= 0.0) {
795
796
797 foundTorus = true;
798 torusRadius[0] = sqrt(temp1 * temp2) / (2.0 * dij);
799 for (int k = 0; k < 3; k++) {
800 torusCenter[k] = bij[k];
801 torusAxis[k] = uij[k];
802 }
803 }
804 }
805 return foundTorus;
806 }
807
808
809
810
811
812 private void nearby() {
813 int maxclsa = 1000;
814 int[] clsa = new int[maxclsa];
815
816 int[] tempNeighborList = new int[maxclsa];
817
818 double[] minAtomicCoordinates = new double[3];
819 double[] ai = new double[3];
820 double[] aj = new double[3];
821
822
823
824
825
826 for (int i = 0; i < nAtoms - 1; i++) {
827 if (!skip[i]) {
828 getVector(ai, atomCoords, i);
829 for (int j = i + 1; j < nAtoms; j++) {
830 getVector(aj, atomCoords, j);
831 double d2 = dist2(ai, aj);
832 double r2 = (radius[i] - radius[j]) * (radius[i] - radius[j]);
833 if (!skip[j] && d2 < r2) {
834 if (radius[i] < radius[j]) {
835 skip[i] = true;
836 } else {
837 skip[j] = true;
838 }
839 }
840 }
841 }
842 }
843
844
845 double radmax = 0.0;
846 for (int k = 0; k < 3; k++) {
847 minAtomicCoordinates[k] = atomCoords[k][0];
848 }
849 for (int i = 0; i < nAtoms; i++) {
850 for (int k = 0; k < 3; k++) {
851 if (atomCoords[k][i] < minAtomicCoordinates[k]) {
852 minAtomicCoordinates[k] = atomCoords[k][i];
853 }
854 }
855 if (radius[i] > radmax) {
856 radmax = radius[i];
857 }
858 }
859
860
861 double width = 2.0 * (radmax + probe);
862
863
864 for (int i = 0; i < nAtoms; i++) {
865 for (int k = 0; k < 3; k++) {
866 cubeCoordinates[k][i] = (int) ((atomCoords[k][i] - minAtomicCoordinates[k]) / width);
867 if (cubeCoordinates[k][i] < 0) {
868 throw new EnergyException(" Cube Coordinate Too Small");
869 } else if (cubeCoordinates[k][i] > MAXCUBE) {
870 throw new EnergyException(" Cube Coordinate Too Large");
871 }
872 }
873 }
874
875
876 fill(firstAtomPointer, -1);
877 fill(activeCube, false);
878 fill(activeAdjacentCube, false);
879
880
881 fill(nextAtomPointer, -1);
882
883
884 atomLoop:
885 for (int iatom = 0; iatom < nAtoms; iatom++) {
886
887 if (skip[iatom]) {
888 continue;
889 }
890
891 getVector(ai, atomCoords, iatom);
892 int i = cubeCoordinates[0][iatom];
893 int j = cubeCoordinates[1][iatom];
894 int k = cubeCoordinates[2][iatom];
895
896 if (firstAtomPointer[index(i, j, k)] <= -1) {
897
898 firstAtomPointer[index(i, j, k)] = iatom;
899 } else {
900
901 int iptr = firstAtomPointer[index(i, j, k)];
902 boolean done = false;
903 while (!done) {
904 getVector(aj, atomCoords, iptr);
905
906 if (dist2(ai, aj) <= 0.0) {
907 skip[iatom] = true;
908 continue atomLoop;
909 }
910
911 if (nextAtomPointer[iptr] <= -1.0) {
912 done = true;
913 } else {
914 iptr = nextAtomPointer[iptr];
915 }
916 }
917
918 nextAtomPointer[iptr] = iatom;
919 }
920
921
922 if (!skip[iatom]) {
923 activeCube[index(i, j, k)] = true;
924 }
925 }
926
927
928 for (int k = 0; k < MAXCUBE; k++) {
929 for (int j = 0; j < MAXCUBE; j++) {
930 for (int i = 0; i < MAXCUBE; i++) {
931 if (firstAtomPointer[index(i, j, k)] != -1) {
932 checkCube(i, j, k);
933 }
934 }
935 }
936 }
937
938 int ncls = -1;
939
940
941 for (int i = 0; i < nAtoms; i++) {
942 int nclsa = -1;
943 noFreeSurface[i] = skip[i];
944 atomNeighborPointers[0][i] = -1;
945 atomNeighborPointers[1][i] = -1;
946 if (skip[i]) {
947 continue;
948 }
949 int ici = cubeCoordinates[0][i];
950 int icj = cubeCoordinates[1][i];
951 int ick = cubeCoordinates[2][i];
952
953
954 if (!activeAdjacentCube[index(ici, icj, ick)]) {
955 continue;
956 }
957 double sumi = 2.0 * probe + radius[i];
958
959
960 for (int jck = max(ick - 1, 0); jck < min(ick + 2, MAXCUBE); jck++) {
961 for (int jcj = max(icj - 1, 0); jcj < min(icj + 2, MAXCUBE); jcj++) {
962
963 for4:
964 for (int jci = max(ici - 1, 0); jci < min(ici + 2, MAXCUBE); jci++) {
965 int j = firstAtomPointer[index(jci, jcj, jck)];
966 int counter = 1;
967 for (int q = 0; q < counter; q++) {
968 for (int z = 0; z < 1; z++) {
969
970 if (j <= -1) {
971 continue for4;
972 } else if (i == j) {
973 continue;
974 } else if (skip[j]) {
975 continue;
976 }
977
978
979 double sum = sumi + radius[j];
980 double vect1 = abs(atomCoords[0][j] - atomCoords[0][i]);
981 if (vect1 >= sum) {
982 continue;
983 }
984 double vect2 = abs(atomCoords[1][j] - atomCoords[1][i]);
985 if (vect2 >= sum) {
986 continue;
987 }
988 double vect3 = abs(atomCoords[2][j] - atomCoords[2][i]);
989 if (vect3 >= sum) {
990 continue;
991 }
992 double d2 = (vect1 * vect1) + (vect2 * vect2) + (vect3 * vect3);
993 if (d2 >= sum * sum) {
994 continue;
995 }
996
997
998 if (!skip[j]) {
999 noFreeSurface[i] = false;
1000 }
1001 nclsa++;
1002 if (nclsa >= maxclsa) {
1003 throw new EnergyException(" Too many Neighbors for Atom");
1004 }
1005 tempNeighborList[nclsa] = j;
1006 }
1007
1008
1009 j = nextAtomPointer[j];
1010 counter++;
1011 }
1012 }
1013 }
1014 }
1015
1016 if (noFreeSurface[i]) {
1017 continue;
1018 }
1019
1020
1021 int jmold = -1;
1022 for (int juse = 0; juse <= nclsa; juse++) {
1023 int jmin = nAtoms;
1024 int jmincls = 0;
1025 for (int jcls = 0; jcls < nclsa + 1; jcls++) {
1026
1027 if (tempNeighborList[jcls] > jmold) {
1028 if (tempNeighborList[jcls] < jmin) {
1029 jmin = tempNeighborList[jcls];
1030 jmincls = jcls;
1031 }
1032 }
1033 }
1034 jmold = jmin;
1035 int jcls = jmincls;
1036 int jatom = tempNeighborList[jcls];
1037 clsa[juse] = jatom;
1038 }
1039
1040
1041 if (nclsa > -1) {
1042 atomNeighborPointers[0][i] = ncls + 1;
1043 for (int m = 0; m < nclsa + 1; m++) {
1044 ncls++;
1045 if (ncls >= maxAtomPairs) {
1046 throw new EnergyException(" Too many Neighboring Atom Pairs");
1047 }
1048 neighborAtomNumbers[ncls] = clsa[m];
1049 }
1050 atomNeighborPointers[1][i] = ncls;
1051 }
1052 }
1053 }
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063 private int index(int i, int j, int k) {
1064 return k + MAXCUBE * (j + MAXCUBE * i);
1065 }
1066
1067
1068
1069
1070
1071
1072
1073
1074 private void checkCube(int i, int j, int k) {
1075 for (int k1 = max(k - 1, 0); k1 < min(k + 2, MAXCUBE); k1++) {
1076 for (int j1 = max(j - 1, 0); j1 < min(j + 2, MAXCUBE); j1++) {
1077 for (int i1 = max(i - 1, 0); i1 < min(i + 2, MAXCUBE); i1++) {
1078 if (activeCube[index(i1, j1, k1)]) {
1079 activeAdjacentCube[index(i, j, k)] = true;
1080 return;
1081 }
1082 }
1083 }
1084 }
1085 }
1086
1087
1088
1089
1090
1091 private void torus() {
1092
1093 nTempTori = -1;
1094 fill(atomFreeOfNeighbors, true);
1095 if (nAtoms <= 1) {
1096 return;
1097 }
1098
1099 double[] tt = new double[3];
1100 double[] ttax = new double[3];
1101
1102 for (int ia = 0; ia < nAtoms; ia++) {
1103 if (!noFreeSurface[ia]) {
1104 int ibeg = atomNeighborPointers[0][ia];
1105 int iend = atomNeighborPointers[1][ia];
1106 if (ibeg > -1) {
1107
1108 for (int jn = ibeg; jn <= iend; jn++) {
1109
1110 neighborToTorus[jn] = -1;
1111
1112 int ja = neighborAtomNumbers[jn];
1113
1114 if (ja >= ia) {
1115
1116 double[] ttr = {0.0};
1117 boolean ttok = getTorus(ia, ja, tt, ttr, ttax);
1118 if (ttok) {
1119
1120 nTempTori++;
1121 if (nTempTori >= maxTempTori) {
1122 throw new EnergyException(" Too many Temporary Tori");
1123 }
1124
1125 atomFreeOfNeighbors[ia] = false;
1126 atomFreeOfNeighbors[ja] = false;
1127 tempToriAtomNumbers[0][nTempTori] = ia;
1128 tempToriAtomNumbers[1][nTempTori] = ja;
1129
1130 neighborToTorus[jn] = nTempTori;
1131
1132 tempToriFree[nTempTori] = true;
1133 tempToriBuried[nTempTori] = true;
1134
1135 tempToriFirstEdge[nTempTori] = -1;
1136 tempToriLastEdge[nTempTori] = -1;
1137 }
1138 }
1139 }
1140 }
1141 }
1142 }
1143 }
1144
1145
1146
1147
1148
1149 private void place() {
1150 int[] mnb = new int[MAXMNB];
1151 int[] ikt = new int[MAXMNB];
1152 int[] jkt = new int[MAXMNB];
1153 int[] lkcls = new int[MAXMNB];
1154 double[] tik = new double[3];
1155 double[] tij = new double[3];
1156 double[] uij = new double[3];
1157 double[] uik = new double[3];
1158 double[] uijk = new double[3];
1159 double[] bij = new double[3];
1160 double[] bijk = new double[3];
1161 double[] aijk = new double[3];
1162 double[] pijk = new double[3];
1163 double[] tijik = new double[3];
1164 double[] tempv = new double[3];
1165 double[] utb = new double[3];
1166 double[] ai = new double[3];
1167 double[] ak = new double[3];
1168 double[] discls = new double[MAXMNB];
1169 double[] sumcls = new double[MAXMNB];
1170 boolean tb, tok, prbok;
1171
1172 nProbePositions = -1;
1173 nConcaveFaces = -1;
1174 nConcaveEdges = -1;
1175 nConcaveVerts = -1;
1176
1177
1178 if (nTempTori <= -1) {
1179 return;
1180 }
1181
1182
1183 for (int itt = 0; itt < nTempTori + 1; itt++) {
1184
1185 int ia = tempToriAtomNumbers[0][itt];
1186 int ja = tempToriAtomNumbers[1][itt];
1187
1188
1189 int nmnb = -1;
1190
1191
1192 int iptr = atomNeighborPointers[0][ia];
1193 int jptr = atomNeighborPointers[0][ja];
1194
1195
1196 outerloop:
1197 for (int i = 0; i < 1; i++) {
1198 if (iptr <= -1 || jptr <= -1) {
1199 continue;
1200 }
1201 int iend = atomNeighborPointers[1][ia];
1202 int jend = atomNeighborPointers[1][ja];
1203
1204
1205 int counter = 1;
1206 int counter2 = 1;
1207
1208 for (int t = 0; t < counter2; t++) {
1209
1210 for (int q = 0; q < counter; q++) {
1211
1212 if (iptr > iend || jptr > jend) {
1213 continue outerloop;
1214 }
1215
1216 if (neighborAtomNumbers[iptr] < neighborAtomNumbers[jptr]) {
1217 iptr++;
1218 counter++;
1219 continue;
1220 }
1221 if (neighborAtomNumbers[jptr] < neighborAtomNumbers[iptr]) {
1222 jptr++;
1223 counter++;
1224 }
1225 }
1226
1227
1228
1229
1230
1231 nmnb++;
1232 if (nmnb >= MAXMNB) {
1233 throw new EnergyException(" Too many Mutual Neighbors");
1234 }
1235 mnb[nmnb] = neighborAtomNumbers[iptr];
1236
1237
1238 ikt[nmnb] = neighborToTorus[iptr];
1239 jkt[nmnb] = neighborToTorus[jptr];
1240 iptr++;
1241 counter2++;
1242 }
1243 }
1244
1245
1246 if (nmnb == -1) {
1247 tempToriBuried[itt] = false;
1248 continue;
1249 }
1250 double[] hij = {0.0};
1251 boolean ttok = getTorus(ia, ja, bij, hij, uij);
1252 for (int km = 0; km < nmnb + 1; km++) {
1253 int ka = mnb[km];
1254 getVector(ak, atomCoords, ka);
1255 discls[km] = dist2(bij, ak);
1256 sumcls[km] = (probe + radius[ka]) * (probe + radius[ka]);
1257
1258 lkcls[km] = -1;
1259 }
1260
1261
1262
1263 int lkf = 0;
1264 for (int z = 0; z < 1; z++) {
1265 if (nmnb == 0) {
1266 continue;
1267 }
1268
1269 int l;
1270 for (l = 1; l < nmnb + 1; l++) {
1271
1272 int l1 = -1;
1273 int l2 = lkf;
1274 int counter2 = 1;
1275 for (int w = 0; w < counter2; w++) {
1276 if (discls[l] < discls[l2]) {
1277 continue;
1278 }
1279 l1 = l2;
1280 l2 = lkcls[l2];
1281 if (l2 != -1) {
1282 counter2++;
1283 }
1284 }
1285
1286
1287 if (l1 == -1) {
1288 lkf = l;
1289 } else {
1290 lkcls[l1] = l;
1291 }
1292 lkcls[l] = l2;
1293 }
1294 }
1295
1296 for (int km = 0; km < nmnb + 1; km++) {
1297
1298
1299 int ka = mnb[km];
1300 if (skip[ia] && skip[ja] && skip[ka]) {
1301 continue;
1302 }
1303
1304
1305 int ik = ikt[km];
1306 int jk = jkt[km];
1307
1308
1309 prbok = false;
1310 tb = false;
1311 double[] rij = {0.0};
1312 double hijk = 0.0;
1313 tok = getTorus(ia, ja, tij, rij, uij);
1314 for (int w = 0; w < 1; w++) {
1315 if (tok) {
1316 getVector(ai, atomCoords, ka);
1317 double dat2 = dist2(ai, tij);
1318 double rad2 = (radius[ka] + probe) * (radius[ka] + probe) - rij[0] * rij[0];
1319
1320
1321 if (ka < ja) {
1322 if (rad2 <= 0.0 || dat2 > rad2) {
1323 continue;
1324 }
1325 }
1326
1327 double[] rik = {0.0};
1328 tok = getTorus(ia, ka, tik, rik, uik);
1329 if (!tok) {
1330 continue;
1331 }
1332 double dotijk = check(dot(uij, uik));
1333 double wijk = acos(dotijk);
1334 double swijk = sin(wijk);
1335
1336
1337
1338
1339 if (swijk == 0.0) {
1340 tb = (rad2 > 0.0 && dat2 <= rad2);
1341 continue;
1342 }
1343 X(uij, uik, uijk);
1344 for (int k = 0; k < 3; k++) {
1345 uijk[k] = uijk[k] / swijk;
1346 }
1347 X(uijk, uij, utb);
1348 for (int k = 0; k < 3; k++) {
1349 tijik[k] = tik[k] - tij[k];
1350 }
1351 double dotut = dot(uik, tijik);
1352 double fact = dotut / swijk;
1353 for (int k = 0; k < 3; k++) {
1354 bijk[k] = tij[k] + utb[k] * fact;
1355 }
1356 getVector(ai, atomCoords, ia);
1357 double dba = dist2(ai, bijk);
1358 double rip2 = (radius[ia] + probe) * (radius[ia] + probe);
1359 double rad = rip2 - dba;
1360 if (rad < 0.0) {
1361 tb = (rad2 > 0.0 && dat2 <= rad2);
1362 } else {
1363 prbok = true;
1364 hijk = sqrt(rad);
1365 }
1366 }
1367 }
1368 if (tb) {
1369 tempToriBuried[itt] = true;
1370 tempToriFree[itt] = false;
1371 continue;
1372 }
1373
1374
1375 if (ka < ja || !prbok) {
1376 continue;
1377 }
1378
1379
1380 for (int k = 0; k < 3; k++) {
1381 aijk[k] = hijk * uijk[k];
1382 }
1383
1384
1385 for3:
1386 for (int ip = 0; ip < 2; ip++) {
1387 for (int k = 0; k < 3; k++) {
1388 if (ip == 0) {
1389 pijk[k] = bijk[k] + aijk[k];
1390 } else {
1391 pijk[k] = bijk[k] - aijk[k];
1392 }
1393 }
1394
1395
1396 tempToriFree[itt] = false;
1397 tempToriFree[ik] = false;
1398 tempToriFree[jk] = false;
1399
1400
1401 int lm = lkf;
1402 int counter3 = 1;
1403 for4:
1404 for (int t = 0; t < counter3; t++) {
1405 for (int p = 0; p < 1; p++) {
1406 if (lm < 0) {
1407 continue for4;
1408 }
1409
1410
1411 int la = mnb[lm];
1412
1413 if (la == ka) {
1414 continue;
1415 }
1416 getVector(ak, atomCoords, la);
1417
1418 if (dist2(pijk, ak) <= sumcls[lm]) {
1419 continue for3;
1420 }
1421 }
1422 lm = lkcls[lm];
1423 counter3++;
1424 }
1425
1426 nProbePositions++;
1427 if (nProbePositions >= maxProbePositions) {
1428 throw new EnergyException(" Too many Probe Positions");
1429 }
1430
1431 tempToriBuried[itt] = false;
1432 tempToriBuried[ik] = false;
1433 tempToriBuried[jk] = false;
1434
1435 for (int k = 0; k < 3; k++) {
1436 probeCoords[k][nProbePositions] = pijk[k];
1437 }
1438
1439
1440 if (nConcaveVerts + 3 >= maxVertices) {
1441 throw new EnergyException(" Too many Vertices");
1442 }
1443 for (int k = 0; k < 3; k++) {
1444 vertexCoords[k][nConcaveVerts + 1] =
1445 atomCoords[k][ia] - probeCoords[k][nProbePositions];
1446 vertexCoords[k][nConcaveVerts + 2] =
1447 atomCoords[k][ja] - probeCoords[k][nProbePositions];
1448 vertexCoords[k][nConcaveVerts + 3] =
1449 atomCoords[k][ka] - probeCoords[k][nProbePositions];
1450 }
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460 double det =
1461 vertexCoords[0][nConcaveVerts + 1]
1462 * vertexCoords[1][nConcaveVerts + 2]
1463 * vertexCoords[2][nConcaveVerts + 3]
1464 + vertexCoords[0][nConcaveVerts + 2]
1465 * vertexCoords[1][nConcaveVerts + 3]
1466 * vertexCoords[2][nConcaveVerts + 1]
1467 + vertexCoords[0][nConcaveVerts + 3]
1468 * vertexCoords[1][nConcaveVerts + 1]
1469 * vertexCoords[2][nConcaveVerts + 2]
1470 - vertexCoords[0][nConcaveVerts + 3]
1471 * vertexCoords[1][nConcaveVerts + 2]
1472 * vertexCoords[2][nConcaveVerts + 1]
1473 - vertexCoords[0][nConcaveVerts + 2]
1474 * vertexCoords[1][nConcaveVerts + 1]
1475 * vertexCoords[2][nConcaveVerts + 3]
1476 - vertexCoords[0][nConcaveVerts + 1]
1477 * vertexCoords[1][nConcaveVerts + 3]
1478 * vertexCoords[2][nConcaveVerts + 2];
1479
1480 for (int k = 0; k < 3; k++) {
1481 vertexCoords[k][nConcaveVerts + 1] =
1482 probeCoords[k][nProbePositions]
1483 + (vertexCoords[k][nConcaveVerts + 1] * probe / (radius[ia] + probe));
1484 vertexCoords[k][nConcaveVerts + 2] =
1485 probeCoords[k][nProbePositions]
1486 + (vertexCoords[k][nConcaveVerts + 2] * probe / (radius[ja] + probe));
1487 vertexCoords[k][nConcaveVerts + 3] =
1488 probeCoords[k][nProbePositions]
1489 + (vertexCoords[k][nConcaveVerts + 3] * probe / (radius[ka] + probe));
1490 }
1491
1492 if (det > 0.0) {
1493
1494 for (int k = 0; k < 3; k++) {
1495 tempv[k] = vertexCoords[k][nConcaveVerts + 2];
1496 vertexCoords[k][nConcaveVerts + 2] = vertexCoords[k][nConcaveVerts + 3];
1497 vertexCoords[k][nConcaveVerts + 3] = tempv[k];
1498 }
1499
1500 probeAtomNumbers[0][nProbePositions] = ia;
1501 probeAtomNumbers[1][nProbePositions] = ka;
1502 probeAtomNumbers[2][nProbePositions] = ja;
1503
1504 vertexAtomNumbers[nConcaveVerts + 1] = ia;
1505 vertexAtomNumbers[nConcaveVerts + 2] = ka;
1506 vertexAtomNumbers[nConcaveVerts + 3] = ja;
1507
1508 insertEdge(nConcaveEdges + 1, ik);
1509 insertEdge(nConcaveEdges + 2, jk);
1510 insertEdge(nConcaveEdges + 3, itt);
1511 } else {
1512
1513 probeAtomNumbers[0][nProbePositions] = ia;
1514 probeAtomNumbers[1][nProbePositions] = ja;
1515 probeAtomNumbers[2][nProbePositions] = ka;
1516 vertexAtomNumbers[nConcaveVerts + 1] = ia;
1517 vertexAtomNumbers[nConcaveVerts + 2] = ja;
1518 vertexAtomNumbers[nConcaveVerts + 3] = ka;
1519 insertEdge(nConcaveEdges + 1, itt);
1520 insertEdge(nConcaveEdges + 2, jk);
1521 insertEdge(nConcaveEdges + 3, ik);
1522 }
1523
1524 for (int kv = 1; kv < 4; kv++) {
1525 vertexProbeNumber[nConcaveVerts + kv] = nProbePositions;
1526 }
1527
1528 if (nConcaveEdges + 3 >= maxConcaveEdges) {
1529 throw new EnergyException(" Too many Concave Edges");
1530 }
1531
1532 concaveEdgeVertexNumbers[0][nConcaveEdges + 1] = nConcaveVerts + 1;
1533 concaveEdgeVertexNumbers[1][nConcaveEdges + 1] = nConcaveVerts + 2;
1534 concaveEdgeVertexNumbers[0][nConcaveEdges + 2] = nConcaveVerts + 2;
1535 concaveEdgeVertexNumbers[1][nConcaveEdges + 2] = nConcaveVerts + 3;
1536 concaveEdgeVertexNumbers[0][nConcaveEdges + 3] = nConcaveVerts + 3;
1537 concaveEdgeVertexNumbers[1][nConcaveEdges + 3] = nConcaveVerts + 1;
1538 if (nConcaveFaces + 1 >= maxConcaveFaces) {
1539 throw new EnergyException(" Too many Concave Faces");
1540 }
1541
1542 for (int ke = 0; ke < 3; ke++) {
1543 concaveFaceEdgeNumbers[ke][nConcaveFaces + 1] = nConcaveEdges + ke + 1;
1544 }
1545
1546 nConcaveFaces++;
1547 nConcaveEdges += 3;
1548 nConcaveVerts += 3;
1549 }
1550 }
1551 }
1552 }
1553
1554
1555
1556
1557
1558
1559
1560 private void insertEdge(int edgeNumber, int torusNumber) {
1561
1562 if (edgeNumber <= -1) {
1563 throw new EnergyException(" Bad Edge Number in INEDGE");
1564 }
1565 if (torusNumber <= -1) {
1566 throw new EnergyException(" Bad Torus Number in INEDGE");
1567 }
1568
1569 if (tempToriFirstEdge[torusNumber] == -1) {
1570 tempToriFirstEdge[torusNumber] = edgeNumber;
1571 } else {
1572 tempToriNextEdge[tempToriLastEdge[torusNumber]] = edgeNumber;
1573 }
1574 tempToriNextEdge[edgeNumber] = -1;
1575 tempToriLastEdge[torusNumber] = edgeNumber;
1576 }
1577
1578
1579
1580
1581
1582 private void compress() {
1583 double[] torCenter = new double[3];
1584 double[] torAxis = new double[3];
1585
1586 nTori = -1;
1587 if (nTempTori <= -1) {
1588 return;
1589 }
1590
1591 double[] torRad = {0};
1592 for (int itt = 0; itt <= nTempTori; itt++) {
1593 if (tempToriFree[itt]) {
1594 tempToriBuried[itt] = false;
1595 }
1596 if (!tempToriBuried[itt]) {
1597
1598 nTori++;
1599 if (nTori >= maxTori) {
1600 throw new EnergyException(" Too many non-buried tori.");
1601 }
1602 int ia = tempToriAtomNumbers[0][itt];
1603 int ja = tempToriAtomNumbers[1][itt];
1604 getVector(torCenter, torusCenter, nTori);
1605 getVector(torAxis, torusAxis, nTori);
1606 getTorus(ia, ja, torCenter, torRad, torAxis);
1607 torusCenter[0][nTori] = torCenter[0];
1608 torusCenter[1][nTori] = torCenter[1];
1609 torusCenter[2][nTori] = torCenter[2];
1610 torusAxis[0][nTori] = torAxis[0];
1611 torusAxis[1][nTori] = torAxis[1];
1612 torusAxis[2][nTori] = torAxis[2];
1613 torusRadius[nTori] = torRad[0];
1614 torusAtomNumber[0][nTori] = ia;
1615 torusAtomNumber[1][nTori] = ja;
1616 torusNeighborFreeEdge[nTori] = tempToriFree[itt];
1617 torusFirstEdge[nTori] = tempToriFirstEdge[itt];
1618
1619 int iptr = torusFirstEdge[nTori];
1620 int ned = -1;
1621 while (iptr != -1) {
1622 ned++;
1623 iptr = tempToriNextEdge[iptr];
1624 }
1625 if ((ned % 2) == 0) {
1626 iptr = torusFirstEdge[nTori];
1627 while (iptr != -1) {
1628 int iv1 = concaveEdgeVertexNumbers[0][iptr];
1629 int iv2 = concaveEdgeVertexNumbers[1][iptr];
1630 int ip1 = vertexProbeNumber[iv1];
1631 int ip2 = vertexProbeNumber[iv2];
1632 logger.warning(format(" Odd Torus for Probes IP1 %d and IP2 %d", ip1, ip2));
1633 iptr = tempToriNextEdge[iptr];
1634 }
1635 }
1636 }
1637 }
1638 }
1639
1640
1641
1642
1643 private void saddles() {
1644 final int maxent = 500;
1645 int[] ten = new int[maxent];
1646 int[] nxtang = new int[maxent];
1647 double[] ai = new double[3];
1648 double[] aj = new double[3];
1649 double[] ak = new double[3];
1650 double[] atvect = new double[3];
1651 double[] teang = new double[maxent];
1652 double[][] tev = new double[3][maxent];
1653 boolean[] sdstrt = new boolean[maxent];
1654
1655
1656 nCircles = -1;
1657 nConvexEdges = -1;
1658 nSaddleFaces = -1;
1659 fill(convexEdgeFirst, -1);
1660 fill(convexEdgeLast, -1);
1661 fill(atomBuried, true);
1662
1663
1664 if (nTori < 0) {
1665 return;
1666 }
1667
1668
1669 for (int it = 0; it <= nTori; it++) {
1670 if (skip[torusAtomNumber[0][it]] && skip[torusAtomNumber[1][it]]) {
1671 continue;
1672 }
1673
1674
1675 for (int in = 0; in < 2; in++) {
1676 int ia = torusAtomNumber[in][it];
1677
1678
1679 atomBuried[ia] = false;
1680
1681
1682 for (int k = 0; k < 3; k++) {
1683 atvect[k] = torusCenter[k][it] - atomCoords[k][ia];
1684 }
1685 double factor = radius[ia] / (radius[ia] + probe);
1686
1687
1688 nCircles++;
1689 if (nCircles >= maxCircles) {
1690 throw new EnergyException(" Too many Circles");
1691 }
1692
1693
1694 for (int k = 0; k < 3; k++) {
1695 circleCenter[k][nCircles] = atomCoords[k][ia] + factor * atvect[k];
1696 }
1697
1698
1699 circleAtomNumber[nCircles] = ia;
1700
1701
1702 circleTorusNumber[nCircles] = it;
1703
1704
1705 circleRadius[nCircles] = factor * torusRadius[it];
1706 }
1707
1708
1709 if (!torusNeighborFreeEdge[it]) {
1710
1711
1712
1713
1714
1715
1716
1717
1718 int nent = -1;
1719
1720
1721 int ien = torusFirstEdge[it];
1722
1723 while (ien >= 0) {
1724
1725 nent++;
1726 if (nent >= maxent) {
1727 throw new EnergyException(" Too many Edges for Torus");
1728 }
1729
1730 int iv = concaveEdgeVertexNumbers[0][ien];
1731
1732
1733 int ip = vertexProbeNumber[iv];
1734 for (int k = 0; k < 3; k++) {
1735 tev[k][nent] = probeCoords[k][ip] - torusCenter[k][it];
1736 }
1737 double dtev = 0.0;
1738 for (int k = 0; k < 3; k++) {
1739 dtev += tev[k][nent] * tev[k][nent];
1740 }
1741 if (dtev <= 0.0) {
1742 throw new EnergyException(" Probe on Torus Axis");
1743 }
1744 dtev = sqrt(dtev);
1745 for (int k = 0; k < 3; k++) {
1746 tev[k][nent] = tev[k][nent] / dtev;
1747 }
1748
1749
1750 ten[nent] = ien;
1751 if (nent > 0) {
1752
1753 double dt = 0.0;
1754 for (int k = 0; k < 3; k++) {
1755 dt += tev[k][0] * tev[k][nent];
1756 }
1757 if (dt > 1.0) {
1758 dt = 1.0;
1759 }
1760 if (dt < -1.0) {
1761 dt = -1.0;
1762 }
1763
1764
1765 teang[nent] = acos(dt);
1766
1767 ai[0] = tev[0][0];
1768 ai[1] = tev[1][0];
1769 ai[2] = tev[2][0];
1770 aj[0] = tev[0][nent];
1771 aj[1] = tev[1][nent];
1772 aj[2] = tev[2][nent];
1773 ak[0] = torusAxis[0][it];
1774 ak[1] = torusAxis[1][it];
1775 ak[2] = torusAxis[2][it];
1776
1777
1778 double triple = tripleProduct(ai, aj, ak);
1779 if (triple < 0.0) {
1780 teang[nent] = 2.0 * Math.PI - teang[nent];
1781 }
1782 } else {
1783 teang[0] = 0.0;
1784 }
1785
1786
1787 sdstrt[nent] = (vertexAtomNumbers[iv] == torusAtomNumber[0][it]);
1788
1789 ien = tempToriNextEdge[ien];
1790 }
1791
1792 if (nent == -1) {
1793 logger.severe(" No Edges for Non-free Torus");
1794 }
1795
1796 if ((nent % 2) == 0) {
1797 throw new EnergyException(" Odd Number of Edges for Torus");
1798 }
1799
1800
1801
1802
1803 for (int ient = 0; ient <= nent; ient++) {
1804 nxtang[ient] = -1;
1805 }
1806 for (int ient = 1; ient <= nent; ient++) {
1807
1808 int l1 = -1;
1809 int l2 = 0;
1810 while (l2 != -1 && teang[ient] >= teang[l2]) {
1811 l1 = l2;
1812 l2 = nxtang[l2];
1813 }
1814
1815 if (l1 == -1) {
1816 throw new EnergyException(" Logic Error in SADDLES", true);
1817 }
1818 nxtang[l1] = ient;
1819 nxtang[ient] = l2;
1820 }
1821
1822
1823
1824 int l1 = 0;
1825 while (l1 > -1) {
1826
1827 if (sdstrt[l1]) {
1828
1829 nSaddleFaces++;
1830 if (nSaddleFaces >= maxSaddleFace) {
1831 throw new EnergyException(" Too many Saddle Faces");
1832 }
1833
1834 ien = ten[l1];
1835
1836 saddleConcaveEdgeNumbers[0][nSaddleFaces] = ien;
1837
1838 nConvexEdges++;
1839 if (nConvexEdges >= maxConvexEdges) {
1840 throw new EnergyException(" Too many Convex Edges");
1841 }
1842
1843 convexEdgeCircleNumber[nConvexEdges] = nCircles;
1844
1845 int ia = circleAtomNumber[nCircles];
1846
1847 insertConvexEdgeForAtom(nConvexEdges, ia);
1848
1849 convexEdgeVertexNumber[0][nConvexEdges] = concaveEdgeVertexNumbers[1][ien];
1850
1851 saddleConvexEdgeNumbers[0][nSaddleFaces] = nConvexEdges;
1852
1853 nConvexEdges++;
1854 if (nConvexEdges >= maxConvexEdges) {
1855 throw new EnergyException(" Too many Convex Edges");
1856 }
1857
1858 convexEdgeCircleNumber[nConvexEdges] = nCircles - 1;
1859 ia = circleAtomNumber[nCircles - 1];
1860
1861 insertConvexEdgeForAtom(nConvexEdges, ia);
1862
1863 convexEdgeVertexNumber[1][nConvexEdges] = concaveEdgeVertexNumbers[0][ien];
1864 l1 = nxtang[l1];
1865
1866 if (l1 <= -1) {
1867 l1 = 0;
1868 }
1869 if (sdstrt[l1]) {
1870 int m1 = nxtang[l1];
1871 if (m1 <= -1) {
1872 m1 = 0;
1873 }
1874 if (sdstrt[m1]) {
1875 throw new EnergyException(" Three Starts in a Row");
1876 }
1877 int n1 = nxtang[m1];
1878
1879 nxtang[l1] = n1;
1880 nxtang[m1] = l1;
1881 l1 = m1;
1882 }
1883 ien = ten[l1];
1884
1885 saddleConcaveEdgeNumbers[1][nSaddleFaces] = ien;
1886
1887 convexEdgeVertexNumber[1][nConvexEdges - 1] = concaveEdgeVertexNumbers[0][ien];
1888
1889 convexEdgeVertexNumber[0][nConvexEdges] = concaveEdgeVertexNumbers[1][ien];
1890 saddleConvexEdgeNumbers[1][nSaddleFaces] = nConvexEdges;
1891
1892 if (l1 == 0) {
1893 break;
1894 }
1895 }
1896
1897 l1 = nxtang[l1];
1898 }
1899 } else {
1900
1901
1902 nSaddleFaces++;
1903 if (nSaddleFaces >= maxSaddleFace) {
1904 throw new EnergyException(" Too many Saddle Faces");
1905 }
1906
1907 saddleConcaveEdgeNumbers[0][nSaddleFaces] = -1;
1908 saddleConcaveEdgeNumbers[1][nSaddleFaces] = -1;
1909
1910 nConvexEdges++;
1911 int ia = circleAtomNumber[nCircles];
1912
1913 insertConvexEdgeForAtom(nConvexEdges, ia);
1914
1915 convexEdgeVertexNumber[0][nConvexEdges] = -1;
1916 convexEdgeVertexNumber[1][nConvexEdges] = -1;
1917
1918 convexEdgeCircleNumber[nConvexEdges] = nCircles;
1919
1920 saddleConvexEdgeNumbers[0][nSaddleFaces] = nConvexEdges;
1921
1922 nConvexEdges++;
1923 ia = circleAtomNumber[nCircles - 1];
1924
1925 insertConvexEdgeForAtom(nConvexEdges, ia);
1926
1927 convexEdgeVertexNumber[0][nConvexEdges] = -1;
1928 convexEdgeVertexNumber[1][nConvexEdges] = -1;
1929
1930 convexEdgeCircleNumber[nConvexEdges] = nCircles - 1;
1931
1932 saddleConvexEdgeNumbers[1][nSaddleFaces] = nConvexEdges;
1933
1934 }
1935 }
1936
1937 logger.fine(format(" Number of circles %d", nCircles + 1));
1938 logger.fine(format(" Number of convex edges %d", nConvexEdges + 1));
1939 logger.fine(format(" Number of saddle faces %d", nSaddleFaces + 1));
1940 }
1941
1942
1943
1944
1945 private void contact() {
1946 final int maxepa = 300;
1947 final int maxcypa = 100;
1948 int[] aic = new int[maxepa];
1949 int[] aia = new int[maxepa];
1950 int[] aep = new int[maxepa];
1951 int[][] av = new int[2][maxepa];
1952 int[] ncyepa = new int[maxcypa];
1953 int[][] cyepa = new int[MAXCYEP][maxcypa];
1954 double[] ai = new double[3];
1955 double[][] acvect = new double[3][maxepa];
1956 double[][] aavect = new double[3][maxepa];
1957 double[] pole = new double[3];
1958 double[] acr = new double[maxepa];
1959 double[] unvect = new double[3];
1960 boolean[] epused = new boolean[maxepa];
1961 boolean[][] cycy = new boolean[maxcypa][maxcypa];
1962 boolean[] cyused = new boolean[maxcypa];
1963 boolean[][] samef = new boolean[maxcypa][maxcypa];
1964
1965
1966 nCycles = -1;
1967 nConvexFaces = -1;
1968
1969
1970 for (int ia = 0; ia < nAtoms; ia++) {
1971 if (atomFreeOfNeighbors[ia]) {
1972 atomBuried[ia] = false;
1973 }
1974 }
1975
1976
1977 atomLoop:
1978 for (int ia = 0; ia < nAtoms; ia++) {
1979 if (skip[ia] || atomBuried[ia]) {
1980 continue;
1981 }
1982
1983
1984 for (int o = 0; o < 1; o++) {
1985 if (atomFreeOfNeighbors[ia]) {
1986 continue;
1987 }
1988
1989 int nepa = -1;
1990
1991 int iep = convexEdgeFirst[ia];
1992
1993 while (iep > -1) {
1994
1995 nepa++;
1996 if (nepa >= maxepa) {
1997 throw new EnergyException(" Too many Convex Edges for Atom");
1998 }
1999
2000 av[0][nepa] = convexEdgeVertexNumber[0][iep];
2001 av[1][nepa] = convexEdgeVertexNumber[1][iep];
2002
2003 aep[nepa] = iep;
2004 int ic = convexEdgeCircleNumber[iep];
2005
2006 aic[nepa] = ic;
2007
2008 int it = circleTorusNumber[ic];
2009 int ia2;
2010 if (torusAtomNumber[0][it] == ia) {
2011 ia2 = torusAtomNumber[1][it];
2012 } else {
2013 ia2 = torusAtomNumber[0][it];
2014 }
2015
2016 aia[nepa] = ia2;
2017
2018
2019
2020
2021
2022 for (int k = 0; k < 3; k++) {
2023 acvect[k][nepa] = circleCenter[k][ic] - atomCoords[k][ia];
2024 aavect[k][nepa] = atomCoords[k][ia2] - atomCoords[k][ia];
2025 }
2026
2027 acr[nepa] = circleRadius[ic];
2028
2029 iep = convexEdgeNext[iep];
2030 }
2031 if (nepa == -1) {
2032 throw new EnergyException(" No Edges for Non-buried, Non-free Atom");
2033 }
2034
2035 for (int iepa = 0; iepa < nepa + 1; iepa++) {
2036 epused[iepa] = false;
2037 }
2038
2039 int ncyold = nCycles;
2040 int nused = -1;
2041 int ncypa = -1;
2042 while (nused < nepa) {
2043
2044 int iepa;
2045 for (iepa = 0; iepa <= nepa; iepa++) {
2046 if (!epused[iepa]) {
2047 break;
2048 }
2049 }
2050 if (iepa > nepa) {
2051
2052 break;
2053 }
2054
2055 iep = aep[iepa];
2056
2057 int ncyep = 0;
2058
2059 ncypa++;
2060 if (ncypa >= maxcypa) {
2061 throw new EnergyException(" Too many Cycles per Atom");
2062 }
2063
2064 epused[iepa] = true;
2065 nused++;
2066
2067 nCycles++;
2068 if (nCycles >= maxCycles) {
2069 throw new EnergyException(" Too many Cycles");
2070 }
2071
2072 cyepa[ncyep][ncypa] = iepa;
2073
2074 convexEdgeCycleNumbers[ncyep][nCycles] = iep;
2075
2076
2077 int lookv = av[1][iepa];
2078
2079 if (lookv > -1) {
2080 for (int jepa = 0; jepa < nepa + 1; jepa++) {
2081 if (epused[jepa]) {
2082 continue;
2083 }
2084
2085 if (av[0][jepa] != lookv) {
2086 continue;
2087 }
2088
2089 iep = aep[jepa];
2090
2091 ncyep++;
2092 if (ncyep >= MAXCYEP) {
2093 throw new EnergyException(" Too many Edges per Cycle");
2094 }
2095 epused[jepa] = true;
2096 nused++;
2097
2098 cyepa[ncyep][ncypa] = jepa;
2099
2100 convexEdgeCycleNumbers[ncyep][nCycles] = iep;
2101
2102 lookv = av[1][jepa];
2103
2104 if (lookv <= -1) {
2105 throw new EnergyException(" Pointer Error in Cycle", true);
2106 }
2107 jepa = 0;
2108 }
2109
2110 if (lookv != av[0][iepa]) {
2111 throw new EnergyException(" Cycle does not Close", true);
2112 }
2113 }
2114
2115 ncyepa[ncypa] = ncyep;
2116 convexEdgeCycleNum[nCycles] = ncyep;
2117 }
2118
2119
2120 for (int icya = 0; icya <= ncypa; icya++) {
2121 innerLoop:
2122 for (int jcya = 0; jcya <= ncypa; jcya++) {
2123 int jcy = ncyold + jcya + 1;
2124
2125 cycy[icya][jcya] = true;
2126
2127 if (icya == jcya || ncyepa[jcya] < 2) {
2128 continue;
2129 }
2130
2131
2132 for (int icyep = 0; icyep <= ncyepa[icya]; icyep++) {
2133 int iepa = cyepa[icyep][icya];
2134 int ic = aic[iepa];
2135 for (int jcyep = 0; jcyep <= ncyepa[jcya]; jcyep++) {
2136 int jepa = cyepa[jcyep][jcya];
2137 int jc = aic[jepa];
2138 if (ic == jc) {
2139 cycy[icya][jcya] = false;
2140 continue innerLoop;
2141 }
2142 }
2143 }
2144 int iepa = cyepa[0][icya];
2145 ai[0] = aavect[0][iepa];
2146 ai[1] = aavect[1][iepa];
2147 ai[2] = aavect[2][iepa];
2148 double anaa = length(ai);
2149 double factor = radius[ia] / anaa;
2150
2151 for (int k = 0; k < 3; k++) {
2152 pole[k] = factor * aavect[k][iepa] + atomCoords[k][ia];
2153 unvect[k] = -aavect[k][iepa] / anaa;
2154 }
2155 cycy[icya][jcya] = ptincy(pole, unvect, jcy);
2156 }
2157 }
2158
2159 for (int icya = 0; icya <= ncypa; icya++) {
2160 for (int jcya = 0; jcya <= ncypa; jcya++) {
2161
2162
2163 samef[icya][jcya] = (cycy[icya][jcya] && cycy[jcya][icya]);
2164 }
2165 }
2166
2167
2168 for (int icya = 0; icya <= ncypa; icya++) {
2169 for (int jcya = 0; jcya <= ncypa; jcya++) {
2170 if (icya != jcya) {
2171 for (int kcya = 0; kcya <= ncypa; kcya++) {
2172 if (kcya != icya && kcya != jcya) {
2173 if (cycy[kcya][icya] && cycy[kcya][jcya] && (!cycy[icya][kcya])) {
2174 samef[icya][jcya] = false;
2175 samef[jcya][icya] = false;
2176 }
2177 }
2178 }
2179 }
2180 }
2181 }
2182
2183 for (int icya = 0; icya < ncypa - 1; icya++) {
2184 for (int jcya = icya + 1; jcya < ncypa; jcya++) {
2185 if (samef[icya][jcya]) {
2186 for (int kcya = jcya + 1; kcya <= ncypa; kcya++) {
2187 if (samef[jcya][kcya]) {
2188 samef[icya][kcya] = true;
2189 samef[kcya][icya] = true;
2190 }
2191 }
2192 }
2193 }
2194 }
2195
2196 for (int icya = 0; icya <= ncypa; icya++) {
2197 cyused[icya] = false;
2198 }
2199
2200 nused = -1;
2201 for (int icya = 0; icya <= ncypa; icya++) {
2202
2203 if (cyused[icya]) {
2204 continue;
2205 }
2206
2207 nConvexFaces++;
2208 if (nConvexFaces >= maxConvexFaces) {
2209 throw new EnergyException(" Too many Convex Faces");
2210 }
2211
2212 convexFaceNumCycles[nConvexFaces] = -1;
2213
2214 convexFaceAtomNumber[nConvexFaces] = ia;
2215
2216 for (int jcya = 0; jcya <= ncypa; jcya++) {
2217
2218 if (cyused[jcya]) {
2219 continue;
2220 }
2221
2222 if (!samef[icya][jcya]) {
2223 continue;
2224 }
2225
2226 cyused[jcya] = true;
2227 nused++;
2228
2229 convexFaceNumCycles[nConvexFaces]++;
2230 if (convexFaceNumCycles[nConvexFaces] >= MAXFPCY) {
2231 throw new EnergyException(" Too many Cycles bounding Convex Face");
2232 }
2233 int i = convexFaceNumCycles[nConvexFaces];
2234
2235 convexFaceCycleNumbers[i][nConvexFaces] = ncyold + jcya + 1;
2236
2237 if (nused >= ncypa) {
2238 continue atomLoop;
2239 }
2240 }
2241 }
2242
2243 throw new EnergyException(" Not all Cycles grouped into Convex Faces", true);
2244 }
2245
2246 nConvexFaces++;
2247 if (nConvexFaces >= maxConvexFaces) {
2248 throw new EnergyException(" Too many Convex Faces");
2249 }
2250 convexFaceAtomNumber[nConvexFaces] = ia;
2251 convexFaceNumCycles[nConvexFaces] = -1;
2252 }
2253 }
2254
2255
2256
2257
2258
2259 private void vam() {
2260 final int maxdot = 1000;
2261 final int maxop = 100;
2262 final int nscale = 20;
2263 int[] ivs = new int[3];
2264 int[] ispind = new int[3];
2265 int[] ispnd2 = new int[3];
2266 int[] ifnop = new int[maxop];
2267 int[] enfs = new int[20 * nAtoms];
2268 double[][] cenop = new double[3][maxop];
2269 double[] sdot = new double[3];
2270 double[] dotv = new double[nscale];
2271 double[] tau = new double[3];
2272 double[] ppm = new double[3];
2273 double[] xpnt1 = new double[3];
2274 double[] xpnt2 = new double[3];
2275 double[] qij = new double[3];
2276 double[] qji = new double[3];
2277 double[][] vects = new double[3][3];
2278 double[] vect1 = new double[3];
2279 double[] vect2 = new double[3];
2280 double[] vect3 = new double[3];
2281 double[] vect4 = new double[3];
2282 double[] vect5 = new double[3];
2283 double[] vect6 = new double[3];
2284 double[] vect7 = new double[3];
2285 double[] vect8 = new double[3];
2286 double[] upp = new double[3];
2287 double[] thetaq = new double[3];
2288 double[] sigmaq = new double[3];
2289 double[] umq = new double[3];
2290 double[] upq = new double[3];
2291 double[] uc = new double[3];
2292 double[] uq = new double[3];
2293 double[] uij = new double[3];
2294 double[] ai = new double[3];
2295 double[] aj = new double[3];
2296 double[] ak = new double[3];
2297 double[] al = new double[3];
2298 double[][] dots = new double[3][maxdot];
2299 double[][] tdots = new double[3][maxdot];
2300 double[] atomArea = new double[nAtoms];
2301 boolean[] ate = new boolean[maxop];
2302 boolean[] vip = new boolean[3];
2303 boolean[] cinsp = new boolean[1];
2304
2305 int[] nlap = null;
2306 int[][] fnt = null;
2307 int[][] nspt = null;
2308 double[] depths = null;
2309 double[] cora = null;
2310 double[] corv = null;
2311 double[][] alts = null;
2312 double[][] fncen = null;
2313 double[][][] fnvect = null;
2314 boolean[] badav = null;
2315 boolean[] badt = null;
2316 boolean[][] fcins = null;
2317 boolean[][] fcint = null;
2318 boolean[][] fntrev = null;
2319 if (nConcaveFaces >= 0) {
2320 nlap = new int[nConcaveFaces + 1];
2321 fnt = new int[3][nConcaveFaces + 1];
2322 nspt = new int[3][nConcaveFaces + 1];
2323 depths = new double[nConcaveFaces + 1];
2324 cora = new double[nConcaveFaces + 1];
2325 corv = new double[nConcaveFaces + 1];
2326 alts = new double[3][nConcaveFaces + 1];
2327 fncen = new double[3][nConcaveFaces + 1];
2328 fnvect = new double[3][3][nConcaveFaces + 1];
2329 badav = new boolean[nConcaveFaces + 1];
2330 badt = new boolean[nConcaveFaces + 1];
2331 fcins = new boolean[3][nConcaveFaces + 1];
2332 fcint = new boolean[3][nConcaveFaces + 1];
2333 fntrev = new boolean[3][nConcaveFaces + 1];
2334 }
2335
2336
2337 double polyhedronVolume = 0.0;
2338 for (int i = 0; i <= nConcaveFaces; i++) {
2339 polyhedronVolume += measurePrism(i);
2340 }
2341
2342
2343
2344 double convexFaceArea = 0.0;
2345 double convexFaceVolume = 0.0;
2346 fill(atomArea, 0.0);
2347 double[] convexFaces = {0.0, 0.0};
2348 for (int i = 0; i <= nConvexFaces; i++) {
2349 measureConvexFace(i, convexFaces);
2350 int ia = convexFaceAtomNumber[i];
2351 atomArea[ia] += convexFaces[0];
2352 convexFaceArea += convexFaces[0];
2353 convexFaceVolume += convexFaces[1];
2354 }
2355
2356
2357
2358 double saddleFaceArea = 0.0;
2359 double saddleFaceVolume = 0.0;
2360 double spindleArea = 0.0;
2361 double spindleVolume = 0.0;
2362 double[] saddle = {0.0, 0.0, 0.0, 0.0};
2363 for (int i = 0; i <= nSaddleFaces; i++) {
2364 for (int k = 0; k < 2; k++) {
2365 int ien = saddleConcaveEdgeNumbers[k][i];
2366 if (ien > -1) {
2367 enfs[ien] = i;
2368 }
2369 }
2370 measureSaddleFace(i, saddle);
2371 double areas = saddle[0];
2372 double vols = saddle[1];
2373 double areasp = saddle[2];
2374 double volsp = saddle[3];
2375 saddleFaceArea += areas;
2376 saddleFaceVolume += vols;
2377 spindleArea += areasp;
2378 spindleVolume += volsp;
2379 if (areas - areasp < 0.0) {
2380 throw new EnergyException(" Negative Area for Saddle Face", true);
2381 }
2382 }
2383
2384
2385 double concaveFaceArea = 0.0;
2386 double concaveFaceVolume = 0.0;
2387 double[] concaveFaces = {0.0, 0.0};
2388 for (int i = 0; i <= nConcaveFaces; i++) {
2389 measureConcaveFace(i, concaveFaces);
2390 double arean = concaveFaces[0];
2391 double voln = concaveFaces[1];
2392 concaveFaceArea += arean;
2393 concaveFaceVolume += voln;
2394 }
2395
2396
2397 double lensArea = 0.0;
2398 double lensAreaNumeric = 0.0;
2399 double lensVolume = 0.0;
2400 double lensVolumeNumeric = 0.0;
2401
2402 if (probe > 0.0) {
2403 int ndots = genDots(maxdot, dots, probe);
2404 double dota = (4.0 * PI * probe * probe) / ndots;
2405 for (int ifn = 0; ifn <= nConcaveFaces; ifn++) {
2406 nlap[ifn] = -1;
2407 cora[ifn] = 0.0;
2408 corv[ifn] = 0.0;
2409 badav[ifn] = false;
2410 badt[ifn] = false;
2411 for (int k = 0; k < 3; k++) {
2412 nspt[k][ifn] = -1;
2413 }
2414 int ien = concaveFaceEdgeNumbers[0][ifn];
2415 int iv = concaveEdgeVertexNumbers[0][ien];
2416 int ip = vertexProbeNumber[iv];
2417 getVector(ai, alts, ifn);
2418 depths[ifn] = depth(ip, ai);
2419 for (int k = 0; k < 3; k++) {
2420 fncen[k][ifn] = probeCoords[k][ip];
2421 }
2422
2423 for (int ke = 0; ke < 3; ke++) {
2424 ien = concaveFaceEdgeNumbers[ke][ifn];
2425 ivs[ke] = concaveEdgeVertexNumbers[0][ien];
2426 int ia = vertexAtomNumbers[ivs[ke]];
2427 int ifs = enfs[ien];
2428 int iep = saddleConvexEdgeNumbers[0][ifs];
2429 int ic = convexEdgeCircleNumber[iep];
2430 int it = circleTorusNumber[ic];
2431 fnt[ke][ifn] = it;
2432 fntrev[ke][ifn] = (torusAtomNumber[0][it] != ia);
2433 }
2434 for (int ke = 0; ke < 3; ke++) {
2435 for (int k = 0; k < 3; k++) {
2436 vects[k][ke] = vertexCoords[k][ivs[ke]] - probeCoords[k][ip];
2437 }
2438 }
2439
2440
2441 getVector(ai, vects, 0);
2442 getVector(aj, vects, 1);
2443 X(ai, aj, ak);
2444 normalize(ak, ak);
2445 putVector(ak, fnvect, 0, ifn);
2446 getVector(ak, vects, 2);
2447 X(aj, ak, ai);
2448 normalize(ai, ai);
2449 putVector(ai, fnvect, 1, ifn);
2450 getVector(ai, vects, 0);
2451 X(ak, ai, aj);
2452 normalize(aj, aj);
2453 putVector(aj, fnvect, 2, ifn);
2454 }
2455 for (int ifn = 0; ifn <= nConcaveFaces - 1; ifn++) {
2456 for (int jfn = ifn + 1; jfn <= nConcaveFaces; jfn++) {
2457 getVector(ai, fncen, ifn);
2458 getVector(aj, fncen, jfn);
2459 double dij2 = dist2(ai, aj);
2460 if (dij2 > 4.0 * probe * probe) {
2461 continue;
2462 }
2463 if (depths[ifn] > probe && depths[jfn] > probe) {
2464 continue;
2465 }
2466
2467 double dpp = dist(ai, aj);
2468
2469 for (int k = 0; k < 3; k++) {
2470 ppm[k] = (fncen[k][ifn] + fncen[k][jfn]) / 2.0;
2471 upp[k] = (fncen[k][jfn] - fncen[k][ifn]) / dpp;
2472 }
2473 double rm = probe * probe - (dpp / 2.0) * (dpp / 2.0);
2474 if (rm < 0.0) {
2475 rm = 0.0;
2476 }
2477 rm = sqrt(rm);
2478 double rat = check(dpp / (2.0 * probe));
2479 double rho = asin(rat);
2480
2481 boolean alli = true;
2482 boolean anyi = false;
2483 boolean spindl = false;
2484 for (int k = 0; k < 3; k++) {
2485 ispind[k] = -1;
2486 ispnd2[k] = -1;
2487 }
2488 for (int ke = 0; ke < 3; ke++) {
2489 thetaq[ke] = 0.0;
2490 sigmaq[ke] = 0.0;
2491 tau[ke] = 0.0;
2492 getVector(ai, fncen, ifn);
2493 getVector(aj, fnvect, ke, ifn);
2494 boolean cintp = circlePlane(ppm, rm, upp, ai, aj, cinsp, xpnt1, xpnt2);
2495 fcins[ke][ifn] = cinsp[0];
2496 fcint[ke][ifn] = cintp;
2497 if (!cinsp[0]) {
2498 alli = false;
2499 }
2500 if (cintp) {
2501 anyi = true;
2502 }
2503 if (!cintp) {
2504 continue;
2505 }
2506 int it = fnt[ke][ifn];
2507 if (torusRadius[it] > probe) {
2508 continue;
2509 }
2510 for (int ke2 = 0; ke2 < 3; ke2++) {
2511 if (it == fnt[ke2][jfn]) {
2512 ispind[ke] = it;
2513 nspt[ke][ifn]++;
2514 ispnd2[ke2] = it;
2515 nspt[ke2][jfn]++;
2516 spindl = true;
2517 }
2518 }
2519 if (ispind[ke] == -1) {
2520 continue;
2521 }
2522
2523
2524 rat = check(torusRadius[it] / probe);
2525 thetaq[ke] = acos(rat);
2526 double stq = sin(thetaq[ke]);
2527 if (fntrev[ke][ifn]) {
2528 for (int k = 0; k < 3; k++) {
2529 uij[k] = -torusAxis[k][it];
2530 }
2531 } else {
2532 for (int k = 0; k < 3; k++) {
2533 uij[k] = torusAxis[k][it];
2534 }
2535 }
2536 for (int k = 0; k < 3; k++) {
2537 qij[k] = torusCenter[k][it] - stq * probe * uij[k];
2538 qji[k] = torusCenter[k][it] + stq * probe * uij[k];
2539 }
2540 for (int k = 0; k < 3; k++) {
2541 umq[k] = (qij[k] - ppm[k]) / rm;
2542 upq[k] = (qij[k] - fncen[k][ifn]) / probe;
2543 }
2544 X(uij, upp, vect1);
2545 double dt = check(dot(umq, vect1));
2546 sigmaq[ke] = acos(dt);
2547 getVector(ai, fnvect, ke, ifn);
2548 X(upq, ai, vect1);
2549 normalize(vect1, uc);
2550 X(upp, upq, vect1);
2551 normalize(vect1, uq);
2552 dt = check(dot(uc, uq));
2553 tau[ke] = PI - acos(dt);
2554 }
2555 boolean allj = true;
2556 boolean anyj = false;
2557 for (int ke = 0; ke < 3; ke++) {
2558 getVector(ai, fncen, jfn);
2559 getVector(aj, fnvect, ke, jfn);
2560 boolean cintp = circlePlane(ppm, rm, upp, ai, aj, cinsp, xpnt1, xpnt2);
2561 fcins[ke][jfn] = cinsp[0];
2562 fcint[ke][jfn] = cintp;
2563 if (!cinsp[0]) {
2564 allj = false;
2565 }
2566 if (cintp) {
2567 anyj = true;
2568 }
2569 }
2570 boolean case1 = (alli && allj && !anyi && !anyj);
2571 boolean case2 = (anyi && anyj && spindl);
2572 if (!case1 && !case2) {
2573 continue;
2574 }
2575
2576 nlap[ifn]++;
2577 nlap[jfn]++;
2578 for (int ke = 0; ke < 3; ke++) {
2579 int ien = concaveFaceEdgeNumbers[ke][ifn];
2580 int iv1 = concaveEdgeVertexNumbers[0][ien];
2581 int iv2 = concaveEdgeVertexNumbers[1][ien];
2582 for (int k = 0; k < 3; k++) {
2583 vect3[k] = vertexCoords[k][iv1] - fncen[k][ifn];
2584 vect4[k] = vertexCoords[k][iv2] - fncen[k][ifn];
2585 }
2586 for (int ke2 = 0; ke2 < 3; ke2++) {
2587 if (ispind[ke] == ispnd2[ke2] || ispind[ke] == -1) {
2588 continue;
2589 }
2590 getVector(ai, fncen, ifn);
2591 getVector(aj, fnvect, ke, ifn);
2592 getVector(ak, fncen, jfn);
2593 getVector(al, fnvect, ke2, jfn);
2594 boolean cintp = circlePlane(ai, probe, aj, ak, al, cinsp, xpnt1, xpnt2);
2595 if (!cintp) {
2596 continue;
2597 }
2598 ien = concaveFaceEdgeNumbers[ke2][jfn];
2599 iv1 = concaveEdgeVertexNumbers[0][ien];
2600 iv2 = concaveEdgeVertexNumbers[1][ien];
2601 for (int k = 0; k < 3; k++) {
2602 vect7[k] = vertexCoords[k][iv1] - fncen[k][jfn];
2603 vect8[k] = vertexCoords[k][iv2] - fncen[k][jfn];
2604 }
2605
2606 for (int k = 0; k < 3; k++) {
2607 vect1[k] = xpnt1[k] - fncen[k][ifn];
2608 vect2[k] = xpnt2[k] - fncen[k][ifn];
2609 vect5[k] = xpnt1[k] - fncen[k][jfn];
2610 vect6[k] = xpnt2[k] - fncen[k][jfn];
2611 }
2612
2613 getVector(ai, fnvect, ke, ifn);
2614 getVector(aj, fnvect, ke2, jfn);
2615 if (tripleProduct(vect3, vect1, ai) < 0.0
2616 || tripleProduct(vect1, vect4, ai) < 0.0
2617 || tripleProduct(vect7, vect5, aj) < 0.0
2618 || tripleProduct(vect5, vect8, aj) < 0.0) {
2619 if (!(tripleProduct(vect3, vect2, ai) < 0.0
2620 || tripleProduct(vect2, vect4, ai) < 0.0
2621 || tripleProduct(vect7, vect6, aj) < 0.0
2622 || tripleProduct(vect6, vect8, aj) < 0.0)) {
2623 badav[ifn] = true;
2624 }
2625 } else {
2626 badav[ifn] = true;
2627 }
2628 }
2629 }
2630 for (int ke = 0; ke < 3; ke++) {
2631 int ien = concaveFaceEdgeNumbers[ke][ifn];
2632 int iv1 = concaveEdgeVertexNumbers[0][ien];
2633 int iv2 = concaveEdgeVertexNumbers[1][ien];
2634 for (int k = 0; k < 3; k++) {
2635 vect3[k] = vertexCoords[k][iv1] - fncen[k][ifn];
2636 vect4[k] = vertexCoords[k][iv2] - fncen[k][ifn];
2637 }
2638 for (int ke2 = 0; ke2 < 3; ke2++) {
2639 if (ispind[ke] == ispnd2[ke2] || ispnd2[ke2] == -1) {
2640 continue;
2641 }
2642 getVector(ai, fncen, ifn);
2643 getVector(aj, fnvect, ke, ifn);
2644 getVector(ak, fncen, jfn);
2645 getVector(al, fnvect, ke2, jfn);
2646 boolean cintp = circlePlane(ak, probe, al, ai, aj, cinsp, xpnt1, xpnt2);
2647 if (!cintp) {
2648 continue;
2649 }
2650 ien = concaveFaceEdgeNumbers[ke2][jfn];
2651 iv1 = concaveEdgeVertexNumbers[0][ien];
2652 iv2 = concaveEdgeVertexNumbers[1][ien];
2653 for (int k = 0; k < 3; k++) {
2654 vect7[k] = vertexCoords[k][iv1] - fncen[k][jfn];
2655 vect8[k] = vertexCoords[k][iv2] - fncen[k][jfn];
2656 }
2657
2658 for (int k = 0; k < 3; k++) {
2659 vect1[k] = xpnt1[k] - fncen[k][ifn];
2660 vect2[k] = xpnt2[k] - fncen[k][ifn];
2661 vect5[k] = xpnt1[k] - fncen[k][jfn];
2662 vect6[k] = xpnt2[k] - fncen[k][jfn];
2663 }
2664
2665 getVector(ai, fnvect, ke, ifn);
2666 getVector(aj, fnvect, ke2, jfn);
2667 if (tripleProduct(vect3, vect1, ai) < 0.0
2668 || tripleProduct(vect1, vect4, ai) < 0.0
2669 || tripleProduct(vect7, vect5, aj) < 0.0
2670 || tripleProduct(vect5, vect8, aj) < 0.0) {
2671 if (!(tripleProduct(vect3, vect2, ai) < 0.0
2672 || tripleProduct(vect2, vect4, ai) < 0.0
2673 || tripleProduct(vect7, vect6, aj) < 0.0
2674 || tripleProduct(vect6, vect8, aj) < 0.0)) {
2675 badav[jfn] = true;
2676 }
2677 } else {
2678 badav[jfn] = true;
2679 }
2680 }
2681 }
2682
2683 double sumlam = 0.0;
2684 double sumsig = 0.0;
2685 double sumsc = 0.0;
2686 for (int ke = 0; ke < 3; ke++) {
2687 if (ispind[ke] != -1) {
2688 sumlam += (PI - tau[ke]);
2689 sumsig += (sigmaq[ke] - PI);
2690 sumsc += (sin(sigmaq[ke]) * cos(sigmaq[ke]));
2691 }
2692 }
2693 double alens = 2.0 * probe * probe * (PI - sumlam - sin(rho) * (PI + sumsig));
2694 double vint = alens * probe / 3.0;
2695 double vcone = probe * rm * rm * sin(rho) * (PI + sumsig) / 3.0;
2696 double vpyr = probe * rm * rm * sin(rho) * sumsc / 3.0;
2697 double vlens = vint - vcone + vpyr;
2698 cora[ifn] += alens;
2699 cora[jfn] += alens;
2700 corv[ifn] += vlens;
2701 corv[jfn] += vlens;
2702
2703
2704 outerloop:
2705 for (int kv = 0; kv < 3; kv++) {
2706 vip[kv] = false;
2707 int ien = concaveFaceEdgeNumbers[kv][jfn];
2708 int iv = concaveEdgeVertexNumbers[0][ien];
2709 for (int k = 0; k < 3; k++) {
2710 vect1[k] = vertexCoords[k][iv] - fncen[k][ifn];
2711 }
2712 normalize(vect1, vect1);
2713 for (int ke = 0; ke < 3; ke++) {
2714 getVector(ai, fnvect, ke, ifn);
2715 getVector(aj, vertexCoords, iv);
2716 double dt = dot(ai, aj);
2717 if (dt > 0.0) {
2718 continue outerloop;
2719 }
2720 vip[kv] = true;
2721 }
2722 }
2723 }
2724 }
2725
2726 outerLoop:
2727 for (int ifn = 0; ifn <= nConcaveFaces; ifn++) {
2728 for (int ke = 0; ke < 3; ke++) {
2729 if (nspt[ke][ifn] > 0) {
2730 badt[ifn] = true;
2731 break outerLoop;
2732 }
2733 }
2734 }
2735
2736 double fourProbe2 = 4.0 * probe * probe;
2737 for (int ifn = 0; ifn <= nConcaveFaces; ifn++) {
2738 if (nlap[ifn] <= -1) {
2739 continue;
2740 }
2741
2742 int nop = -1;
2743 for (int jfn = 0; jfn <= nConcaveFaces; jfn++) {
2744 if (ifn != jfn) {
2745 getVector(ai, fncen, ifn);
2746 getVector(aj, fncen, jfn);
2747 double dij2 = dist2(ai, aj);
2748 if (dij2 <= fourProbe2 && depths[jfn] <= probe) {
2749 nop++;
2750 if (nop >= maxop) {
2751 throw new EnergyException(" NOP Overflow in VAM");
2752 }
2753 ifnop[nop] = jfn;
2754 for (int k = 0; k < 3; k++) {
2755 cenop[k][nop] = fncen[k][jfn];
2756 }
2757 }
2758 }
2759 }
2760
2761
2762 double areado = 0.0;
2763 double voldo = 0.0;
2764 double scinc = 1.0 / nscale;
2765 for (int isc = 0; isc < nscale; isc++) {
2766 double rsc = (isc + 1) - 0.5;
2767 dotv[isc] = probe * dota * rsc * rsc * scinc * scinc * scinc;
2768 }
2769 for (int iop = 0; iop <= nop; iop++) {
2770 ate[iop] = false;
2771 }
2772 int neatmx = 0;
2773 dotLoop:
2774 for (int idot = 0; idot < ndots; idot++) {
2775 for (int ke = 0; ke < 3; ke++) {
2776 getVector(ai, fnvect, ke, ifn);
2777 getVector(aj, dots, idot);
2778 double dt = dot(ai, aj);
2779 if (dt > 0.0) {
2780 continue dotLoop;
2781 }
2782 }
2783 for (int k = 0; k < 3; k++) {
2784 tdots[k][idot] = fncen[k][ifn] + dots[k][idot];
2785 }
2786 for (int iop = 0; iop <= nop; iop++) {
2787 int jfn = ifnop[iop];
2788 getVector(ai, tdots, idot);
2789 getVector(aj, fncen, jfn);
2790 double ds2 = dist2(ai, aj);
2791 if (ds2 < probe * probe) {
2792 areado += dota;
2793 break;
2794 }
2795 }
2796 for (int isc = 0; isc < nscale; isc++) {
2797 double rsc = (isc + 1) - 0.5;
2798 for (int k = 0; k < 3; k++) {
2799 sdot[k] = fncen[k][ifn] + rsc * scinc * dots[k][idot];
2800 }
2801 int neat = 0;
2802 optLoop:
2803 for (int iop = 0; iop <= nop; iop++) {
2804 int jfn = ifnop[iop];
2805 getVector(ai, fncen, jfn);
2806 double ds2 = dist2(sdot, ai);
2807 if (ds2 < probe * probe) {
2808 for (int k = 0; k < 3; k++) {
2809 vect1[k] = sdot[k] - fncen[k][jfn];
2810 }
2811 for (int ke = 0; ke < 3; ke++) {
2812 getVector(ai, fnvect, ke, jfn);
2813 double dt = dot(ai, vect1);
2814 if (dt > 0.0) {
2815 continue optLoop;
2816 }
2817 }
2818 neat++;
2819 ate[iop] = true;
2820 }
2821 }
2822 if (neat > neatmx) {
2823 neatmx = neat;
2824 }
2825 if (neat > 0) {
2826 voldo += dotv[isc] * (neat / (1.0 + neat));
2827 }
2828 }
2829 }
2830 double coran = areado;
2831 double corvn = voldo;
2832 int nate = 0;
2833 for (int iop = 0; iop <= nop; iop++) {
2834 if (ate[iop]) {
2835 nate++;
2836 }
2837 }
2838
2839
2840 boolean usenum = (nate > nlap[ifn] + 1 || neatmx > 1 || badt[ifn]);
2841 if (usenum) {
2842 cora[ifn] = coran;
2843 corv[ifn] = corvn;
2844 lensAreaNumeric += cora[ifn];
2845 lensVolumeNumeric += corv[ifn];
2846 } else if (badav[ifn]) {
2847 corv[ifn] = corvn;
2848 lensVolumeNumeric += corv[ifn];
2849 }
2850 lensArea += cora[ifn];
2851 lensVolume += corv[ifn];
2852 }
2853 }
2854
2855 if (logger.isLoggable(Level.FINE)) {
2856 logger.fine(
2857 format(
2858 " Convex Faces: %6d Area: %12.6f Volume: %12.6f",
2859 nConvexFaces + 1, convexFaceArea, convexFaceVolume));
2860 logger.fine(
2861 format(
2862 " Saddle Faces: %6d Area: %12.6f Volume: %12.6f",
2863 nSaddleFaces + 1, saddleFaceArea, saddleFaceVolume));
2864 logger.fine(
2865 format(
2866 " Concave Faces: %6d Area: %12.6f Volume: %12.6f",
2867 nConcaveFaces + 1, concaveFaceArea, concaveFaceVolume));
2868 logger.fine(
2869 format(
2870 " Buried Polyhedron: Volume: %12.6f", polyhedronVolume));
2871 if (probe > 0.0) {
2872 logger.fine(
2873 format(
2874 "\n Spindle Correction: Area: %12.6f Volume: %12.6f",
2875 -spindleArea, -spindleVolume));
2876 logger.fine(
2877 format(
2878 " Lens Analytic Correction: Area: %12.6f Volume: %12.6f",
2879 -lensArea - lensAreaNumeric, lensVolume - lensVolumeNumeric));
2880 logger.fine(
2881 format(
2882 " Lens Numerical Correction: Area: %12.6f Volume: %12.6f",
2883 lensAreaNumeric, lensVolumeNumeric));
2884 }
2885 }
2886
2887
2888 double area = convexFaceArea + saddleFaceArea + concaveFaceArea - spindleArea - lensArea;
2889 double volume =
2890 convexFaceVolume
2891 + saddleFaceVolume
2892 + concaveFaceVolume
2893 + polyhedronVolume
2894 - spindleVolume
2895 + lensVolume;
2896
2897 localVolume += volume;
2898 localSurfaceArea += area;
2899 }
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910 private double tripleProduct(double[] x, double[] y, double[] z) {
2911 double[] xy = new double[3];
2912 X(x, y, xy);
2913 return dot(xy, z);
2914 }
2915
2916
2917
2918
2919
2920
2921
2922 private void insertConvexEdgeForAtom(int edgeNumber, int atomNumber) {
2923 if (edgeNumber <= -1) {
2924 throw new EnergyException(" Bad Edge Number in IPEDGE", true);
2925 }
2926 if (atomNumber <= -1) {
2927 throw new EnergyException(" Bad Atom Number in IPEDGE", true);
2928 }
2929
2930 if (convexEdgeFirst[atomNumber] == -1) {
2931 convexEdgeFirst[atomNumber] = edgeNumber;
2932 } else {
2933 convexEdgeNext[convexEdgeLast[atomNumber]] = edgeNumber;
2934 }
2935 convexEdgeNext[edgeNumber] = -1;
2936 convexEdgeLast[atomNumber] = edgeNumber;
2937 }
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947 private boolean ptincy(double[] northPole, double[] unitVector, int icy) {
2948 double[] acvect = new double[3];
2949 double[] cpvect = new double[3];
2950 double[][] projectedVertsForConvexEdges = new double[3][MAXCYEP];
2951 double[][] unitVectorsAlongEdges = new double[3][MAXCYEP];
2952
2953 int iatom = -1;
2954 for (int ke = 0; ke <= convexEdgeCycleNum[icy]; ke++) {
2955 int iep = convexEdgeCycleNumbers[ke][icy];
2956 int ic = convexEdgeCircleNumber[iep];
2957 int it = circleTorusNumber[ic];
2958 iatom = circleAtomNumber[ic];
2959 int iaoth;
2960 if (torusAtomNumber[0][it] == iatom) {
2961 iaoth = torusAtomNumber[1][it];
2962 } else {
2963 iaoth = torusAtomNumber[0][it];
2964 }
2965 for (int k = 0; k < 3; k++) {
2966 acvect[k] = atomCoords[k][iaoth] - atomCoords[k][iatom];
2967 cpvect[k] = northPole[k] - circleCenter[k][ic];
2968 }
2969 if (dot(acvect, cpvect) >= 0.0) {
2970 return false;
2971 }
2972 }
2973 if (convexEdgeCycleNum[icy] <= 1) {
2974 return true;
2975 }
2976 if (projectedVertexForEachConvexEdge(
2977 northPole, unitVector, icy, iatom, projectedVertsForConvexEdges)) {
2978 return true;
2979 }
2980 int nEdges = convexEdgeCycleNum[icy];
2981 unitVectorsAlongEdges(projectedVertsForConvexEdges, nEdges, unitVectorsAlongEdges);
2982 double angleSum = sumOfAnglesAtVerticesForCycle(unitVectorsAlongEdges, nEdges, unitVector);
2983 return (angleSum > 0.0);
2984 }
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996 private boolean projectedVertexForEachConvexEdge(
2997 double[] northPole,
2998 double[] unitVector,
2999 int icy,
3000 int ia,
3001 double[][] projectedVertsForConvexEdges) {
3002 double[] polev = new double[3];
3003 for (int ke = 0; ke <= convexEdgeCycleNum[icy]; ke++) {
3004
3005 int iep = convexEdgeCycleNumbers[ke][icy];
3006 int iv = convexEdgeVertexNumber[0][iep];
3007 if (iv != -1) {
3008
3009 for (int k = 0; k < 3; k++) {
3010 polev[k] = vertexCoords[k][iv] - northPole[k];
3011 }
3012
3013 double dt = dot(polev, unitVector);
3014 if (dt == 0.0) {
3015 return true;
3016 }
3017 double f = (2 * radius[ia]) / dt;
3018 if (f < 1.0) {
3019 return true;
3020 }
3021
3022 for (int k = 0; k < 3; k++) {
3023 projectedVertsForConvexEdges[k][ke] = northPole[k] + f * polev[k];
3024 }
3025 }
3026 }
3027 return false;
3028 }
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038 private double sumOfAnglesAtVerticesForCycle(
3039 double[][] unitVectorsAlongEdges, int nEdges, double[] unitVector) {
3040 double[] crs = new double[3];
3041 double[] ai = new double[3];
3042 double[] aj = new double[3];
3043 double sumOfAngles = 0.0;
3044
3045 for (int ke = 0; ke <= nEdges; ke++) {
3046 double dt;
3047 if (ke < nEdges) {
3048 getVector(ai, unitVectorsAlongEdges, ke);
3049 getVector(aj, unitVectorsAlongEdges, ke + 1);
3050 dt = dot(ai, aj);
3051 X(ai, aj, crs);
3052 } else {
3053
3054 getVector(ai, unitVectorsAlongEdges, ke);
3055 getVector(aj, unitVectorsAlongEdges, 0);
3056 dt = dot(ai, aj);
3057 X(ai, aj, crs);
3058 }
3059 dt = check(dt);
3060 double ang = acos(dt);
3061 if (dot(crs, unitVector) > 0.0) {
3062 ang = -ang;
3063 }
3064
3065 sumOfAngles += ang;
3066 }
3067 return sumOfAngles;
3068 }
3069
3070
3071
3072
3073
3074
3075
3076
3077 private void unitVectorsAlongEdges(
3078 double[][] projectedVertsForConvexEdges, int nEdges, double[][] unitVectorsAlongEdges) {
3079 double[] ai = new double[3];
3080
3081 for (int ke = 0; ke <= nEdges; ke++) {
3082
3083 int ke2;
3084 if (ke < nEdges) {
3085 ke2 = ke + 1;
3086 } else {
3087 ke2 = 0;
3088 }
3089
3090 for (int k = 0; k < 3; k++) {
3091 unitVectorsAlongEdges[k][ke] =
3092 projectedVertsForConvexEdges[k][ke2] - projectedVertsForConvexEdges[k][ke];
3093 }
3094 getVector(ai, unitVectorsAlongEdges, ke);
3095 double epun = length(ai);
3096 if (epun <= 0.0) {
3097 throw new EnergyException(" Null Edge in Cycle", true);
3098 }
3099
3100 if (epun > 0.0) {
3101 for (int k = 0; k < 3; k++) {
3102 unitVectorsAlongEdges[k][ke] = unitVectorsAlongEdges[k][ke] / epun;
3103 }
3104 } else {
3105 for (int k = 0; k < 3; k++) {
3106 unitVectorsAlongEdges[k][ke] = 0.0;
3107 }
3108 }
3109 }
3110
3111 for (int ke = 0; ke <= nEdges; ke++) {
3112 getVector(ai, unitVectorsAlongEdges, ke);
3113 if (length(ai) <= 0.0) {
3114 int le = ke - 1;
3115 if (le < 0) {
3116 le = nEdges;
3117 }
3118 for (int k = 0; k < 3; k++) {
3119 unitVectorsAlongEdges[k][ke] = unitVectorsAlongEdges[k][le];
3120 }
3121 }
3122 }
3123 }
3124
3125
3126
3127
3128
3129 private double measurePrism(int ifn) {
3130 double[][] pav = new double[3][3];
3131 double[] vect1 = new double[3];
3132 double[] vect2 = new double[3];
3133 double[] vect3 = new double[3];
3134 double height = 0.0;
3135 for (int ke = 0; ke < 3; ke++) {
3136 int ien = concaveFaceEdgeNumbers[ke][ifn];
3137 int iv = concaveEdgeVertexNumbers[0][ien];
3138 int ia = vertexAtomNumbers[iv];
3139 height += atomCoords[2][ia];
3140 int ip = vertexProbeNumber[iv];
3141 for (int k = 0; k < 3; k++) {
3142 pav[k][ke] = atomCoords[k][ia] - probeCoords[k][ip];
3143 }
3144 }
3145 height *= 1.0 / 3.0;
3146 for (int k = 0; k < 3; k++) {
3147 vect1[k] = pav[k][1] - pav[k][0];
3148 vect2[k] = pav[k][2] - pav[k][0];
3149 }
3150 X(vect1, vect2, vect3);
3151 return height * vect3[2] / 2.0;
3152 }
3153
3154
3155
3156
3157
3158
3159
3160 private void measureConvexFace(int iConvexFace, double[] areaVolume) {
3161 double angle;
3162 double[] ai = new double[3];
3163 double[] aj = new double[3];
3164 double[] ak = new double[3];
3165 double[] vect1 = new double[3];
3166 double[] vect2 = new double[3];
3167 double[] acvect = new double[3];
3168 double[] aavect = new double[3];
3169 double[][][] tanv = new double[3][2][MAXCYEP];
3170 double[][] radial = new double[3][MAXCYEP];
3171 double pcurve = 0.0;
3172 double gcurve = 0.0;
3173 int ia = convexFaceAtomNumber[iConvexFace];
3174 int ncycle = convexFaceNumCycles[iConvexFace];
3175 int ieuler;
3176 if (ncycle > -1) {
3177 ieuler = 1 - ncycle;
3178 } else {
3179 ieuler = 2;
3180 }
3181 for (int icyptr = 0; icyptr < ncycle + 1; icyptr++) {
3182 int icy = convexFaceCycleNumbers[icyptr][iConvexFace];
3183 int nedge = convexEdgeCycleNum[icy];
3184 for (int ke = 0; ke < nedge + 1; ke++) {
3185 int iep = convexEdgeCycleNumbers[ke][icy];
3186 int ic = convexEdgeCircleNumber[iep];
3187 int it = circleTorusNumber[ic];
3188 int ia2;
3189 if (ia == torusAtomNumber[0][it]) {
3190 ia2 = torusAtomNumber[1][it];
3191 } else {
3192 ia2 = torusAtomNumber[0][it];
3193 }
3194 for (int k = 0; k < 3; k++) {
3195 acvect[k] = circleCenter[k][ic] - atomCoords[k][ia];
3196 aavect[k] = atomCoords[k][ia2] - atomCoords[k][ia];
3197 }
3198 normalize(aavect, aavect);
3199 double dt = dot(acvect, aavect);
3200 double geo = -dt / (radius[ia] * circleRadius[ic]);
3201 int iv1 = convexEdgeVertexNumber[0][iep];
3202 int iv2 = convexEdgeVertexNumber[1][iep];
3203 if (iv1 == -1 || iv2 == -1) {
3204 angle = 2.0 * PI;
3205 } else {
3206 for (int k = 0; k < 3; k++) {
3207 vect1[k] = vertexCoords[k][iv1] - circleCenter[k][ic];
3208 vect2[k] = vertexCoords[k][iv2] - circleCenter[k][ic];
3209 radial[k][ke] = vertexCoords[k][iv1] - atomCoords[k][ia];
3210 }
3211 getVector(ai, radial, ke);
3212 normalize(ai, ai);
3213 radial[0][ke] = ai[0];
3214 radial[1][ke] = ai[1];
3215 radial[2][ke] = ai[2];
3216 getVector(ai, tanv, 0, ke);
3217 X(vect1, aavect, aj);
3218 normalize(aj, aj);
3219 tanv[0][0][ke] = aj[0];
3220 tanv[1][0][ke] = aj[1];
3221 tanv[2][0][ke] = aj[2];
3222 getVector(ak, tanv, 1, ke);
3223 X(vect2, aavect, ak);
3224 normalize(ak, ak);
3225 tanv[0][1][ke] = ak[0];
3226 tanv[1][1][ke] = ak[1];
3227 tanv[2][1][ke] = ak[2];
3228 angle = vectorAngle(vect1, vect2, aavect, -1.0);
3229 }
3230 gcurve += circleRadius[ic] * angle * geo;
3231 if (nedge != 0) {
3232 if (ke > 0) {
3233 getVector(ai, tanv, 1, ke - 1);
3234 getVector(aj, tanv, 0, ke);
3235 getVector(ak, radial, ke);
3236 angle = vectorAngle(ai, aj, ak, 1.0);
3237 if (angle < 0.0) {
3238 throw new EnergyException(" Negative Angle in measureConvexFace", true);
3239 }
3240 pcurve += angle;
3241 }
3242 }
3243 }
3244 if (nedge > 0) {
3245 getVector(ai, tanv, 1, nedge);
3246 getVector(aj, tanv, 0, 0);
3247 getVector(ak, radial, 0);
3248 angle = vectorAngle(ai, aj, ak, 1.0);
3249 if (angle < 0.0) {
3250 throw new EnergyException(" Negative Angle in measureConvexFace", true);
3251 }
3252 pcurve += angle;
3253 }
3254 }
3255 double gauss = 2.0 * PI * ieuler - pcurve - gcurve;
3256 double areap = gauss * (radius[ia] * radius[ia]);
3257 double volp = areap * radius[ia] / 3.0;
3258 areaVolume[0] = areap;
3259 areaVolume[1] = volp;
3260 }
3261
3262
3263
3264
3265
3266
3267
3268 private void measureSaddleFace(int iSaddleFace, double[] areaVolume) {
3269 double areas;
3270 double vols;
3271 double areasp = 0.0;
3272 double volsp = 0.0;
3273 int iep = saddleConvexEdgeNumbers[0][iSaddleFace];
3274 int ic = convexEdgeCircleNumber[iep];
3275 int it = circleTorusNumber[ic];
3276 int ia1 = torusAtomNumber[0][it];
3277 int ia2 = torusAtomNumber[1][it];
3278 double[] aavect = new double[3];
3279 for (int k = 0; k < 3; k++) {
3280 aavect[k] = atomCoords[k][ia2] - atomCoords[k][ia1];
3281 }
3282 normalize(aavect, aavect);
3283 int iv1 = convexEdgeVertexNumber[0][iep];
3284 int iv2 = convexEdgeVertexNumber[1][iep];
3285 double phi;
3286 double[] vect1 = new double[3];
3287 double[] vect2 = new double[3];
3288 if (iv1 == -1 || iv2 == -1) {
3289 phi = 2.0 * PI;
3290 } else {
3291 for (int k = 0; k < 3; k++) {
3292 vect1[k] = vertexCoords[k][iv1] - circleCenter[k][ic];
3293 vect2[k] = vertexCoords[k][iv2] - circleCenter[k][ic];
3294 }
3295 phi = vectorAngle(vect1, vect2, aavect, 1.0);
3296 }
3297 for (int k = 0; k < 3; k++) {
3298 vect1[k] = atomCoords[k][ia1] - torusCenter[k][it];
3299 vect2[k] = atomCoords[k][ia2] - torusCenter[k][it];
3300 }
3301 double d1 = -1.0 * dot(vect1, aavect);
3302 double d2 = dot(vect2, aavect);
3303 double theta1 = atan2(d1, torusRadius[it]);
3304 double theta2 = atan2(d2, torusRadius[it]);
3305
3306
3307 double thetaq;
3308 boolean cusp;
3309 if (torusRadius[it] < probe && theta1 > 0.0 && theta2 > 0.0) {
3310 cusp = true;
3311 double rat = torusRadius[it] / probe;
3312 if (rat > 1.0) {
3313 rat = 1.0;
3314 } else if (rat < -1.0) {
3315 rat = -1.0;
3316 }
3317 thetaq = acos(rat);
3318 } else {
3319 cusp = false;
3320 thetaq = 0.0;
3321 areasp = 0.0;
3322 volsp = 0.0;
3323 }
3324 double term1 = torusRadius[it] * probe * (theta1 + theta2);
3325 double term2 = (probe * probe) * (sin(theta1) + sin(theta2));
3326 areas = phi * (term1 - term2);
3327 if (cusp) {
3328 double spin = torusRadius[it] * probe * thetaq - probe * probe * sin(thetaq);
3329 areasp = 2.0 * phi * spin;
3330 }
3331
3332 iep = saddleConvexEdgeNumbers[0][iSaddleFace];
3333 int ic2 = convexEdgeCircleNumber[iep];
3334 iep = saddleConvexEdgeNumbers[1][iSaddleFace];
3335 int ic1 = convexEdgeCircleNumber[iep];
3336 if (circleAtomNumber[ic1] != ia1) {
3337 throw new EnergyException(" Atom number inconsistency in measureSaddleFace", true);
3338 }
3339 for (int k = 0; k < 3; k++) {
3340 vect1[k] = circleCenter[k][ic1] - atomCoords[k][ia1];
3341 vect2[k] = circleCenter[k][ic2] - atomCoords[k][ia2];
3342 }
3343 double w1 = dot(vect1, aavect);
3344 double w2 = -1.0 * dot(vect2, aavect);
3345 double cone1 = phi * ((w1 * circleRadius[ic1] * circleRadius[ic1])) / 6.0;
3346 double cone2 = phi * ((w2 * circleRadius[ic2] * circleRadius[ic2])) / 6.0;
3347 term1 = (torusRadius[it] * torusRadius[it]) * probe * (sin(theta1) + sin(theta2));
3348 term2 = sin(theta1) * cos(theta1) + theta1 + sin(theta2) * cos(theta2) + theta2;
3349 term2 = torusRadius[it] * (probe * probe) * term2;
3350 double term3 =
3351 sin(theta1) * cos(theta1) * cos(theta1)
3352 + 2.0 * sin(theta1)
3353 + sin(theta2) * cos(theta2) * cos(theta2)
3354 + 2.0 * sin(theta2);
3355 term3 = (probe * probe * probe / 3.0) * term3;
3356 double volt = (phi / 2.0) * (term1 - term2 + term3);
3357 vols = volt + cone1 + cone2;
3358 if (cusp) {
3359 term1 = (torusRadius[it] * torusRadius[it]) * probe * sin(thetaq);
3360 term2 = sin(thetaq) * cos(thetaq) + thetaq;
3361 term2 = torusRadius[it] * (probe * probe) * term2;
3362 term3 = sin(thetaq) * cos(thetaq) * cos(thetaq) + 2.0 * sin(thetaq);
3363 term3 = (probe * probe * probe / 3.0) * term3;
3364 volsp = phi * (term1 - term2 + term3);
3365 }
3366 areaVolume[0] = areas;
3367 areaVolume[1] = vols;
3368 areaVolume[2] = areasp;
3369 areaVolume[3] = volsp;
3370 }
3371
3372
3373
3374
3375
3376
3377
3378 private void measureConcaveFace(int iConcaveFace, double[] areaVolume) {
3379 double[] ai = new double[3];
3380 double[] aj = new double[3];
3381 double[] ak = new double[3];
3382 double[] angle = new double[3];
3383 double[][] pvv = new double[3][3];
3384 double[][] pav = new double[3][3];
3385 double[][] planev = new double[3][3];
3386 double arean;
3387 double voln;
3388 for (int ke = 0; ke < 3; ke++) {
3389 int ien = concaveFaceEdgeNumbers[ke][iConcaveFace];
3390 int iv = concaveEdgeVertexNumbers[0][ien];
3391 int ia = vertexAtomNumbers[iv];
3392 int ip = vertexProbeNumber[iv];
3393 for (int k = 0; k < 3; k++) {
3394 pvv[k][ke] = vertexCoords[k][iv] - probeCoords[k][ip];
3395 pav[k][ke] = atomCoords[k][ia] - probeCoords[k][ip];
3396 }
3397 if (probe > 0.0) {
3398 getVector(ai, pvv, ke);
3399 normalize(ai, ai);
3400 putVector(ai, pvv, ke);
3401 }
3402 }
3403 if (probe <= 0.0) {
3404 arean = 0.0;
3405 } else {
3406 for (int ke = 0; ke < 3; ke++) {
3407 int je = ke + 1;
3408 if (je > 2) {
3409 je = 0;
3410 }
3411 getVector(ai, pvv, ke);
3412 getVector(aj, pvv, je);
3413 X(ai, aj, ak);
3414 normalize(ak, ak);
3415 putVector(ak, planev, ke);
3416 }
3417 for (int ke = 0; ke < 3; ke++) {
3418 int je = ke - 1;
3419 if (je < 0) {
3420 je = 2;
3421 }
3422 getVector(ai, planev, je);
3423 getVector(aj, planev, ke);
3424 getVector(ak, pvv, ke);
3425 angle[ke] = vectorAngle(ai, aj, ak, -1.0);
3426 if (angle[ke] < 0.0) {
3427 throw new EnergyException(" Negative angle in measureConcaveFace", true);
3428 }
3429 }
3430 double defect = 2.0 * PI - (angle[0] + angle[1] + angle[2]);
3431 arean = (probe * probe) * defect;
3432 }
3433 getVector(ai, pav, 0);
3434 getVector(aj, pav, 1);
3435 getVector(ak, pav, 2);
3436 double simplx = -tripleProduct(ai, aj, ak) / 6.0;
3437 voln = simplx - arean * probe / 3.0;
3438 areaVolume[0] = arean;
3439 areaVolume[1] = voln;
3440 }
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450 private int genDots(int ndots, double[][] dots, double radius) {
3451 int nequat = (int) sqrt(PI * ((double) ndots));
3452 int nvert = (int) (0.5 * (double) nequat);
3453 if (nvert < 1) {
3454 nvert = 1;
3455 }
3456 int k = -1;
3457 outerloop:
3458 for (int i = 0; i <= nvert; i++) {
3459 double fi = (PI * ((double) i)) / ((double) nvert);
3460 double z = cos(fi);
3461 double xy = sin(fi);
3462 int nhoriz = (int) (nequat * xy);
3463 if (nhoriz < 1) {
3464 nhoriz = 1;
3465 }
3466 for (int j = 0; j < nhoriz; j++) {
3467 double fj = (2.0 * PI * ((double) j)) / ((double) nhoriz);
3468 double x = cos(fj) * xy;
3469 double y = sin(fj) * xy;
3470 k++;
3471 dots[0][k] = x * radius;
3472 dots[1][k] = y * radius;
3473 dots[2][k] = z * radius;
3474 if (k >= ndots) {
3475 break outerloop;
3476 }
3477 }
3478 }
3479 return k;
3480 }
3481
3482
3483
3484
3485 private boolean circlePlane(
3486 double[] circen,
3487 double cirrad,
3488 double[] cirvec,
3489 double[] plncen,
3490 double[] plnvec,
3491 boolean[] cinsp,
3492 double[] xpnt1,
3493 double[] xpnt2) {
3494 double[] cpvect = new double[3];
3495 double[] pnt1 = new double[3];
3496 double[] vect1 = new double[3];
3497 double[] vect2 = new double[3];
3498 double[] uvect1 = new double[3];
3499 double[] uvect2 = new double[3];
3500 for (int k = 0; k < 3; k++) {
3501 cpvect[k] = plncen[k] - circen[k];
3502 }
3503 double dcp = dot(cpvect, plnvec);
3504 cinsp[0] = (dcp > 0.0);
3505 X(plnvec, cirvec, vect1);
3506 if (length(vect1) > 0.0) {
3507 normalize(vect1, uvect1);
3508 X(cirvec, uvect1, vect2);
3509 if (length(vect2) > 0.0) {
3510 normalize(vect2, uvect2);
3511 double dir = dot(uvect2, plnvec);
3512 if (dir != 0.0) {
3513 double ratio = dcp / dir;
3514 if (abs(ratio) <= cirrad) {
3515 for (int k = 0; k < 3; k++) {
3516 pnt1[k] = circen[k] + ratio * uvect2[k];
3517 }
3518 double rlen = cirrad * cirrad - ratio * ratio;
3519 if (rlen < 0.0) {
3520 rlen = 0.0;
3521 }
3522 rlen = sqrt(rlen);
3523 for (int k = 0; k < 3; k++) {
3524 xpnt1[k] = pnt1[k] - rlen * uvect1[k];
3525 xpnt2[k] = pnt1[k] + rlen * uvect1[k];
3526 }
3527 return true;
3528 }
3529 }
3530 }
3531 }
3532 return false;
3533 }
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545 private double vectorAngle(double[] v1, double[] v2, double[] axis, double hand) {
3546 double a1 = length(v1);
3547 double a2 = length(v2);
3548 double dt = dot(v1, v2);
3549 double a12 = a1 * a2;
3550 if (abs(a12) != 0.0) {
3551 dt = dt / a12;
3552 }
3553 dt = check(dt);
3554 double angle = acos(dt);
3555 if (hand * tripleProduct(v1, v2, axis) < 0.0) {
3556 return 2.0 * PI - angle;
3557 } else {
3558 return angle;
3559 }
3560 }
3561
3562
3563
3564
3565
3566
3567
3568
3569 private double depth(int ip, double[] alt) {
3570 double[] vect1 = new double[3];
3571 double[] vect2 = new double[3];
3572 double[] vect3 = new double[3];
3573 double[] vect4 = new double[3];
3574 int ia1 = probeAtomNumbers[0][ip];
3575 int ia2 = probeAtomNumbers[1][ip];
3576 int ia3 = probeAtomNumbers[2][ip];
3577 for (int k = 0; k < 3; k++) {
3578 vect1[k] = atomCoords[k][ia1] - atomCoords[k][ia3];
3579 vect2[k] = atomCoords[k][ia2] - atomCoords[k][ia3];
3580 vect3[k] = probeCoords[k][ip] - atomCoords[k][ia3];
3581 }
3582 X(vect1, vect2, vect4);
3583 normalize(vect4, vect4);
3584 double dot = dot(vect4, vect3);
3585 arraycopy(vect4, 0, alt, 0, 3);
3586 return dot;
3587 }
3588
3589
3590
3591
3592
3593
3594
3595 private double check(double angle) {
3596 return max(min(angle, 1.0), -1.0);
3597 }
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607 private int index2(int i, int j, int k) {
3608 return k + MXCUBE * (j + MXCUBE * i);
3609 }
3610
3611 private void getVector(double[] ai, double[][] temp, int index) {
3612 ai[0] = temp[0][index];
3613 ai[1] = temp[1][index];
3614 ai[2] = temp[2][index];
3615 }
3616
3617 private void putVector(double[] ai, double[][] temp, int index) {
3618 temp[0][index] = ai[0];
3619 temp[1][index] = ai[1];
3620 temp[2][index] = ai[2];
3621 }
3622
3623 private void getVector(double[] ai, double[][][] temp, int index1, int index2) {
3624 ai[0] = temp[0][index1][index2];
3625 ai[1] = temp[1][index1][index2];
3626 ai[2] = temp[2][index1][index2];
3627 }
3628
3629 private void putVector(double[] ai, double[][][] temp, int index1, int index2) {
3630 temp[0][index1][index2] = ai[0];
3631 temp[1][index1][index2] = ai[1];
3632 temp[2][index1][index2] = ai[2];
3633 }
3634
3635 private void computeVolumeGradient() {
3636 int[][] cube = new int[2][MXCUBE * MXCUBE * MXCUBE];
3637 int[] inov = new int[MAXARC];
3638 double[] arci = new double[MAXARC];
3639 double[] arcf = new double[MAXARC];
3640 double[] dx = new double[MAXARC];
3641 double[] dy = new double[MAXARC];
3642 double[] dsq = new double[MAXARC];
3643 double[] d = new double[MAXARC];
3644
3645
3646 double rmax = 0.0;
3647 double xmin = x[0];
3648 double xmax = x[0];
3649 double ymin = y[0];
3650 double ymax = y[0];
3651 double zmin = z[0];
3652 double zmax = z[0];
3653 for (int i = 0; i < nAtoms; i++) {
3654 if (radius[i] > 0.0) {
3655 if (radius[i] > rmax) {
3656 rmax = radius[i];
3657 }
3658 if (x[i] < xmin) {
3659 xmin = x[i];
3660 }
3661 if (x[i] > xmax) {
3662 xmax = x[i];
3663 }
3664 if (y[i] < ymin) {
3665 ymin = y[i];
3666 }
3667 if (y[i] > ymax) {
3668 ymax = y[i];
3669 }
3670 if (z[i] < zmin) {
3671 zmin = z[i];
3672 }
3673 if (z[i] > zmax) {
3674 zmax = z[i];
3675 }
3676 }
3677 }
3678
3679
3680
3681
3682
3683
3684 double zstep = 0.0601;
3685
3686
3687
3688 double edge = 2.0 * rmax;
3689 int nx = (int) ((xmax - xmin) / edge);
3690 int ny = (int) ((ymax - ymin) / edge);
3691 int nz = (int) ((zmax - zmin) / edge);
3692 if (max(max(nx, ny), nz) > MXCUBE) {
3693 throw new EnergyException(" VolumeRegion derivative -- Increase the Value of mxcube");
3694 }
3695
3696
3697 fill(cube[0], -1);
3698 fill(cube[1], -1);
3699
3700
3701 for (int m = 0; m < nAtoms; m++) {
3702 if (!skip[m]) {
3703 int i = (int) ((x[m] - xmin) / edge);
3704 int j = (int) ((y[m] - ymin) / edge);
3705 int k = (int) ((z[m] - zmin) / edge);
3706 cube[0][index2(i, j, k)]++;
3707 }
3708 }
3709
3710
3711
3712
3713
3714
3715
3716
3717 int isum = 0;
3718 int tcube;
3719 for (int i = 0; i <= nx; i++) {
3720 for (int j = 0; j <= ny; j++) {
3721 for (int k = 0; k <= nz; k++) {
3722 tcube = cube[0][index2(i, j, k)];
3723 if (tcube != -1) {
3724 isum += tcube;
3725 cube[1][index2(i, j, k)] = isum;
3726 }
3727 }
3728 }
3729 }
3730
3731
3732
3733
3734 for (int m = 0; m < nAtoms; m++) {
3735 if (!skip[m]) {
3736 int i = (int) ((x[m] - xmin) / edge);
3737 int j = (int) ((y[m] - ymin) / edge);
3738 int k = (int) ((z[m] - zmin) / edge);
3739 tcube = cube[1][index2(i, j, k)];
3740 itab[tcube] = m;
3741 cube[1][index2(i, j, k)]--;
3742 }
3743 }
3744
3745
3746
3747 isum = 0;
3748 for (int i = 0; i <= nx; i++) {
3749 for (int j = 0; j <= ny; j++) {
3750 for (int k = 0; k <= nz; k++) {
3751 tcube = cube[0][index2(i, j, k)];
3752 if (tcube != -1) {
3753 isum += tcube;
3754 cube[0][index2(i, j, k)] = isum;
3755 cube[1][index2(i, j, k)]++;
3756 }
3757 }
3758 }
3759 }
3760
3761
3762
3763 int ir;
3764 for (ir = 0; ir < nAtoms; ir++) {
3765 double pre_dx = 0.0;
3766 double pre_dy = 0.0;
3767 double pre_dz = 0.0;
3768 if (skip[ir]) {
3769 continue;
3770 }
3771 double rr = radius[ir];
3772 double rrx2 = 2.0 * rr;
3773 double rrsq = rr * rr;
3774 double xr = x[ir];
3775 double yr = y[ir];
3776 double zr = z[ir];
3777
3778 int istart = (int) ((xr - xmin) / edge);
3779 int istop = min(istart + 2, nx + 1);
3780 istart = max(istart, 1);
3781 int jstart = (int) ((yr - ymin) / edge);
3782 int jstop = min(jstart + 2, ny + 1);
3783 jstart = max(jstart, 1);
3784 int kstart = (int) ((zr - zmin) / edge);
3785 int kstop = min(kstart + 2, nz + 1);
3786 kstart = max(kstart, 1);
3787
3788 int io = -1;
3789 int in;
3790 for (int i = istart - 1; i < istop; i++) {
3791 for (int j = jstart - 1; j < jstop; j++) {
3792 for (int k = kstart - 1; k < kstop; k++) {
3793 int mstart = cube[1][index2(i, j, k)];
3794 if (mstart != -1) {
3795 int mstop = cube[0][index2(i, j, k)];
3796 for (int m = mstart; m <= mstop; m++) {
3797 in = itab[m];
3798 if (in != ir) {
3799 io++;
3800 if (io > MAXARC) {
3801 logger.severe(" VolumeRegion gradient -- Increase the Value of MAXARC");
3802 }
3803 dx[io] = x[in] - xr;
3804 dy[io] = y[in] - yr;
3805 dsq[io] = (dx[io] * dx[io]) + (dy[io] * dy[io]);
3806 double dist2 = dsq[io] + ((z[in] - zr) * (z[in] - zr));
3807 double vdwsum = (rr + radius[in]) * (rr + radius[in]);
3808 if (dist2 > vdwsum || dist2 == 0.0) {
3809 io--;
3810 } else {
3811 d[io] = sqrt(dsq[io]);
3812 inov[io] = in;
3813 }
3814 }
3815 }
3816 }
3817 }
3818 }
3819 }
3820
3821
3822 if (io != -1) {
3823 double ztop = zr + rr;
3824 double ztopshave = ztop - zstep;
3825 double zgrid = zr - rr;
3826
3827 zgrid += 0.5 * (rrx2 - (((int) (rrx2 / zstep)) * zstep));
3828 double zstart = zgrid;
3829
3830 while (zgrid <= ztop) {
3831
3832 double rsec2r = rrsq - ((zgrid - zr) * (zgrid - zr));
3833 if (rsec2r < 0.0) {
3834 rsec2r = 0.000001;
3835 }
3836 double rsecr = sqrt(rsec2r);
3837 double phi1;
3838 double cos_phi1;
3839 if (zgrid >= ztopshave) {
3840 cos_phi1 = 1.0;
3841 phi1 = 0.0;
3842 } else {
3843 cos_phi1 = (zgrid + (0.5 * zstep) - zr) / rr;
3844 phi1 = acos(cos_phi1);
3845 }
3846 double phi2;
3847 double cos_phi2;
3848 if (zgrid == zstart) {
3849 cos_phi2 = -1.0;
3850 phi2 = PI;
3851 } else {
3852 cos_phi2 = (zgrid - (0.5 * zstep) - zr) / rr;
3853 phi2 = acos(cos_phi2);
3854 }
3855
3856 int narc = -1;
3857 double twoPI = 2.0 * PI;
3858 for (int k = 0; k <= io; k++) {
3859 in = inov[k];
3860 double rinsq = radius[in] * radius[in];
3861 double rsec2n = rinsq - ((zgrid - z[in]) * (zgrid - z[in]));
3862 if (rsec2n > 0.0) {
3863 double rsecn = sqrt(rsec2n);
3864 if (d[k] < (rsecr + rsecn)) {
3865 double rdiff = rsecr - rsecn;
3866 if (d[k] <= abs(rdiff)) {
3867 if (rdiff < 0.0) {
3868 narc = 0;
3869 arci[narc] = 0.0;
3870 arcf[narc] = twoPI;
3871 }
3872 continue;
3873 }
3874 narc++;
3875 if (narc > MAXARC) {
3876 logger.severe(" VolumeRegion gradient -- Increase the Value of MAXARC");
3877 }
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887 double cosine = (dsq[k] + rsec2r - rsec2n) / (2.0 * d[k] * rsecr);
3888 cosine = min(1.0, max(-1.0, cosine));
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898 double alpha = acos(cosine);
3899 double beta = atan2(dy[k], dx[k]);
3900 if (dy[k] < 0.0) {
3901 beta += twoPI;
3902 }
3903 double ti = beta - alpha;
3904 double tf = beta + alpha;
3905 if (ti < 0.0) {
3906 ti += twoPI;
3907 }
3908 if (tf > twoPI) {
3909 tf -= twoPI;
3910 }
3911 arci[narc] = ti;
3912
3913
3914 if (tf < ti) {
3915 arcf[narc] = twoPI;
3916 narc++;
3917 arci[narc] = 0.0;
3918 }
3919 arcf[narc] = tf;
3920 }
3921 }
3922 }
3923
3924
3925
3926
3927 double seg_dz;
3928 if (narc == -1) {
3929 seg_dz = twoPI * ((cos_phi1 * cos_phi1) - (cos_phi2 * cos_phi2));
3930 pre_dz += seg_dz;
3931 } else {
3932
3933
3934
3935 for (int k = 0; k < narc; k++) {
3936 double aa = arci[k];
3937 double bb = arcf[k];
3938 double temp = 1000000.0;
3939 int itemp = 0;
3940 for (int i = k; i <= narc; i++) {
3941 if (arci[i] <= temp) {
3942 temp = arci[i];
3943 itemp = i;
3944 }
3945 }
3946 arci[k] = arci[itemp];
3947 arcf[k] = arcf[itemp];
3948 arci[itemp] = aa;
3949 arcf[itemp] = bb;
3950 }
3951
3952 double temp = arcf[0];
3953 int j = 0;
3954 for (int k = 1; k <= narc; k++) {
3955 if (temp < arci[k]) {
3956 arcf[j] = temp;
3957 j++;
3958 arci[j] = arci[k];
3959 temp = arcf[k];
3960 } else if (temp < arcf[k]) {
3961 temp = arcf[k];
3962 }
3963 }
3964 arcf[j] = temp;
3965 narc = j;
3966 if (narc == 0) {
3967 narc = 1;
3968 arcf[1] = twoPI;
3969 arci[1] = arcf[0];
3970 arcf[0] = arci[0];
3971 arci[0] = 0.0;
3972 } else {
3973 temp = arci[0];
3974 for (int k = 0; k < narc; k++) {
3975 arci[k] = arcf[k];
3976 arcf[k] = arci[k + 1];
3977 }
3978
3979 if (temp == 0.0 && arcf[narc] == twoPI) {
3980 narc--;
3981 } else {
3982 arci[narc] = arcf[narc];
3983 arcf[narc] = temp;
3984 }
3985 }
3986
3987
3988 for (int k = 0; k <= narc; k++) {
3989 double theta1 = arci[k];
3990 double theta2 = arcf[k];
3991 double dtheta;
3992 if (theta2 >= theta1) {
3993 dtheta = theta2 - theta1;
3994 } else {
3995 dtheta = (theta2 + twoPI) - theta1;
3996 }
3997 double phi_term = phi2 - phi1 - 0.5 * (sin(2.0 * phi2) - sin(2.0 * phi1));
3998 double seg_dx = (sin(theta2) - sin(theta1)) * phi_term;
3999 double seg_dy = (cos(theta1) - cos(theta2)) * phi_term;
4000 seg_dz = dtheta * ((cos_phi1 * cos_phi1) - (cos_phi2 * cos_phi2));
4001 pre_dx += seg_dx;
4002 pre_dy += seg_dy;
4003 pre_dz += seg_dz;
4004 }
4005 }
4006 zgrid += zstep;
4007 }
4008 }
4009 volumeGradient[0][ir] = 0.5 * rrsq * pre_dx;
4010 volumeGradient[1][ir] = 0.5 * rrsq * pre_dy;
4011 volumeGradient[2][ir] = 0.5 * rrsq * pre_dz;
4012 }
4013 }
4014 }
4015 }