1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 package ffx.xray.cli;
39
40 import ffx.potential.MolecularAssembly;
41 import ffx.utilities.FFXProperty;
42 import ffx.xray.CrystalReciprocalSpace;
43 import ffx.xray.CrystalReciprocalSpace.SolventModel;
44 import ffx.xray.DiffractionData;
45 import ffx.xray.RefinementEnergy;
46 import ffx.xray.RefinementMinimize;
47 import ffx.xray.RefinementMinimize.RefinementMode;
48 import ffx.xray.parsers.DiffractionFile;
49 import org.apache.commons.configuration2.CompositeConfiguration;
50 import org.apache.commons.io.FilenameUtils;
51 import picocli.CommandLine.ArgGroup;
52 import picocli.CommandLine.Option;
53 import picocli.CommandLine.ParseResult;
54
55 import java.util.ArrayList;
56 import java.util.List;
57 import java.util.logging.Logger;
58
59 import static ffx.utilities.PropertyGroup.StructuralRefinement;
60 import static java.lang.Boolean.parseBoolean;
61 import static java.lang.Double.parseDouble;
62 import static java.lang.String.format;
63
64
65
66
67
68
69
70
71 public class XrayOptions extends DataRefinementOptions {
72
73 private static final Logger logger = Logger.getLogger(XrayOptions.class.getName());
74
75
76
77
78 @ArgGroup(heading = "%n X-ray Refinement Options%n", validate = false)
79 private final XrayOptionGroup group = new XrayOptionGroup();
80
81
82
83 @ArgGroup(heading = "%n X-ray Reflection Data Options%n", validate = false)
84 private final XrayReflectionsGroup reflectionGroup = new XrayReflectionsGroup();
85
86
87
88 @ArgGroup(heading = "%n X-ray B-Factor Options%n", validate = false)
89 private final BFactorGroup bfactorGroup = new BFactorGroup();
90
91
92
93 @ArgGroup(heading = "%n X-ray Target Options%n", validate = false)
94 private final ScatteringGroup targetGroup = new ScatteringGroup();
95
96
97
98 @ArgGroup(heading = "%n X-ray Bulk Solvent Options%n", validate = false)
99 private final BulkSolventGroup solventGroup = new BulkSolventGroup();
100
101
102
103 public RefinementMode refinementMode = RefinementMode.COORDINATES;
104
105
106
107 public SolventModel solventModel = SolventModel.POLYNOMIAL;
108
109
110
111
112 public void init() {
113 refinementMode = RefinementMinimize.parseMode(group.modeString);
114 solventModel = CrystalReciprocalSpace.parseSolventModel(solventGroup.solventString);
115 }
116
117
118
119
120
121
122
123
124 public List<DiffractionFile> processData(List<String> filenames, MolecularAssembly[] systems) {
125 List<DiffractionFile> diffractionfiles = new ArrayList<>();
126
127 logger.info("\n");
128
129 if (filenames.size() > 1) {
130 logger.info(format(" Diffraction file = %s, weight = %3.1f, neutron = %b", filenames.get(1), wA, Boolean.FALSE));
131 DiffractionFile diffractionfile = new DiffractionFile(filenames.get(1), wA, false);
132 diffractionfiles.add(diffractionfile);
133 }
134
135 if (reflectionGroup.data != null) {
136 for (int i = 0; i < reflectionGroup.data.length; i += 3) {
137 boolean neutron = false;
138 double w = wA;
139 if (reflectionGroup.data.length > i + 1) {
140 try {
141 w = parseDouble(reflectionGroup.data[i + 1]);
142 } catch (Exception e) {
143
144 }
145 }
146 if (reflectionGroup.data.length > i + 2) {
147 try {
148 neutron = parseBoolean(reflectionGroup.data[i + 2]);
149 } catch (Exception e) {
150
151 }
152 }
153 logger.info(format(" Diffraction file = %s, weight = %3.1f, neutron = %b", reflectionGroup.data[i], w, neutron));
154 DiffractionFile diffractionfile = new DiffractionFile(reflectionGroup.data[i], w, neutron);
155 diffractionfiles.add(diffractionfile);
156 }
157 }
158
159 if (diffractionfiles.isEmpty()) {
160 String filename = systems[0].getFile().getAbsolutePath();
161 filename = FilenameUtils.removeExtension(filename);
162 filename = FilenameUtils.getBaseName(filename);
163
164 logger.info(format(" Diffraction from = %s, weight = %3.1f, neutron = %b", filename, wA, false));
165 DiffractionFile diffractionfile = new DiffractionFile(systems, 1.0, false);
166 diffractionfiles.add(diffractionfile);
167 }
168
169 return diffractionfiles;
170 }
171
172
173
174
175
176
177
178 public void setProperties(ParseResult parseResult, CompositeConfiguration properties) {
179
180 if (!parseResult.hasMatchedOption("wA")) {
181 wA = properties.getDouble("data-weight", wA);
182 }
183 properties.setProperty("data-weight", wA);
184
185
186 if (!parseResult.hasMatchedOption("bSimWeight")) {
187 bfactorGroup.bSimWeight = properties.getDouble("b-sim-weight", bfactorGroup.bSimWeight);
188 }
189 properties.setProperty("b-sim-weight", bfactorGroup.bSimWeight);
190
191
192 if (!parseResult.hasMatchedOption("fSigFCutoff")) {
193 reflectionGroup.fSigFCutoff = properties.getDouble("f-sigf-cutoff", reflectionGroup.fSigFCutoff);
194 }
195 properties.setProperty("f-sigf-cutoff", reflectionGroup.fSigFCutoff);
196
197
198 if (!parseResult.hasMatchedOption("gridSearch")) {
199 solventGroup.gridSearch = properties.getBoolean("solvent-grid-search", solventGroup.gridSearch);
200 }
201 properties.setProperty("solvent-grid-search", solventGroup.gridSearch);
202
203
204 if (!parseResult.hasMatchedOption("nBins")) {
205 reflectionGroup.nBins = properties.getInt("reflection-bins", reflectionGroup.nBins);
206 }
207 properties.setProperty("reflection-bins", reflectionGroup.nBins);
208
209
210 if (!parseResult.hasMatchedOption("sampling")) {
211 targetGroup.sampling = properties.getDouble("sampling", targetGroup.sampling);
212 }
213 properties.setProperty("sampling", targetGroup.sampling);
214
215
216 if (!parseResult.hasMatchedOption("aRadBuffer")) {
217 targetGroup.aRadBuffer = properties.getDouble("scattering-buffer", targetGroup.aRadBuffer);
218 }
219 properties.setProperty("scattering-buffer", targetGroup.aRadBuffer);
220
221
222 if (!parseResult.hasMatchedOption("rFreeFlag")) {
223 reflectionGroup.rFreeFlag = properties.getInt("rfree-flag", reflectionGroup.rFreeFlag);
224 }
225 properties.setProperty("rfree-flag", reflectionGroup.rFreeFlag);
226
227
228 if (!parseResult.hasMatchedOption("noSplineFit")) {
229 targetGroup.noSplineFit = properties.getBoolean("no-spline-fit", targetGroup.noSplineFit);
230 }
231 properties.setProperty("no-spline-fit", targetGroup.noSplineFit);
232
233
234 if (!parseResult.hasMatchedOption("allGaussians")) {
235 targetGroup.useAllGaussians = !properties.getBoolean("use-3g", !targetGroup.useAllGaussians);
236 }
237 properties.setProperty("use-3g", !targetGroup.useAllGaussians);
238
239
240 if (!parseResult.hasMatchedOption("xrayScaleTol")) {
241 targetGroup.xrayScaleTol = properties.getDouble("xray-scale-tol", targetGroup.xrayScaleTol);
242 }
243 properties.setProperty("xray-scale-tol", targetGroup.xrayScaleTol);
244
245
246 if (!parseResult.hasMatchedOption("sigmaATol")) {
247 targetGroup.sigmaATol = properties.getDouble("sigmaa-tol", targetGroup.sigmaATol);
248 }
249 properties.setProperty("sigmaa-tol", targetGroup.sigmaATol);
250
251
252 if (!parseResult.hasMatchedOption("nResidueBFactor")) {
253 bfactorGroup.nResidueBFactor = properties
254 .getInt("n-residue-bfactor", bfactorGroup.nResidueBFactor);
255 }
256 properties.setProperty("n-residue-bfactor", Integer.toString(bfactorGroup.nResidueBFactor));
257 if (bfactorGroup.nResidueBFactor > 0) {
258 properties.setProperty("residue-bfactor", "true");
259 }
260
261
262 if (!parseResult.hasMatchedOption("anisoU")) {
263 bfactorGroup.anisoU = properties.getBoolean("add-anisou", bfactorGroup.anisoU);
264 }
265 properties.setProperty("add-anisou", bfactorGroup.anisoU);
266
267
268 if (!parseResult.hasMatchedOption("refineMolOcc")) {
269 group.refineMolOcc = properties.getBoolean("refine-mol-occ", group.refineMolOcc);
270 }
271 properties.setProperty("refine-mol-occ", group.refineMolOcc);
272 }
273
274
275
276
277
278
279
280
281
282 public DiffractionData getDiffractionData(List<String> filenames, MolecularAssembly[] assemblies,
283 CompositeConfiguration properties) {
284
285 List<DiffractionFile> diffractionFiles = processData(filenames, assemblies);
286 return new DiffractionData(assemblies, properties, solventModel,
287 diffractionFiles.toArray(new DiffractionFile[0]));
288 }
289
290
291
292
293 private static class XrayOptionGroup {
294
295
296
297
298 @Option(names = {"--rmo", "--refineMolOcc"}, paramLabel = "false", defaultValue = "false",
299 description = "Refine molecular occupancy.")
300 @FFXProperty(name = "refine-mol-occ", propertyGroup = StructuralRefinement, defaultValue = "false",
301 description = "Refine molecular occupancy.")
302 boolean refineMolOcc = false;
303
304
305
306
307
308
309 @Option(names = {"-m", "--mode"}, paramLabel = "coordinates", defaultValue = "coordinates",
310 description = "Refinement mode: coordinates, bfactors and/or occupancies.")
311 String modeString = "coordinates";
312 }
313
314
315
316
317 private static class XrayReflectionsGroup {
318
319
320
321
322 @Option(names = {"--nBins"}, paramLabel = "10", defaultValue = "10",
323 description = "The number of refection bins.")
324 @FFXProperty(name = "reflection-bins", propertyGroup = StructuralRefinement, defaultValue = "10",
325 description = "The number of refection bins.")
326 int nBins = 10;
327
328
329
330
331 @Option(names = {"--FSigFCutoff"}, paramLabel = "-1.0", defaultValue = "-1.0",
332 description = "F / SigF cutoff (-1.0 is no cutoff).")
333 @FFXProperty(name = "f-sigf-cutoff", propertyGroup = StructuralRefinement, defaultValue = "-1.0",
334 description = "F / SigF cutoff (-1.0 is no cutoff)."
335 )
336 double fSigFCutoff = -1.0;
337
338
339
340
341 @Option(names = {"-R", "--rFreeFlag"}, paramLabel = "-1", defaultValue = "-1",
342 description = "R-Free Flag value (-1 attempts to auto-determine from the data).")
343 @FFXProperty(name = "rfree-flag", propertyGroup = StructuralRefinement, defaultValue = "-1",
344 description = "R-Free Flag value (-1 attempts to auto-determine from the data)."
345 )
346 int rFreeFlag = -1;
347
348
349
350
351
352 @Option(names = {"-X", "--data"}, arity = "3",
353 description = "Specify input data filename, its weight (wA) and if its from a neutron experiment (e.g. -X filename 1.0 false).")
354 String[] data = null;
355 }
356
357
358
359
360 private static class BFactorGroup {
361
362
363
364
365 @Option(names = {"-B", "--bSimWeight"}, paramLabel = "1.0", defaultValue = "1.0",
366 description = "B-Factor similarity weight.")
367 @FFXProperty(name = "b-sim-weight", propertyGroup = StructuralRefinement, defaultValue = "1.0", description = """
368 B-factor harmonic restraint weight between bonded atoms.
369 This can be increased for low resolution structures to ~5-10.
370 """)
371 double bSimWeight = 1.0;
372
373
374
375
376 @Option(names = {"--nResidueBFactor"}, paramLabel = "0", defaultValue = "0",
377 description = "Number of residues per B-factor. 0 uses atomic B-factors (default).")
378 @FFXProperty(name = "n-residue-bfactor", propertyGroup = StructuralRefinement, defaultValue = "0",
379 description = "Number of residues per B-factor. 0 uses atomic B-factors (default).")
380 int nResidueBFactor = 0;
381
382
383
384
385 @Option(names = {"-U", "--addAnisoU"}, paramLabel = "false", defaultValue = "false",
386 description = "Add Anisotropic B-Factors to refinement.")
387 @FFXProperty(name = "add-anisou", propertyGroup = StructuralRefinement, defaultValue = "false",
388 description = "Add Anisotropic B-Factors to refinement.")
389 boolean anisoU = false;
390
391 }
392
393
394
395
396 private static class ScatteringGroup {
397
398
399
400
401 @Option(names = {"--aRadBuffer"}, paramLabel = "0.75", defaultValue = "0.75",
402 description = "Scattering is evaluated within the atomic radius plus this buffer (Å).")
403 @FFXProperty(name = "scattering-buffer", propertyGroup = StructuralRefinement, defaultValue = "0.6",
404 description = "Scattering is evaluated within the atomic radius plus this buffer (Å).")
405 double aRadBuffer = 0.75;
406
407
408
409
410 @Option(names = {"-G", "--sampling"}, paramLabel = "0.6", defaultValue = "0.6",
411 description = "The number of grid spaces per Angstrom for the scattering FFT grid.")
412 @FFXProperty(name = "sampling", propertyGroup = StructuralRefinement, defaultValue = "0.6",
413 description = "The number of grid spaces per Angstrom for the scattering FFT grid.")
414 double sampling = 0.6;
415
416
417
418
419 @Option(names = {"--nsf", "--noSplineFit"}, paramLabel = "false", defaultValue = "false",
420 description = "Use a resolution dependent spline scale factor.")
421 @FFXProperty(name = "no-spline-fit", propertyGroup = StructuralRefinement, defaultValue = "false",
422 description = "Do not use a resolution dependent spline scale factor.")
423 boolean noSplineFit = false;
424
425
426
427
428 @Option(names = {"-A", "--allGaussians"}, paramLabel = "false", defaultValue = "false",
429 description = "Use all defined Gaussians for atomic scattering density (the default is to use the top 3).")
430 @FFXProperty(name = "use-3g", propertyGroup = StructuralRefinement, defaultValue = "true",
431 description = "The three Gaussians with the largest amplitudes define the atomic scattering density.")
432 boolean useAllGaussians = false;
433
434
435
436
437 @Option(names = {"--xrayScaleTol"}, paramLabel = "1.0e-4", defaultValue = "1.0e-4",
438 description = "X-ray scale optimization tolerance.")
439 @FFXProperty(name = "xray-scale-tol", propertyGroup = StructuralRefinement, defaultValue = "1.0e-4",
440 description = "X-ray scale optimization tolerance.")
441 double xrayScaleTol = 1.0e-4;
442
443
444
445
446 @Option(names = {"--sigmaATol"}, paramLabel = "0.05", defaultValue = "0.05",
447 description = "Sigma A optimization tolerance.")
448 @FFXProperty(name = "sigmaa-tol", propertyGroup = StructuralRefinement, defaultValue = "0.05",
449 description = "Sigma A optimization tolerance.")
450 double sigmaATol = 0.05;
451 }
452
453
454
455
456 private static class BulkSolventGroup {
457
458
459
460
461 @Option(names = {"-S", "--solventGridSearch"}, paramLabel = "false", defaultValue = "false",
462 description = "Perform a grid search for optimal bulk solvent parameters.")
463 @FFXProperty(name = "solvent-grid-search", propertyGroup = StructuralRefinement, defaultValue = "false",
464 description = "Perform a grid search for optimal bulk solvent parameters.")
465 boolean gridSearch = false;
466
467
468
469
470 @Option(names = {"--sol", "--solvent"}, paramLabel = "POLYNOMIAL", defaultValue = "POLYNOMIAL",
471 description = "Bulk solvent scattering model [Polynomial/Gaussian/Binary/None]")
472 String solventString = "POLYNOMIAL";
473 }
474
475
476
477
478
479
480
481 public RefinementEnergy toXrayEnergy(DiffractionData diffractionData) {
482 diffractionData.scaleBulkFit();
483 diffractionData.printStats();
484 return new RefinementEnergy(diffractionData, refinementMode);
485 }
486 }