View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.xray;
39  
40  import ffx.crystal.ReflectionList;
41  import ffx.numerics.math.ComplexNumber;
42  import org.apache.commons.configuration2.CompositeConfiguration;
43  
44  import java.util.Random;
45  import java.util.logging.Level;
46  import java.util.logging.Logger;
47  
48  import static ffx.numerics.math.ScalarMath.b2u;
49  import static java.lang.Double.isNaN;
50  import static java.lang.String.format;
51  import static org.apache.commons.math3.util.FastMath.PI;
52  import static org.apache.commons.math3.util.FastMath.sqrt;
53  
54  /**
55   * DiffractionRefinementData class.
56   *
57   * @author Timothy D. Fenn
58   * @since 1.0
59   */
60  public class DiffractionRefinementData {
61  
62    private static final Logger logger = Logger.getLogger(DiffractionRefinementData.class.getName());
63    /** Number of reflections in the data set. */
64    public final int n;
65    /** Array of R free flags; */
66    public final int[] freeR;
67    /** Calculated atomic structure factors. */
68    public final double[][] fc;
69    /** Calculated bulk solvent structure factors. */
70    public final double[][] fs;
71    /** Figure of merit and phase. */
72    public final double[][] fomPhi;
73    /** mFo - DFc coefficients. */
74    public final double[][] foFc1;
75    /** 2mFo - DFc coefficients. */
76    final double[][] foFc2;
77    /**
78     * F / Sig_F Cutoff.
79     */
80    public final double fSigFCutoff;
81    /** Number of scale parameters. */
82    final int nScale;
83    /** 2D array of F/sigF data. */
84    final double[][] fSigF;
85    /** Scaled sum of Fc and Fs */
86    final double[][] fcTot;
87    /** Derivatives with respect to Fc. */
88    final double[][] dFc;
89    /** Derivatives with respect to Fs. */
90    final double[][] dFs;
91    /** Number of resolution bins. */
92    final int nBins;
93    /** Spine scaling coefficients. */
94    public double[] spline;
95    /** SigmaA coefficient - s. */
96    public double[] sigmaA;
97    /** SigmaA coefficient - w. */
98    public double[] sigmaW;
99    /**
100    * Duplicated settings - these are also in DiffractionData, but duplicated here until settings are
101    * put in their own class.
102    */
103   public int rFreeFlag;
104   /** Log Likelihoods. */
105   double llkR, llkF;
106   /** Reciprocal space reference for structure factor calculations and computing derivatives. */
107   CrystalReciprocalSpace crystalReciprocalSpaceFc;
108   /**
109    * Reciprocal space reference for bulk solvent structure factor calculations and computing
110    * derivatives.
111    */
112   CrystalReciprocalSpace crystalReciprocalSpaceFs;
113   /** Scaled, E-like Fc. */
114   double[] esqFc;
115   /** Scaled, E-like Fo. */
116   double[] esqFo;
117   /** Bulk solvent scale and Ueq */
118   double bulkSolventK, bulkSolventUeq;
119   /**
120    * If true, the bulk solvent K and Ueq were set by properties and are fixed.
121    */
122   boolean bulkSolventFixed = false;
123   /** Overall model scale. */
124   double modelScaleK;
125   /** model anisotropic B */
126   double[] modelAnisoB = new double[6];
127 
128   /**
129    * allocate data given a {@link ffx.crystal.ReflectionList}
130    *
131    * @param properties configuration properties
132    * @param reflectionList {@link ffx.crystal.ReflectionList} to use to allocate data
133    */
134   public DiffractionRefinementData(
135       CompositeConfiguration properties, ReflectionList reflectionList) {
136 
137     int rflag = -1;
138     if (properties != null) {
139       rflag = properties.getInt("rfree-flag", -1);
140       fSigFCutoff = properties.getDouble("f-sigf-cutoff", -1.0);
141     } else {
142       fSigFCutoff = -1.0;
143     }
144 
145     this.n = reflectionList.hklList.size();
146     this.nScale = reflectionList.crystal.scaleN;
147     this.rFreeFlag = rflag;
148     this.nBins = reflectionList.nBins;
149     fSigF = new double[n][2];
150     freeR = new int[n];
151     fc = new double[n][2];
152     fs = new double[n][2];
153     fcTot = new double[n][2];
154     fomPhi = new double[n][2];
155     foFc2 = new double[n][2];
156     foFc1 = new double[n][2];
157     dFc = new double[n][2];
158     dFs = new double[n][2];
159 
160     for (int i = 0; i < n; i++) {
161       fSigF[i][0] = fSigF[i][1] = Double.NaN;
162       fcTot[i][0] = fcTot[i][1] = Double.NaN;
163     }
164 
165     spline = new double[nBins * 2];
166     sigmaA = new double[nBins];
167     sigmaW = new double[nBins];
168     esqFc = new double[nBins];
169     esqFo = new double[nBins];
170     for (int i = 0; i < nBins; i++) {
171       spline[i] = spline[i + nBins] = sigmaA[i] = esqFc[i] = esqFo[i] = 1.0;
172       sigmaW[i] = 0.05;
173     }
174 
175     // Initial guess for scaling/bulk solvent correction.
176     bulkSolventK = 0.33;
177     bulkSolventUeq = b2u(50.0);
178     modelScaleK = 0.0;
179   }
180 
181   /**
182    * FoFc2F
183    *
184    * @param i a int.
185    * @return a double.
186    */
187   public double FoFc2F(int i) {
188     ComplexNumber c = new ComplexNumber(foFc2[i][0], foFc2[i][1]);
189     return c.abs();
190   }
191 
192   /**
193    * FoFc2Phi
194    *
195    * @param i a int.
196    * @return a double.
197    */
198   public double FoFc2Phi(int i) {
199     ComplexNumber c = new ComplexNumber(foFc2[i][0], foFc2[i][1]);
200     return c.phase();
201   }
202 
203   /**
204    * get the amplitude of a complex Fc
205    *
206    * @param i reflection to get
207    * @return amplitude of Fc
208    */
209   public double fcF(int i) {
210     ComplexNumber c = new ComplexNumber(fc[i][0], fc[i][1]);
211     return c.abs();
212   }
213 
214   /**
215    * get the phase of a complex Fc
216    *
217    * @param i reflection to get
218    * @return phase of Fc
219    */
220   public double fcPhi(int i) {
221     ComplexNumber c = new ComplexNumber(fc[i][0], fc[i][1]);
222     return c.phase();
223   }
224 
225   /**
226    * fcTotF
227    *
228    * @param i a int.
229    * @return a double.
230    */
231   public double fcTotF(int i) {
232     ComplexNumber c = new ComplexNumber(fcTot[i][0], fcTot[i][1]);
233     return c.abs();
234   }
235 
236   /**
237    * fcTotPhi
238    *
239    * @param i a int.
240    * @return a double.
241    */
242   public double fcTotPhi(int i) {
243     ComplexNumber c = new ComplexNumber(fcTot[i][0], fcTot[i][1]);
244     return c.phase();
245   }
246 
247   /**
248    * foFc1F
249    *
250    * @param i a int.
251    * @return a double.
252    */
253   public double foFc1F(int i) {
254     ComplexNumber c = new ComplexNumber(foFc1[i][0], foFc1[i][1]);
255     return c.abs();
256   }
257 
258   /**
259    * foFc1Phi
260    *
261    * @param i a int.
262    * @return a double.
263    */
264   public double foFc1Phi(int i) {
265     ComplexNumber c = new ComplexNumber(foFc1[i][0], foFc1[i][1]);
266     return c.phase();
267   }
268 
269   /**
270    * fsF
271    *
272    * @param i a int.
273    * @return a double.
274    */
275   public double fsF(int i) {
276     ComplexNumber c = new ComplexNumber(fs[i][0], fs[i][1]);
277     return c.abs();
278   }
279 
280   /**
281    * fsPhi
282    *
283    * @param i a int.
284    * @return a double.
285    */
286   public double fsPhi(int i) {
287     ComplexNumber c = new ComplexNumber(fs[i][0], fs[i][1]);
288     return c.phase();
289   }
290 
291   /**
292    * Generate average F/sigF from anomalous F/sigF.
293    *
294    * @param anomalousFsigF an array of double.
295    */
296   public void generateFsigFfromAnomalousFsigF(double[][] anomalousFsigF) {
297     for (int i = 0; i < n; i++) {
298       if (isNaN(anomalousFsigF[i][0]) && isNaN(anomalousFsigF[i][2])) {
299         // Do Nothing.
300       } else if (isNaN(anomalousFsigF[i][0])) {
301         fSigF[i][0] = anomalousFsigF[i][2];
302         fSigF[i][1] = anomalousFsigF[i][3];
303       } else if (isNaN(anomalousFsigF[i][2])) {
304         fSigF[i][0] = anomalousFsigF[i][0];
305         fSigF[i][1] = anomalousFsigF[i][1];
306       } else {
307         fSigF[i][0] = (anomalousFsigF[i][0] + anomalousFsigF[i][2]) / 2.0;
308         fSigF[i][1] =
309             sqrt(
310                 anomalousFsigF[i][1] * anomalousFsigF[i][1]
311                     + anomalousFsigF[i][3] * anomalousFsigF[i][3]);
312       }
313     }
314   }
315 
316   /** Mark 5% of reflections for cross validation (R free flags). */
317   public void generateRFree() {
318     Random generator = new Random();
319     int free;
320     int nonfree;
321     int nfree = 0;
322 
323     if (rFreeFlag == 0) {
324       free = 0;
325       nonfree = 1;
326     } else {
327       free = 1;
328       nonfree = 0;
329     }
330 
331     for (int i = 0; i < n; i++) {
332       if (isNaN(fSigF[i][0])) {
333         freeR[i] = nonfree;
334         continue;
335       }
336 
337       int randomi = generator.nextInt(100);
338       if (randomi < 5) {
339         freeR[i] = free;
340         nfree++;
341       } else {
342         freeR[i] = nonfree;
343       }
344     }
345 
346     if (logger.isLoggable(Level.INFO)) {
347       logger.info(format(" Assigned %d of %d reflections to the R free set (5%%).\n", nfree, n));
348     }
349   }
350 
351   /**
352    * getF
353    *
354    * @param i a int.
355    * @return a double.
356    */
357   public double getF(int i) {
358     return fSigF[i][0];
359   }
360 
361   /**
362    * getFSigF
363    *
364    * @param i a int.
365    * @return an array of double.
366    */
367   public double[] getFSigF(int i) {
368     return fSigF[i];
369   }
370 
371   /**
372    * getFcTot
373    *
374    * @param i a int.
375    * @return a {@link ComplexNumber} object.
376    */
377   public ComplexNumber getFcTot(int i) {
378     return new ComplexNumber(fcTot[i][0], fcTot[i][1]);
379   }
380 
381   /**
382    * getFoFc1
383    *
384    * @param i a int.
385    * @return a {@link ComplexNumber} object.
386    */
387   public ComplexNumber getFoFc1(int i) {
388     return new ComplexNumber(foFc1[i][0], foFc1[i][1]);
389   }
390 
391   /**
392    * getFoFc1IP
393    *
394    * @param i a int.
395    * @param c a {@link ComplexNumber} object.
396    */
397   public void getFoFc1IP(int i, ComplexNumber c) {
398     c.re(foFc1[i][0]);
399     c.im(foFc1[i][1]);
400   }
401 
402   /**
403    * getFoFc2
404    *
405    * @param i a int.
406    * @return a {@link ComplexNumber} object.
407    */
408   public ComplexNumber getFoFc2(int i) {
409     return new ComplexNumber(foFc2[i][0], foFc2[i][1]);
410   }
411 
412   /**
413    * getFoFc2IP
414    *
415    * @param i a int.
416    * @param c a {@link ComplexNumber} object.
417    */
418   public void getFoFc2IP(int i, ComplexNumber c) {
419     c.re(foFc2[i][0]);
420     c.im(foFc2[i][1]);
421   }
422 
423   /**
424    * getFreeR
425    *
426    * @param i a int.
427    * @return a int.
428    */
429   public int getFreeR(int i) {
430     return freeR[i];
431   }
432 
433   /**
434    * getFs
435    *
436    * @param i a int.
437    * @return a {@link ComplexNumber} object.
438    */
439   public ComplexNumber getFs(int i) {
440     return new ComplexNumber(fs[i][0], fs[i][1]);
441   }
442 
443   /**
444    * getSigF
445    *
446    * @param i a int.
447    * @return a double.
448    */
449   public double getSigF(int i) {
450     return fSigF[i][1];
451   }
452 
453   /**
454    * Generate amplitudes from intensities.
455    *
456    * <p>This does NOT use French and Wilson caling, but just a simple square root.
457    */
458   public void intensitiesToAmplitudes() {
459     double tmp;
460 
461     for (int i = 0; i < n; i++) {
462       if (fSigF[i][0] > 0.0) {
463         tmp = fSigF[i][0];
464         fSigF[i][0] = sqrt(tmp);
465         if (fSigF[i][1] < tmp) {
466           fSigF[i][1] = fSigF[i][0] - sqrt(tmp - fSigF[i][1]);
467         } else {
468           fSigF[i][1] = fSigF[i][0];
469         }
470       } else if (!isNaN(fSigF[i][0])) {
471         fSigF[i][0] = 0.0;
472         fSigF[i][1] = 0.0;
473       }
474     }
475 
476     if (logger.isLoggable(Level.WARNING)) {
477       StringBuilder sb = new StringBuilder();
478       sb.append("\n Internally converting intensities to amplitudes.\n");
479       sb.append(" This does not use French & Wilson scaling.\n");
480       logger.info(sb.toString());
481     }
482   }
483 
484   /**
485    * isFreeR
486    *
487    * @param i a int.
488    * @param f a int.
489    * @return a boolean.
490    */
491   public boolean isFreeR(int i, int f) {
492     return (freeR[i] == f);
493   }
494 
495   /**
496    * return the current likelihood
497    *
498    * @return the free likelihood (Rfree based)
499    */
500   public double likelihoodFree() {
501     return llkF;
502   }
503 
504   /**
505    * return the current likelihood
506    *
507    * @return the work likelihood (non-Rfree based)
508    */
509   public double likelihoodWork() {
510     return llkR;
511   }
512 
513   /**
514    * Set amplitude (F).
515    *
516    * @param i reflection to set
517    * @param f value of F desired
518    */
519   public void setF(int i, double f) {
520     fSigF[i][0] = f;
521   }
522 
523   /**
524    * Set amplitude and sigF.
525    *
526    * @param i reflection to set
527    * @param f value of F desired
528    * @param sigf value of sigF desired
529    */
530   public void setFSigF(int i, double f, double sigf) {
531     fSigF[i][0] = f;
532     fSigF[i][1] = sigf;
533   }
534 
535   /**
536    * set complex Fc
537    *
538    * @param i reflection to set
539    * @param c {@link ComplexNumber} to set reflection to
540    */
541   public void setFc(int i, ComplexNumber c) {
542     fc[i][0] = c.re();
543     fc[i][1] = c.im();
544   }
545 
546   /**
547    * setFcTot
548    *
549    * @param i a int.
550    * @param c a {@link ComplexNumber} object.
551    */
552   public void setFcTot(int i, ComplexNumber c) {
553     fcTot[i][0] = c.re();
554     fcTot[i][1] = c.im();
555   }
556 
557   /**
558    * setFoFc1
559    *
560    * @param i a int.
561    * @param c a {@link ComplexNumber} object.
562    */
563   public void setFoFc1(int i, ComplexNumber c) {
564     foFc1[i][0] = c.re();
565     foFc1[i][1] = c.im();
566   }
567 
568   /**
569    * setFoFc2
570    *
571    * @param i a int.
572    * @param c a {@link ComplexNumber} object.
573    */
574   public void setFoFc2(int i, ComplexNumber c) {
575     foFc2[i][0] = c.re();
576     foFc2[i][1] = c.im();
577   }
578 
579   /**
580    * Set FreeR value flag of a reflection.
581    *
582    * @param i reflection to set
583    * @param f FreeR value to set reflection to
584    */
585   public void setFreeR(int i, int f) {
586     freeR[i] = f;
587   }
588 
589   /**
590    * Set FreeR value flag.
591    *
592    * @param i If FreeR value is i, it is marked for cross validation.
593    */
594   public void setFreeRFlag(int i) {
595     rFreeFlag = i;
596   }
597 
598   /**
599    * setFs
600    *
601    * @param i a int.
602    * @param c a {@link ComplexNumber} object.
603    */
604   public void setFs(int i, ComplexNumber c) {
605     fs[i][0] = c.re();
606     fs[i][1] = c.im();
607   }
608 
609   /**
610    * Set amplitude sigma (sigF).
611    *
612    * @param i reflection to set
613    * @param sigF value of sigF desired
614    */
615   public void setSigF(int i, double sigF) {
616     fSigF[i][1] = sigF;
617   }
618 
619   /**
620    * setCrystalReciprocalSpace_fc
621    *
622    * @param crystalReciprocalSpace a {@link ffx.xray.CrystalReciprocalSpace} object.
623    */
624   void setCrystalReciprocalSpaceFc(CrystalReciprocalSpace crystalReciprocalSpace) {
625     this.crystalReciprocalSpaceFc = crystalReciprocalSpace;
626   }
627 
628   /**
629    * setCrystalReciprocalSpace_fs
630    *
631    * @param crystalReciprocalSpace a {@link ffx.xray.CrystalReciprocalSpace} object.
632    */
633   void setCrystalReciprocalSpaceFs(CrystalReciprocalSpace crystalReciprocalSpace) {
634     this.crystalReciprocalSpaceFs = crystalReciprocalSpace;
635   }
636 
637   /**
638    * isFreeR
639    *
640    * @param i a int.
641    * @return a boolean.
642    */
643   boolean isFreeR(int i) {
644     return (freeR[i] == rFreeFlag);
645   }
646 
647   /**
648    * get the complex number for a Fc reflection
649    *
650    * @param i reflection to get
651    * @return newly allocated {@link ComplexNumber}
652    */
653   ComplexNumber getFc(int i) {
654     return new ComplexNumber(fc[i][0], fc[i][1]);
655   }
656 
657   /**
658    * get the complex number for a Fc reflection
659    *
660    * @param i reflection to get
661    * @param c {@link ComplexNumber} to fill
662    */
663   void getFcIP(int i, ComplexNumber c) {
664     c.re(fc[i][0]);
665     c.im(fc[i][1]);
666   }
667 
668   /**
669    * getFsIP
670    *
671    * @param i a int.
672    * @param c a {@link ComplexNumber} object.
673    */
674   void getFsIP(int i, ComplexNumber c) {
675     c.re(fs[i][0]);
676     c.im(fs[i][1]);
677   }
678 
679   /**
680    * getFcTotIP
681    *
682    * @param i a int.
683    * @param c a {@link ComplexNumber} object.
684    */
685   void getFcTotIP(int i, ComplexNumber c) {
686     c.re(fcTot[i][0]);
687     c.im(fcTot[i][1]);
688   }
689 }