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.crystal;
39
40 import static ffx.numerics.math.DoubleMath.dot;
41 import static ffx.numerics.math.MatrixMath.mat3Inverse;
42 import static ffx.numerics.math.MatrixMath.mat4Mat4;
43 import static ffx.numerics.math.ScalarMath.mod;
44 import static java.lang.Double.parseDouble;
45 import static java.lang.String.format;
46 import static org.apache.commons.math3.util.FastMath.PI;
47 import static org.apache.commons.math3.util.FastMath.cos;
48 import static org.apache.commons.math3.util.FastMath.random;
49 import static org.apache.commons.math3.util.FastMath.rint;
50 import static org.apache.commons.math3.util.FastMath.sin;
51 import static org.apache.commons.math3.util.FastMath.sqrt;
52
53
54
55
56
57
58
59
60 public class SymOp {
61
62
63
64
65 private static final double ZERO = 0.0;
66
67
68
69 public static final double[][] ZERO_ROTATION = {
70 {1.0, ZERO, ZERO},
71 {ZERO, 1.0, ZERO},
72 {ZERO, ZERO, 1.0}};
73
74
75
76 public static final double[] Tr_0_0_0 = {ZERO, ZERO, ZERO};
77
78
79
80 private static final double f12 = 1.0 / 2.0;
81
82
83
84 static final double[] Tr_12_0_12 = {f12, ZERO, f12};
85
86
87
88 static final double[] Tr_0_12_12 = {ZERO, f12, f12};
89
90
91
92 static final double[] Tr_12_12_0 = {f12, f12, ZERO};
93
94
95
96 static final double[] Tr_12_12_12 = {f12, f12, f12};
97
98
99
100 static final double[] Tr_0_12_0 = {ZERO, f12, ZERO};
101
102
103
104 static final double[] Tr_12_0_0 = {f12, ZERO, ZERO};
105
106
107
108 static final double[] Tr_0_0_12 = {ZERO, ZERO, f12};
109
110
111
112 private static final double f13 = 1.0 / 3.0;
113
114
115
116 static final double[] Tr_0_0_13 = {ZERO, ZERO, f13};
117
118
119
120 private static final double f23 = 2.0 / 3.0;
121
122
123
124 static final double[] Tr_23_13_13 = {f23, f13, f13};
125
126
127
128 static final double[] Tr_13_23_23 = {f13, f23, f23};
129
130
131
132 static final double[] Tr_0_0_23 = {ZERO, ZERO, f23};
133
134
135
136 private static final double f14 = 1.0 / 4.0;
137
138
139
140 static final double[] Tr_12_0_14 = {f12, ZERO, f14};
141
142
143
144 static final double[] Tr_0_12_14 = {ZERO, f12, f14};
145
146
147
148 static final double[] Tr_14_14_14 = {f14, f14, f14};
149
150
151
152 static final double[] Tr_12_12_14 = {f12, f12, f14};
153
154
155
156 static final double[] Tr_0_0_14 = {ZERO, ZERO, f14};
157
158
159
160 private static final double f34 = 3.0 / 4.0;
161
162
163
164 static final double[] Tr_0_0_34 = {ZERO, ZERO, f34};
165
166
167
168 static final double[] Tr_12_0_34 = {f12, ZERO, f34};
169
170
171
172 static final double[] Tr_0_12_34 = {ZERO, f12, f34};
173
174
175
176 static final double[] Tr_34_14_14 = {f34, f14, f14};
177
178
179
180 static final double[] Tr_14_14_34 = {f14, f14, f34};
181
182
183
184 static final double[] Tr_14_34_14 = {f14, f34, f14};
185
186
187
188 static final double[] Tr_12_12_34 = {f12, f12, f34};
189
190
191
192 static final double[] Tr_14_34_34 = {f14, f34, f34};
193
194
195
196 static final double[] Tr_34_34_14 = {f34, f34, f14};
197
198
199
200 static final double[] Tr_34_34_34 = {f34, f34, f34};
201
202
203
204 static final double[] Tr_34_14_34 = {f34, f14, f34};
205
206
207
208 private static final double f16 = 1.0 / 6.0;
209
210
211
212 static final double[] Tr_13_23_16 = {f13, f23, f16};
213
214
215
216 static final double[] Tr_0_0_16 = {ZERO, ZERO, f16};
217
218
219
220 private static final double f56 = 5.0 / 6.0;
221
222
223
224 static final double[] Tr_0_0_56 = {ZERO, ZERO, f56};
225
226
227
228 static final double[] Tr_23_13_56 = {f23, f13, f56};
229
230
231
232 private static final double[] X = {1.0, ZERO, ZERO};
233
234
235
236 private static final double[] Y = {ZERO, 1.0, ZERO};
237
238
239
240 private static final double[] Z = {ZERO, ZERO, 1.0};
241
242
243
244 static final double[][] Rot_Y_Z_X = {Y, Z, X};
245
246
247
248 static final double[][] Rot_X_Y_Z = {X, Y, Z};
249
250
251
252 static final double[][] Rot_Z_X_Y = {Z, X, Y};
253
254
255
256 static final double[][] Rot_X_Z_Y = {X, Z, Y};
257
258
259
260 static final double[][] Rot_Z_Y_X = {Z, Y, X};
261
262
263
264 static final double[][] Rot_Y_X_Z = {Y, X, Z};
265
266
267
268 private static final double[] mX = {-1.0, ZERO, ZERO};
269
270
271
272 static final double[][] Rot_Y_mX_Z = {Y, mX, Z};
273
274
275
276 static final double[][] Rot_mX_Z_Y = {mX, Z, Y};
277
278
279
280 static final double[][] Rot_Y_Z_mX = {Y, Z, mX};
281
282
283
284 static final double[][] Rot_mX_Y_Z = {mX, Y, Z};
285
286
287
288 static final double[][] Rot_Z_Y_mX = {Z, Y, mX};
289
290
291
292 static final double[][] Rot_Z_mX_Y = {Z, mX, Y};
293
294
295
296 private static final double[] mY = {ZERO, -1.0, ZERO};
297
298
299
300 static final double[][] Rot_Z_mY_X = {Z, mY, X};
301
302
303
304 static final double[][] Rot_X_Z_mY = {X, Z, mY};
305
306
307
308 static final double[][] Rot_mY_X_Z = {mY, X, Z};
309
310
311
312 static final double[][] Rot_mY_Z_mX = {mY, Z, mX};
313
314
315
316 static final double[][] Rot_mY_Z_X = {mY, Z, X};
317
318
319
320 static final double[][] Rot_Z_X_mY = {Z, X, mY};
321
322
323
324 static final double[][] Rot_Z_mX_mY = {Z, mX, mY};
325
326
327
328 static final double[][] Rot_mX_Z_mY = {mX, Z, mY};
329
330
331
332 static final double[][] Rot_X_mY_Z = {X, mY, Z};
333
334
335
336 static final double[][] Rot_mY_mX_Z = {mY, mX, Z};
337
338
339
340 static final double[][] Rot_Z_mY_mX = {Z, mY, mX};
341
342
343
344 static final double[][] Rot_mX_mY_Z = {mX, mY, Z};
345
346
347
348 private static final double[] mZ = {ZERO, ZERO, -1.0};
349
350
351
352 static final double[][] Rot_Y_mX_mZ = {Y, mX, mZ};
353
354
355
356 static final double[][] Rot_mX_Y_mZ = {mX, Y, mZ};
357
358
359
360 static final double[][] Rot_X_mZ_Y = {X, mZ, Y};
361
362
363
364 static final double[][] Rot_mY_mZ_X = {mY, mZ, X};
365
366
367
368 static final double[][] Rot_Y_X_mZ = {Y, X, mZ};
369
370
371
372 static final double[][] Rot_Y_mZ_X = {Y, mZ, X};
373
374
375
376 static final double[][] Rot_mX_mY_mZ = {mX, mY, mZ};
377
378
379
380 static final double[][] Rot_X_Y_mZ = {X, Y, mZ};
381
382
383
384 static final double[][] Rot_mZ_mY_mX = {mZ, mY, mX};
385
386
387
388 static final double[][] Rot_X_mZ_mY = {X, mZ, mY};
389
390
391
392 static final double[][] Rot_mY_mX_mZ = {mY, mX, mZ};
393
394
395
396 static final double[][] Rot_mY_X_mZ = {mY, X, mZ};
397
398
399
400 static final double[][] Rot_mX_mZ_mY = {mX, mZ, mY};
401
402
403
404 static final double[][] Rot_mZ_mX_mY = {mZ, mX, mY};
405
406
407
408 static final double[][] Rot_mZ_mY_X = {mZ, mY, X};
409
410
411
412 static final double[][] Rot_mZ_Y_mX = {mZ, Y, mX};
413
414
415
416 static final double[][] Rot_mZ_mX_Y = {mZ, mX, Y};
417
418
419
420 static final double[][] Rot_mX_mZ_Y = {mX, mZ, Y};
421
422
423
424 static final double[][] Rot_X_mY_mZ = {X, mY, mZ};
425
426
427
428 static final double[][] Rot_mZ_X_Y = {mZ, X, Y};
429
430
431
432 static final double[][] Rot_Y_mZ_mX = {Y, mZ, mX};
433
434
435
436 static final double[][] Rot_mY_mZ_mX = {mY, mZ, mX};
437
438
439
440 static final double[][] Rot_mZ_Y_X = {mZ, Y, X};
441
442
443
444 static final double[][] Rot_mZ_X_mY = {mZ, X, mY};
445
446
447
448 private static final double[] XmY = {1.0, -1.0, ZERO};
449
450
451
452 static final double[][] Rot_XmY_X_mZ = {XmY, X, mZ};
453
454
455
456 static final double[][] Rot_XmY_X_Z = {XmY, X, Z};
457
458
459
460 static final double[][] Rot_XmY_mY_Z = {XmY, mY, Z};
461
462
463
464 static final double[][] Rot_X_XmY_Z = {X, XmY, Z};
465
466
467
468 static final double[][] Rot_X_XmY_mZ = {X, XmY, mZ};
469
470
471
472 static final double[][] Rot_mY_XmY_mZ = {mY, XmY, mZ};
473
474
475
476 static final double[][] Rot_mY_XmY_Z = {mY, XmY, Z};
477
478
479
480 static final double[][] Rot_XmY_mY_mZ = {XmY, mY, mZ};
481
482
483
484 private static final double[] mXY = {-1.0, 1.0, ZERO};
485
486
487
488 static final double[][] Rot_Y_mXY_Z = {Y, mXY, Z};
489
490
491
492 static final double[][] Rot_mX_mXY_mZ = {mX, mXY, mZ};
493
494
495
496 static final double[][] Rot_mXY_Y_Z = {mXY, Y, Z};
497
498
499
500 static final double[][] Rot_mXY_mX_Z = {mXY, mX, Z};
501
502
503
504 static final double[][] Rot_mXY_Y_mZ = {mXY, Y, mZ};
505
506
507
508 static final double[][] Rot_mXY_mX_mZ = {mXY, mX, mZ};
509
510
511
512 static final double[][] Rot_mX_mXY_Z = {mX, mXY, Z};
513
514
515
516 static final double[][] Rot_Y_mXY_mZ = {Y, mXY, mZ};
517
518
519
520 public final double[][] rot;
521
522
523
524 public final double[] tr;
525
526
527
528 private static final int XX = 0;
529
530
531
532 private static final int YY = 1;
533
534
535
536 private static final int ZZ = 2;
537
538
539
540 public final int[] replicatesVector;
541
542
543
544
545
546
547
548 public SymOp(double[][] rot, double[] tr) {
549 this.rot = rot;
550 this.tr = tr;
551 replicatesVector = new int[]{0, 0, 0};
552 }
553
554
555
556
557
558
559
560
561 public SymOp(double[][] rot, double[] tr, int[] replicatesVector) {
562 this.rot = rot;
563 this.tr = tr;
564 this.replicatesVector = replicatesVector;
565 }
566
567
568
569
570
571
572 public SymOp(double[][] m) {
573 this.rot = new double[3][3];
574 rot[0][0] = m[0][0];
575 rot[0][1] = m[0][1];
576 rot[0][2] = m[0][2];
577 rot[1][0] = m[1][0];
578 rot[1][1] = m[1][1];
579 rot[1][2] = m[1][2];
580 rot[2][0] = m[2][0];
581 rot[2][1] = m[2][1];
582 rot[2][2] = m[2][2];
583
584 this.tr = new double[3];
585 tr[0] = m[0][3] / m[3][3];
586 tr[1] = m[1][3] / m[3][3];
587 tr[2] = m[2][3] / m[3][3];
588
589 replicatesVector = new int[]{0, 0, 0};
590 }
591
592
593
594
595
596
597
598 public double symPhaseShift(double[] hkl) {
599
600 return -2.0 * PI * (hkl[0] * tr[0] + hkl[1] * tr[1] + hkl[2] * tr[2]);
601 }
602
603
604
605
606
607
608
609 public double symPhaseShift(HKL hkl) {
610
611 return -2.0 * PI * (hkl.getH() * tr[0] + hkl.getK() * tr[1] + hkl.getL() * tr[2]);
612 }
613
614
615
616
617
618
619 public double[][] asMatrix() {
620 return new double[][]{
621 {rot[0][0], rot[0][1], rot[0][2], tr[0]},
622 {rot[1][0], rot[1][1], rot[1][2], tr[1]},
623 {rot[2][0], rot[2][1], rot[2][2], tr[2]},
624 {0.0, 0.0, 0.0, 1.0}};
625 }
626
627
628
629
630
631
632
633
634
635
636 public SymOp append(SymOp symOp) {
637 return new SymOp(mat4Mat4(symOp.asMatrix(), asMatrix()));
638 }
639
640
641
642
643
644
645
646
647
648
649 public SymOp prepend(SymOp symOp) {
650 return new SymOp(mat4Mat4(asMatrix(), symOp.asMatrix()));
651 }
652
653
654
655
656
657
658
659
660
661
662
663
664 public static SymOp combineSymOps(SymOp symOp1, SymOp symOp2) {
665 return new SymOp(mat4Mat4(symOp2.asMatrix(), symOp1.asMatrix()));
666 }
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682 public static void applyCartSymOp(int n, double[] x, double[] y, double[] z,
683 double[] mateX, double[] mateY, double[] mateZ, SymOp symOp) {
684 if (x == null || y == null || z == null) {
685 throw new IllegalArgumentException("The input arrays x, y and z must not be null.");
686 }
687 if (x.length < n || y.length < n || z.length < n) {
688 throw new IllegalArgumentException("The input arrays x, y and z must be of length n: " + n);
689 }
690 if (mateX == null || mateY == null || mateZ == null) {
691 throw new IllegalArgumentException("The output arrays mateX, mateY and mateZ must not be null.");
692 }
693 if (mateX.length < n || mateY.length < n || mateZ.length < n) {
694 throw new IllegalArgumentException("The output arrays mateX, mateY and mateZ must be of length n: " + n);
695 }
696
697 final double[][] rot = symOp.rot;
698 final double[] trans = symOp.tr;
699
700 final double rot00 = rot[0][0];
701 final double rot10 = rot[1][0];
702 final double rot20 = rot[2][0];
703 final double rot01 = rot[0][1];
704 final double rot11 = rot[1][1];
705 final double rot21 = rot[2][1];
706 final double rot02 = rot[0][2];
707 final double rot12 = rot[1][2];
708 final double rot22 = rot[2][2];
709 final double t0 = trans[0];
710 final double t1 = trans[1];
711 final double t2 = trans[2];
712 for (int i = 0; i < n; i++) {
713 double xc = x[i];
714 double yc = y[i];
715 double zc = z[i];
716
717 mateX[i] = rot00 * xc + rot01 * yc + rot02 * zc + t0;
718 mateY[i] = rot10 * xc + rot11 * yc + rot12 * zc + t1;
719 mateZ[i] = rot20 * xc + rot21 * yc + rot22 * zc + t2;
720 }
721 }
722
723
724
725
726
727
728
729
730 public static void applyCartesianSymOp(double[] xyz, double[] mate, SymOp symOp) {
731 applyCartesianSymOp(xyz, mate, symOp, null);
732 }
733
734
735
736
737
738
739
740
741
742 public static void applyCartesianSymOp(double[] xyz, double[] mate, SymOp symOp, boolean[] mask) {
743 var rot = symOp.rot;
744 var trans = symOp.tr;
745
746 assert (xyz.length % 3 == 0);
747 assert (xyz.length == mate.length);
748 int len = xyz.length / 3;
749
750
751 var rot00 = rot[0][0];
752 var rot10 = rot[1][0];
753 var rot20 = rot[2][0];
754 var rot01 = rot[0][1];
755 var rot11 = rot[1][1];
756 var rot21 = rot[2][1];
757 var rot02 = rot[0][2];
758 var rot12 = rot[1][2];
759 var rot22 = rot[2][2];
760 var tx = trans[0];
761 var ty = trans[1];
762 var tz = trans[2];
763
764 if (mask == null) {
765 for (int i = 0; i < len; i++) {
766 int index = i * 3;
767 var xc = xyz[index + XX];
768 var yc = xyz[index + YY];
769 var zc = xyz[index + ZZ];
770
771 mate[index + XX] = rot00 * xc + rot01 * yc + rot02 * zc + tx;
772 mate[index + YY] = rot10 * xc + rot11 * yc + rot12 * zc + ty;
773 mate[index + ZZ] = rot20 * xc + rot21 * yc + rot22 * zc + tz;
774 }
775 } else {
776 for (int i = 0; i < len; i++) {
777 int index = i * 3;
778 var xc = xyz[index + XX];
779 var yc = xyz[index + YY];
780 var zc = xyz[index + ZZ];
781 if (mask[i]) {
782
783 mate[index + XX] = rot00 * xc + rot01 * yc + rot02 * zc + tx;
784 mate[index + YY] = rot10 * xc + rot11 * yc + rot12 * zc + ty;
785 mate[index + ZZ] = rot20 * xc + rot21 * yc + rot22 * zc + tz;
786 } else {
787 mate[index + XX] = xc;
788 mate[index + YY] = yc;
789 mate[index + ZZ] = zc;
790 }
791 }
792 }
793 }
794
795
796
797
798
799
800
801
802 public static void applyFracSymOp(double[] xyz, double[] mate, SymOp symOp) {
803 var rot = symOp.rot;
804 var trans = symOp.tr;
805 var xf = xyz[0];
806 var yf = xyz[1];
807 var zf = xyz[2];
808
809 mate[0] = rot[0][0] * xf + rot[0][1] * yf + rot[0][2] * zf + trans[0];
810 mate[1] = rot[1][0] * xf + rot[1][1] * yf + rot[1][2] * zf + trans[1];
811 mate[2] = rot[2][0] * xf + rot[2][1] * yf + rot[2][2] * zf + trans[2];
812 }
813
814
815
816
817
818
819
820
821
822
823
824
825
826 public static void applySymOp(int h, int k, int l, int[] mate, SymOp symOp, int nx, int ny, int nz) {
827 var rot = symOp.rot;
828 var trans = symOp.tr;
829
830 mate[0] =
831 (int) rot[0][0] * h + (int) rot[0][1] * k + (int) rot[0][2] * l + (int) rint(nx * trans[0]);
832 mate[1] =
833 (int) rot[1][0] * h + (int) rot[1][1] * k + (int) rot[1][2] * l + (int) rint(ny * trans[1]);
834 mate[2] =
835 (int) rot[2][0] * h + (int) rot[2][1] * k + (int) rot[2][2] * l + (int) rint(nz * trans[2]);
836 mate[0] = mod(mate[0], nx);
837 mate[1] = mod(mate[1], ny);
838 mate[2] = mod(mate[2], nz);
839 }
840
841
842
843
844
845
846
847
848 public static void applySymRot(HKL hkl, HKL mate, SymOp symOp) {
849 var rot = symOp.rot;
850 double h = hkl.getH();
851 double k = hkl.getK();
852 double l = hkl.getL();
853 double hs = rot[0][0] * h + rot[0][1] * k + rot[0][2] * l;
854 double ks = rot[1][0] * h + rot[1][1] * k + rot[1][2] * l;
855 double ls = rot[2][0] * h + rot[2][1] * k + rot[2][2] * l;
856
857 mate.setH((int) rint(hs));
858 mate.setK((int) rint(ks));
859 mate.setL((int) rint(ls));
860 }
861
862
863
864
865
866
867
868
869
870 public static void applyCartesianSymRot(double[] xyz, double[] mate, SymOp symOp) {
871 applyCartesianSymRot(xyz, mate, symOp, null);
872 }
873
874
875
876
877
878
879
880
881
882
883 public static void applyCartesianSymRot(double[] xyz, double[] mate, SymOp symOp, boolean[] mask) {
884 int l = xyz.length;
885 int n = l / 3;
886 assert (l % 3 == 0);
887 assert (mate.length == l);
888
889
890 var rot = symOp.rot;
891 var rot00 = rot[0][0];
892 var rot10 = rot[1][0];
893 var rot20 = rot[2][0];
894 var rot01 = rot[0][1];
895 var rot11 = rot[1][1];
896 var rot21 = rot[2][1];
897 var rot02 = rot[0][2];
898 var rot12 = rot[1][2];
899 var rot22 = rot[2][2];
900
901 if (mask == null) {
902 for (int i = 0; i < n; i++) {
903 int index = i * 3;
904 var xi = xyz[index + XX];
905 var yi = xyz[index + YY];
906 var zi = xyz[index + ZZ];
907
908 mate[index + XX] = rot00 * xi + rot01 * yi + rot02 * zi;
909 mate[index + YY] = rot10 * xi + rot11 * yi + rot12 * zi;
910 mate[index + ZZ] = rot20 * xi + rot21 * yi + rot22 * zi;
911 }
912 } else {
913 for (int i = 0; i < n; i++) {
914 int index = i * 3;
915 var xi = xyz[index + XX];
916 var yi = xyz[index + YY];
917 var zi = xyz[index + ZZ];
918 if (mask[i]) {
919
920 mate[index + XX] = rot00 * xi + rot01 * yi + rot02 * zi;
921 mate[index + YY] = rot10 * xi + rot11 * yi + rot12 * zi;
922 mate[index + ZZ] = rot20 * xi + rot21 * yi + rot22 * zi;
923 } else {
924 mate[index + XX] = xi;
925 mate[index + YY] = yi;
926 mate[index + ZZ] = zi;
927 }
928 }
929 }
930 }
931
932
933
934
935
936
937
938
939 public static void applyTransSymRot(HKL hkl, HKL mate, SymOp symOp) {
940 double[][] rot = symOp.rot;
941 double h = hkl.getH();
942 double k = hkl.getK();
943 double l = hkl.getL();
944
945 double hs = rot[0][0] * h + rot[1][0] * k + rot[2][0] * l;
946 double ks = rot[0][1] * h + rot[1][1] * k + rot[2][1] * l;
947 double ls = rot[0][2] * h + rot[1][2] * k + rot[2][2] * l;
948
949 mate.setH((int) rint(hs));
950 mate.setK((int) rint(ks));
951 mate.setL((int) rint(ls));
952 }
953
954
955
956
957
958
959
960 public static String asMatrixString(SymOp symOp) {
961 double[][] values = symOp.asMatrix();
962 return format("""
963 %14.8f %14.8f %14.8f \\
964 %14.8f %14.8f %14.8f \\
965 %14.8f %14.8f %14.8f \\
966 %14.8f %14.8f %14.8f \
967 """, values[0][0],
968 values[0][1], values[0][2], values[1][0], values[1][1], values[1][2], values[2][0],
969 values[2][1], values[2][2], values[0][3], values[1][3], values[2][3]);
970 }
971
972
973
974
975
976
977
978 public static SymOp invertSymOp(SymOp symOp) {
979 var tr = symOp.tr;
980 var rot = symOp.rot;
981 var inv = mat3Inverse(rot);
982 return new SymOp(inv,
983 new double[]{-dot(inv[0], tr), -dot(inv[1], tr), -dot(inv[2], tr)});
984 }
985
986
987
988
989
990
991
992 public static SymOp parse(String s) {
993 String[] tokens = s.split(" +");
994 if (tokens.length < 12) {
995 return null;
996 }
997 return new SymOp(new double[][]{
998 {parseDouble(tokens[0]), parseDouble(tokens[1]), parseDouble(tokens[2])},
999 {parseDouble(tokens[3]), parseDouble(tokens[4]), parseDouble(tokens[5])},
1000 {parseDouble(tokens[6]), parseDouble(tokens[7]), parseDouble(tokens[8])}},
1001 new double[]{parseDouble(tokens[9]), parseDouble(tokens[10]), parseDouble(tokens[11])});
1002 }
1003
1004
1005
1006
1007
1008
1009
1010 public static SymOp randomSymOpFactory(double scalar) {
1011 double[] tr = {scalar * (random() - 0.5), scalar * (random() - 0.5), scalar * (random() - 0.5)};
1012 return randomSymOpFactory(tr);
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 public static SymOp randomSymOpFactory(double[] tr) {
1026 double[][] rot = new double[3][3];
1027 double PI2 = 2.0 * PI;
1028 double[] x = new double[3];
1029 x[0] = random();
1030 x[1] = random();
1031 x[2] = random();
1032
1033 double theta = x[0] * PI2;
1034
1035 double phi = x[1] * PI2;
1036
1037 double z = x[2] * 2.0;
1038
1039
1040
1041
1042
1043
1044
1045 double r = sqrt(z);
1046 double Vx = sin(phi) * r;
1047 double Vy = cos(phi) * r;
1048 double Vz = sqrt(2.0 - z);
1049
1050
1051
1052
1053
1054 double st = sin(theta);
1055 double ct = cos(theta);
1056 double Sx = Vx * ct - Vy * st;
1057 double Sy = Vx * st + Vy * ct;
1058
1059
1060 rot[0][0] = Vx * Sx - ct;
1061 rot[0][1] = Vx * Sy - st;
1062 rot[0][2] = Vx * Vz;
1063 rot[1][0] = Vy * Sx + st;
1064 rot[1][1] = Vy * Sy - ct;
1065 rot[1][2] = Vy * Vz;
1066 rot[2][0] = Vz * Sx;
1067 rot[2][1] = Vz * Sy;
1068
1069 rot[2][2] = 1.0 - z;
1070
1071 return new SymOp(rot, tr);
1072 }
1073
1074
1075
1076
1077
1078
1079
1080 private static String trtoString(double tr) {
1081 if (tr == f12) {
1082 return "+1/2";
1083 }
1084 if (tr == f13) {
1085 return "+1/3";
1086 }
1087 if (tr == f23) {
1088 return "+2/3";
1089 }
1090 if (tr == f14) {
1091 return "+1/4";
1092 }
1093 if (tr == f34) {
1094 return "+3/4";
1095 }
1096 if (tr == f16) {
1097 return "+1/6";
1098 }
1099 if (tr == f56) {
1100 return "+5/6";
1101 }
1102
1103 return "";
1104 }
1105
1106
1107
1108
1109 @Override
1110 public String toString() {
1111 StringBuilder sb = new StringBuilder(" Rotation operator:\n");
1112 sb.append(format(" [[%4.1f,%4.1f,%4.1f]\n [%4.1f,%4.1f,%4.1f]\n [%4.1f,%4.1f,%4.1f]]\n",
1113 rot[0][0], rot[0][1], rot[0][2],
1114 rot[1][0], rot[1][1], rot[1][2],
1115 rot[2][0], rot[2][1], rot[2][2]));
1116 sb.append(" Translation:\n");
1117 sb.append(format(" [%4.2f,%4.2f,%4.2f]", tr[0], tr[1], tr[2]));
1118 return sb.toString();
1119 }
1120
1121
1122
1123
1124
1125
1126 public String toStringPrecise() {
1127 StringBuilder sb = new StringBuilder(" Rotation operator:\n");
1128 sb.append(format(
1129 " [[%18.16e,%18.16e,%18.16e]\n [%18.16e,%18.16e,%18.16e]\n [%18.16e,%18.16e,%18.16e]]\n",
1130 rot[0][0], rot[0][1], rot[0][2],
1131 rot[1][0], rot[1][1], rot[1][2],
1132 rot[2][0], rot[2][1], rot[2][2]));
1133 sb.append(" Translation:\n");
1134 sb.append(format(" [%18.16e,%18.16e,%18.16e]", tr[0], tr[1], tr[2]));
1135 return sb.toString();
1136 }
1137
1138
1139
1140
1141
1142
1143 public String toXYZString() {
1144 StringBuilder sb = new StringBuilder();
1145 for (int i = 0; i < 3; i++) {
1146 boolean s = false;
1147 if (rot[i][0] < 0.0) {
1148 sb.append("-X");
1149 s = true;
1150 } else if (rot[i][0] > 0.0) {
1151 sb.append("X");
1152 s = true;
1153 }
1154 if (rot[i][1] < 0.0) {
1155 sb.append("-Y");
1156 s = true;
1157 } else if (rot[i][1] > 0.0) {
1158 sb.append(s ? "+Y" : "Y");
1159 s = true;
1160 }
1161 if (rot[i][2] < 0.0) {
1162 sb.append("-Z");
1163 } else if (rot[i][2] > 0.0) {
1164 sb.append(s ? "+Z" : "Z");
1165 }
1166
1167 if (tr[i] > 0.0) {
1168 sb.append(trtoString(tr[i]));
1169 }
1170
1171 if (i < 2) {
1172 sb.append(", ");
1173 }
1174 }
1175 return sb.toString();
1176 }
1177 }