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 org.apache.commons.configuration2.CompositeConfiguration;
41
42 import javax.annotation.Nullable;
43 import java.util.ArrayList;
44 import java.util.HashMap;
45 import java.util.Map.Entry;
46
47 import static ffx.crystal.SymOp.applySymRot;
48 import static ffx.crystal.SymOp.applyTransSymRot;
49 import static ffx.numerics.math.ScalarMath.mod;
50 import static org.apache.commons.math3.util.FastMath.PI;
51 import static org.apache.commons.math3.util.FastMath.cos;
52 import static org.apache.commons.math3.util.FastMath.floor;
53 import static org.apache.commons.math3.util.FastMath.max;
54 import static org.apache.commons.math3.util.FastMath.min;
55 import static org.apache.commons.math3.util.FastMath.rint;
56
57
58
59
60
61
62
63
64
65
66 public class ReflectionList {
67
68
69
70
71 public final ArrayList<HKL> hklList = new ArrayList<>();
72
73
74
75 public final Crystal crystal;
76
77
78
79 public final SpaceGroup spaceGroup;
80
81
82
83 public final Resolution resolution;
84
85
86
87 final HashMap<String, HKL> hklMap = new HashMap<>();
88
89
90
91 public int nBins = 10;
92
93
94
95 private final double[] histogram = new double[1001];
96
97
98
99 private double minResolution;
100
101
102
103 private double maxResolution;
104
105
106
107
108
109
110
111 public ReflectionList(Crystal crystal, Resolution resolution) {
112 this(crystal, resolution, null);
113 }
114
115
116
117
118
119
120
121
122 public ReflectionList(Crystal crystal, Resolution resolution, CompositeConfiguration properties) {
123 this.crystal = crystal;
124 this.spaceGroup = crystal.spaceGroup;
125 this.resolution = resolution;
126
127 int hMax = (int) (this.crystal.a / this.resolution.resolutionLimit());
128 int kMax = (int) (this.crystal.b / this.resolution.resolutionLimit());
129 int lMax = (int) (this.crystal.c / this.resolution.resolutionLimit());
130
131 minResolution = Double.POSITIVE_INFINITY;
132 maxResolution = Double.NEGATIVE_INFINITY;
133 int n = 0;
134
135 HKL hkl = new HKL();
136 for (int h = -hMax; h <= hMax; h++) {
137 hkl.setH(h);
138 for (int k = -kMax; k <= kMax; k++) {
139 hkl.setK(k);
140 for (int l = -lMax; l <= lMax; l++) {
141 hkl.setL(l);
142
143 double res = this.crystal.invressq(hkl);
144 getEpsilon(hkl);
145 LaueSystem laueSystem = spaceGroup.laueSystem;
146 if (laueSystem.checkRestrictions(h, k, l)
147 && resolution.inInverseResSqRange(res)
148 && !hkl.sysAbs()) {
149 minResolution = min(res, minResolution);
150 maxResolution = max(res, maxResolution);
151 String s = (h + "_" + k + "_" + l).intern();
152 hklMap.put(s, new HKL(hkl.getH(), hkl.getK(), hkl.getL(), hkl.getEpsilon(), hkl.allowed));
153 n++;
154 }
155 }
156 }
157 }
158
159 n = 0;
160 for (Entry<String, HKL> entry : hklMap.entrySet()) {
161 HKL ih = entry.getValue();
162 ih.setIndex(n);
163 hklList.add(ih);
164 n++;
165 }
166
167
168 for (HKL ih : hklList) {
169 double r = (this.crystal.invressq(ih) - minResolution) / (maxResolution - minResolution);
170 int i = (int) (min(r, 0.999) * 1000.0);
171 histogram[i + 1] += 1.0;
172 }
173
174
175 for (int i = 1; i < histogram.length; i++) {
176 histogram[i] += histogram[i - 1];
177 }
178 for (int i = 0; i < histogram.length; i++) {
179 histogram[i] /= histogram[histogram.length - 1];
180 }
181
182
183 setResolutionBins(properties);
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198 public ReflectionList(double a, double b, double c, double alpha, double beta, double gamma,
199 String sg, double resolution) {
200 this(new Crystal(a, b, c, alpha, beta, gamma, sg), new Resolution(resolution));
201 }
202
203
204
205
206
207
208
209
210 public boolean findSymHKL(HKL hkl, HKL mate) {
211 return findSymHKL(hkl, mate, false);
212 }
213
214
215
216
217
218
219
220
221
222
223 public boolean findSymHKL(int h, int k, int l, HKL mate) {
224 return findSymHKL(new HKL(h, k, l), mate, false);
225 }
226
227
228
229
230
231
232
233
234
235
236
237 public boolean findSymHKL(int h, int k, int l, HKL mate, boolean transpose) {
238 return findSymHKL(new HKL(h, k, l), mate, transpose);
239 }
240
241
242
243
244
245
246
247
248
249 public HKL getHKL(int h, int k, int l) {
250 String s = (h + "_" + k + "_" + l);
251 return hklMap.get(s);
252 }
253
254
255
256
257
258
259
260 public HKL getHKL(HKL hkl) {
261 return getHKL(hkl.getH(), hkl.getK(), hkl.getL());
262 }
263
264
265
266
267
268
269 public double getMaxResolution() {
270 return maxResolution;
271 }
272
273
274
275
276
277
278 public double getMinResolution() {
279 return minResolution;
280 }
281
282
283
284
285
286
287
288 public boolean hasHKL(HKL hkl) {
289 return hasHKL(hkl.getH(), hkl.getK(), hkl.getL());
290 }
291
292
293
294
295
296
297
298 public final double ordinal(double s) {
299 double r = (s - minResolution) / (maxResolution - minResolution);
300 r = min(r, 0.999) * 1000.0;
301 int i = (int) r;
302 r -= floor(r);
303 return ((1.0 - r) * histogram[i] + r * histogram[i + 1]);
304 }
305
306
307
308
309 @Override
310 public String toString() {
311 return " Reflection list with "
312 + this.hklList.size()
313 + " reflections, spacegroup "
314 + this.spaceGroup.shortName
315 + " resolution limit: "
316 + resolution.resolutionLimit();
317 }
318
319
320
321
322
323
324
325
326
327 private boolean findSymHKL(HKL hkl, HKL mate, boolean transpose) {
328 int nsym = spaceGroup.numPrimitiveSymEquiv;
329
330 for (int i = 0; i < nsym; i++) {
331 if (transpose) {
332 applyTransSymRot(hkl, mate, spaceGroup.symOps.get(i));
333 } else {
334 applySymRot(hkl, mate, spaceGroup.symOps.get(i));
335 }
336
337 LaueSystem laueSystem = spaceGroup.laueSystem;
338 if (laueSystem.checkRestrictions(mate.getH(), mate.getK(), mate.getL())) {
339 return false;
340 }
341 if (laueSystem.checkRestrictions(-mate.getH(), -mate.getK(), -mate.getL())) {
342 mate.setH(-mate.getH());
343 mate.setK(-mate.getK());
344 mate.setL(-mate.getL());
345 return true;
346 }
347 }
348
349 mate.setH(hkl.getH());
350 mate.setK(hkl.getK());
351 mate.setL(hkl.getL());
352 return false;
353 }
354
355
356
357
358
359
360
361
362
363 private boolean hasHKL(int h, int k, int l) {
364 String s = (h + "_" + k + "_" + l);
365 return hklMap.containsKey(s);
366 }
367
368 private void getEpsilon(HKL hkl) {
369 int epsilon = 1;
370 int allowed = 255;
371
372 int nSym = spaceGroup.symOps.size();
373 for (int i = 1; i < nSym; i++) {
374 HKL mate = new HKL();
375 SymOp symOp = spaceGroup.symOps.get(i);
376 applySymRot(hkl, mate, symOp);
377 double shift = symOp.symPhaseShift(hkl);
378 if (mate.equals(hkl)) {
379 if (cos(shift) > 0.999) {
380 epsilon++;
381 } else {
382 allowed = 0;
383 epsilon = 0;
384 break;
385 }
386 } else if (mate.equals(hkl.neg())) {
387
388 allowed = (int) rint(mod(-0.5 * shift, PI) / (PI / HKL.ndiv));
389 }
390 }
391 if (hkl.getH() == 0 && hkl.getK() == 0 && hkl.getL() == 0) {
392 allowed = 0;
393 }
394
395 hkl.setEpsilon(epsilon);
396 hkl.setAllowed(allowed);
397 }
398
399 private void setResolutionBins(@Nullable CompositeConfiguration properties) {
400 if (properties != null) {
401 nBins = properties.getInt("reflection-bins", 10);
402 }
403 double nBinsDouble = nBins;
404 for (HKL ih : hklList) {
405 int bin = (int) (nBinsDouble * ordinal(crystal.invressq(ih)));
406 ih.bin = min(bin, nBins - 1);
407 }
408 }
409 }