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 static java.lang.String.format;
41  import static org.junit.Assert.assertEquals;
42  import static org.junit.Assert.assertTrue;
43  
44  import edu.rit.pj.ParallelTeam;
45  import ffx.algorithms.misc.AlgorithmsTest;
46  import ffx.crystal.Crystal;
47  import ffx.crystal.ReflectionList;
48  import ffx.crystal.Resolution;
49  import ffx.potential.MolecularAssembly;
50  import ffx.potential.bonded.Atom;
51  import ffx.potential.utils.PotentialsUtils;
52  import ffx.xray.parsers.CIFFilter;
53  import ffx.xray.parsers.MTZFilter;
54  
55  import java.io.File;
56  import java.util.Arrays;
57  import java.util.Collection;
58  import java.util.List;
59  import java.util.logging.Logger;
60  
61  import org.apache.commons.configuration2.CompositeConfiguration;
62  import org.junit.Test;
63  import org.junit.runner.RunWith;
64  import org.junit.runners.Parameterized;
65  import org.junit.runners.Parameterized.Parameters;
66  
67  /**
68   * @author Timothy D. Fenn and Michael J. Schnieders
69   */
70  @RunWith(Parameterized.class)
71  public class XRayMinimizeTest extends AlgorithmsTest {
72  
73    private static final Logger logger = Logger.getLogger(XRayMinimizeTest.class.getName());
74    private final String info;
75    private final double r;
76    private final double rFree;
77    private final double sigmaA;
78    private final double sigmaW;
79    private final boolean ciOnly;
80    private DiffractionRefinementData refinementData;
81    private ReflectionList reflectionList;
82    private ParallelTeam parallelTeam;
83  
84    public XRayMinimizeTest(boolean ciOnly, String info, String pdbname, String mtzname, String cifname,
85                            double r, double rFree, double sigmaA, double sigmaW) {
86      this.ciOnly = ciOnly;
87      this.info = info;
88      this.r = r;
89      this.rFree = rFree;
90      this.sigmaA = sigmaA;
91      this.sigmaW = sigmaW;
92  
93      if (!ffxCI && ciOnly) {
94        return;
95      }
96  
97      // Load the structure
98      File structure = getResourceFile(pdbname);
99      File mtzFile = getResourceFile(mtzname);
100     File cifFile = getResourceFile(cifname);
101     PotentialsUtils potutil = new PotentialsUtils();
102     MolecularAssembly mola = potutil.open(structure);
103     CompositeConfiguration properties = mola.getProperties();
104 
105     // read in Fo/sigFo/FreeR
106     MTZFilter mtzFilter = new MTZFilter();
107     CIFFilter cifFilter = new CIFFilter();
108     Crystal crystal = Crystal.checkProperties(properties);
109     double defaultResolution = -1.0;
110     if (crystal != null) {
111       defaultResolution = mtzFilter.getResolution(mtzFile, crystal);
112     }
113     Resolution resolution = Resolution.checkProperties(properties, false, defaultResolution);
114     if (crystal == null || resolution == null) {
115       if (mtzname != null) {
116         reflectionList = mtzFilter.getReflectionList(mtzFile);
117       } else {
118         reflectionList = cifFilter.getReflectionList(cifFile);
119       }
120     } else {
121       reflectionList = new ReflectionList(crystal, resolution);
122     }
123 
124     refinementData = new DiffractionRefinementData(properties, reflectionList);
125     if (mtzname != null) {
126       assertTrue(info + " mtz file should be read in without errors",
127           mtzFilter.readFile(mtzFile, reflectionList, refinementData, properties));
128     } else {
129       assertTrue(info + " cif file should be read in without errors",
130           cifFilter.readFile(cifFile, reflectionList, refinementData, properties));
131     }
132 
133     mola.finalize(true, mola.getForceField());
134 
135     List<Atom> atomList = mola.getAtomList();
136     Atom[] atomArray = atomList.toArray(new Atom[0]);
137 
138     // Set up the CrystalReciprocalSpace
139     parallelTeam = new ParallelTeam();
140     CrystalReciprocalSpace crs =
141         new CrystalReciprocalSpace(reflectionList, atomArray, parallelTeam, parallelTeam, false);
142     crs.computeDensity(refinementData.fc);
143     refinementData.setCrystalReciprocalSpaceFc(crs);
144     crs = new CrystalReciprocalSpace(reflectionList, atomArray, parallelTeam, parallelTeam, true);
145     crs.computeDensity(refinementData.fs);
146     refinementData.setCrystalReciprocalSpaceFs(crs);
147 
148     ScaleBulkMinimize scaleBulkMinimize = new ScaleBulkMinimize(reflectionList,
149         refinementData, refinementData.crystalReciprocalSpaceFs, parallelTeam);
150     scaleBulkMinimize.minimize(6, 1.0e-4);
151 
152     SigmaAMinimize sigmaAMinimize = new SigmaAMinimize(reflectionList, refinementData, parallelTeam);
153     sigmaAMinimize.minimize(7, 2.0e-2);
154 
155     SplineMinimize splineMinimize = new SplineMinimize(reflectionList, refinementData,
156         refinementData.spline, SplineEnergy.SplineType.FOFC);
157     splineMinimize.minimize(7, 1e-5);
158   }
159 
160   @Parameters
161   public static Collection<Object[]> data() {
162     return Arrays.asList(
163         new Object[][]{
164             {
165                 false,
166                 "NSF D2 domain test",
167                 "1NSF.pdb",
168                 "1NSF.mtz",
169                 null,
170                 25.17866326312945,
171                 25.448305511010272,
172                 0.893903833644513,
173                 0.14952134994994207
174             },
175             {
176                 true,
177                 "SNARE complex",
178                 "1N7S.pdb",
179                 "1N7S.mtz",
180                 null,
181                 19.43334760963002,
182                 21.555930987392596,
183                 0.9336845537932159,
184                 0.1319269157669047
185             }
186         });
187   }
188 
189   @Test
190   public void testCrystalStats() {
191     if (!ffxCI && ciOnly) {
192       return;
193     }
194     CrystalStats crystalStats = new CrystalStats(reflectionList, refinementData);
195 
196     crystalStats.printScaleStats();
197     crystalStats.printHKLStats();
198     crystalStats.printSNStats();
199     crystalStats.printRStats();
200 
201     assertEquals(info + " R value", r, crystalStats.getR(), 0.02);
202     assertEquals(info + " Rfree value", rFree, crystalStats.getRFree(), 0.02);
203     assertEquals(info + " sigmaA s", sigmaA, crystalStats.getSigmaA(), 0.001);
204     assertEquals(info + " sigmaA w", sigmaW, crystalStats.getSigmaW(), 0.001);
205   }
206 
207   @Test
208   public void testScaleBulk() {
209     if (!ffxCI && ciOnly) {
210       return;
211     }
212     ScaleBulkMinimize scaleBulkMinimize = new ScaleBulkMinimize(
213         reflectionList, refinementData, refinementData.crystalReciprocalSpaceFs, parallelTeam);
214     ScaleBulkEnergy scaleBulkEnergy = scaleBulkMinimize.getScaleBulkEnergy();
215     int n = scaleBulkMinimize.getNumberOfVariables();
216     double[] x = new double[n];
217     double[] g = new double[n];
218     scaleBulkMinimize.getCoordinates(x);
219     scaleBulkEnergy.energyAndGradient(x, g);
220     double delta = 1.0e-4;
221     double tolerance = 1.0e-4;
222     for (int i = 0; i < n; i++) {
223       String test = format(" Scale Bulk Solvent Derivative %d.", i);
224       double orig = x[i];
225       x[i] += delta;
226       double ePlus = scaleBulkEnergy.energy(x);
227       x[i] -= 2.0 * delta;
228       double eMinus = scaleBulkEnergy.energy(x);
229       x[i] = orig;
230       double fd = (ePlus - eMinus) / (2.0 * delta);
231       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
232       assertEquals(test, g[i], fd, tolerance);
233     }
234   }
235 
236   @Test
237   public void testSigmaA() {
238     if (!ffxCI && ciOnly) {
239       return;
240     }
241     SigmaAMinimize sigmaAMinimize = new SigmaAMinimize(reflectionList, refinementData, parallelTeam);
242     SigmaAEnergy sigmaAEnergy = sigmaAMinimize.getSigmaAEnergy();
243     int n = sigmaAMinimize.getNumberOfVariables();
244     double[] x = new double[n];
245     double[] g = new double[n];
246     sigmaAMinimize.getCoordinates(x);
247     sigmaAEnergy.energyAndGradient(x, g);
248     double delta = 1.0e-4;
249     double tolerance = 1.0e-3;
250     for (int i = 0; i < n; i++) {
251       double orig = x[i];
252       x[i] += delta;
253       double ePlus = sigmaAEnergy.energy(x);
254       x[i] -= 2.0 * delta;
255       double eMinus = sigmaAEnergy.energy(x);
256       x[i] = orig;
257       double fd = (ePlus - eMinus) / (2.0 * delta);
258       String test = format(" SigmaA Derivative %d.", i);
259       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
260       assertEquals(test, 1.0, g[i] / fd, tolerance);
261     }
262   }
263 
264   @Test
265   public void testSplineFOFC() {
266     if (!ffxCI && ciOnly) {
267       return;
268     }
269     SplineMinimize splineMinimize = new SplineMinimize(reflectionList, refinementData,
270         refinementData.spline, SplineEnergy.SplineType.FOFC);
271     SplineEnergy splineEnergy = splineMinimize.getSplineEnergy();
272     int n = splineMinimize.getNumberOfVariables();
273     double[] x = new double[n];
274     double[] g = new double[n];
275     splineMinimize.getCoordinates(x);
276     splineEnergy.energyAndGradient(x, g);
277     double delta = 1.0e-4;
278     double tolerance = 1.0e-4;
279     for (int i = 0; i < n; i++) {
280       double orig = x[i];
281       x[i] += delta;
282       double ePlus = splineEnergy.energy(x);
283       x[i] -= 2.0 * delta;
284       double eMinus = splineEnergy.energy(x);
285       x[i] = orig;
286       double fd = (ePlus - eMinus) / (2.0 * delta);
287       String test = format(" FOFC Spline Derivative %d.", i);
288       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
289       assertEquals(test, 1.0, g[i] / fd, tolerance);
290     }
291   }
292 
293   @Test
294   public void testSplineF1F2() {
295     if (!ffxCI && ciOnly) {
296       return;
297     }
298     SplineMinimize splineMinimize = new SplineMinimize(
299         reflectionList, refinementData, refinementData.spline, SplineEnergy.SplineType.F1F2);
300     SplineEnergy splineEnergy = splineMinimize.getSplineEnergy();
301     int n = splineMinimize.getNumberOfVariables();
302     double[] x = new double[n];
303     double[] g = new double[n];
304     splineMinimize.getCoordinates(x);
305     splineEnergy.energyAndGradient(x, g);
306     double delta = 1.0e-4;
307     double tolerance = 1.0e-4;
308     for (int i = 0; i < n; i++) {
309       double orig = x[i];
310       x[i] += delta;
311       double ePlus = splineEnergy.energy(x);
312       x[i] -= 2.0 * delta;
313       double eMinus = splineEnergy.energy(x);
314       x[i] = orig;
315       double fd = (ePlus - eMinus) / (2.0 * delta);
316       String test = format(" F1F2 Spline Derivative %d.", i);
317       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
318       assertEquals(test, 1.0, g[i] / fd, tolerance);
319     }
320   }
321 
322   @Test
323   public void testSplineFCTOESQ() {
324     if (!ffxCI && ciOnly) {
325       return;
326     }
327     SplineMinimize splineMinimize = new SplineMinimize(
328         reflectionList, refinementData, refinementData.spline, SplineEnergy.SplineType.FCTOESQ);
329     SplineEnergy splineEnergy = splineMinimize.getSplineEnergy();
330     int n = splineMinimize.getNumberOfVariables();
331     double[] x = new double[n];
332     double[] g = new double[n];
333     splineMinimize.getCoordinates(x);
334     splineEnergy.energyAndGradient(x, g);
335     double delta = 1.0e-4;
336     double tolerance = 1.0e-4;
337     for (int i = 0; i < n; i++) {
338       double orig = x[i];
339       x[i] += delta;
340       double ePlus = splineEnergy.energy(x);
341       x[i] -= 2.0 * delta;
342       double eMinus = splineEnergy.energy(x);
343       x[i] = orig;
344       double fd = (ePlus - eMinus) / (2.0 * delta);
345       String test = format(" FCTOESQ Spline Derivative %d.", i);
346       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
347       assertEquals(test, 1.0, g[i] / fd, tolerance);
348     }
349   }
350 
351   @Test
352   public void testSplineFOTOESQ() {
353     if (!ffxCI && ciOnly) {
354       return;
355     }
356     SplineMinimize splineMinimize = new SplineMinimize(
357         reflectionList, refinementData, refinementData.spline, SplineEnergy.SplineType.FOTOESQ);
358     SplineEnergy splineEnergy = splineMinimize.getSplineEnergy();
359     int n = splineMinimize.getNumberOfVariables();
360     double[] x = new double[n];
361     double[] g = new double[n];
362     splineMinimize.getCoordinates(x);
363     splineEnergy.energyAndGradient(x, g);
364     double delta = 1.0e-4;
365     double tolerance = 1.0e-4;
366     for (int i = 0; i < n; i++) {
367       double orig = x[i];
368       x[i] += delta;
369       double ePlus = splineEnergy.energy(x);
370       x[i] -= 2.0 * delta;
371       double eMinus = splineEnergy.energy(x);
372       x[i] = orig;
373       double fd = (ePlus - eMinus) / (2.0 * delta);
374       String test = format(" FOTOESQ Spline Derivative %d.", i);
375       logger.info(format(" %s A %16.8f vs. FD %16.8f", test, g[i], fd));
376       assertEquals(test, 1.0, g[i] / fd, tolerance);
377     }
378   }
379 }