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.commands;
39  
40  import ffx.algorithms.cli.AlgorithmsCommand;
41  import ffx.numerics.Potential;
42  import ffx.potential.MolecularAssembly;
43  import ffx.potential.cli.AtomSelectionOptions;
44  import ffx.potential.cli.TimerOptions;
45  import ffx.utilities.FFXBinding;
46  import ffx.xray.DiffractionData;
47  import ffx.xray.RefinementEnergy;
48  import ffx.xray.cli.XrayOptions;
49  import org.apache.commons.configuration2.CompositeConfiguration;
50  import picocli.CommandLine.Command;
51  import picocli.CommandLine.Mixin;
52  import picocli.CommandLine.Parameters;
53  
54  import java.util.List;
55  
56  import static java.lang.String.format;
57  
58  /**
59   * The X-ray Timer script.
60   * <br>
61   * Usage:
62   * <br>
63   * ffxc xray.Timer [options] &lt;filename&gt;
64   */
65  @Command(description = " Time calculation of the X-ray target.", name = "xray.Timer")
66  public class Timer extends AlgorithmsCommand {
67  
68    @Mixin
69    private TimerOptions timerOptions;
70  
71    @Mixin
72    private XrayOptions xrayOptions;
73  
74    @Mixin
75    AtomSelectionOptions atomSelectionOptions;
76  
77    /**
78     * One or more filenames.
79     */
80    @Parameters(arity = "1..*", paramLabel = "files", description = "PDB and Diffraction input files.")
81    private List<String> filenames;
82  
83    private DiffractionData diffractionData;
84    private MolecularAssembly[] molecularAssemblies;
85  
86    private RefinementEnergy refinementEnergy;
87  
88    /**
89     * Timer constructor.
90     */
91    public Timer() {
92      super();
93    }
94  
95    /**
96     * Timer constructor that sets the command line arguments.
97     *
98     * @param args Command line arguments.
99     */
100   public Timer(String[] args) {
101     super(args);
102   }
103 
104   /**
105    * Timer constructor.
106    *
107    * @param binding The Binding to use.
108    */
109   public Timer(FFXBinding binding) {
110     super(binding);
111   }
112 
113   /**
114    * {@inheritDoc}
115    */
116   @Override
117   public Timer run() {
118 
119     if (!init()) {
120       return this;
121     }
122 
123     xrayOptions.init();
124 
125     // Set the number of threads (needs to be done before opening the files).
126     if (timerOptions.getThreads() > 0) {
127       System.setProperty("pj.nt", Integer.toString(timerOptions.getThreads()));
128     }
129 
130     String filename;
131     if (filenames != null && !filenames.isEmpty()) {
132       // Each alternate conformer is returned in a separate MolecularAssembly.
133       molecularAssemblies = algorithmFunctions.openAll(filenames.get(0));
134       activeAssembly = molecularAssemblies[0];
135       filename = filenames.get(0);
136     } else if (activeAssembly == null) {
137       logger.info(helpString());
138       return this;
139     } else {
140       molecularAssemblies = new MolecularAssembly[]{activeAssembly};
141       filename = activeAssembly.getFile().getAbsolutePath();
142     }
143 
144     logger.info("\n Running xray.Timer on " + filename);
145 
146     // Apply active atom flags.
147     for (MolecularAssembly molecularAssembly : molecularAssemblies) {
148       atomSelectionOptions.setActiveAtoms(molecularAssembly);
149     }
150 
151     // Combine script flags (in parseResult) with properties.
152     CompositeConfiguration properties = activeAssembly.getProperties();
153     xrayOptions.setProperties(parseResult, properties);
154 
155     // Set up diffraction data (can be multiple files)
156     diffractionData = xrayOptions.getDiffractionData(filenames, molecularAssemblies, properties);
157     refinementEnergy = xrayOptions.toXrayEnergy(diffractionData);
158 
159     // Print the initial energy of each conformer.
160     algorithmFunctions.energy(molecularAssemblies);
161 
162     int n = refinementEnergy.getNumberOfVariables();
163     double[] x = new double[n];
164     double[] g = new double[n];
165     refinementEnergy.getCoordinates(x);
166     Potential energy = refinementEnergy.getDataEnergy();
167 
168     logger.info("\n Beginning Timings\n");
169 
170     int nEvals = timerOptions.getIterations();
171     boolean gradient = !timerOptions.getNoGradient();
172     long minTime = Long.MAX_VALUE;
173     double sumTime2 = 0.0;
174     int halfnEvals = (nEvals % 2 == 1) ? (nEvals / 2) : (nEvals / 2) - 1; // Halfway point
175     for (int i = 0; i < nEvals; i++) {
176       long time = -System.nanoTime();
177       double e;
178       if (gradient) {
179         e = energy.energyAndGradient(x, g);
180       } else {
181         e = energy.energy(x);
182       }
183       time += System.nanoTime();
184       if (gradient) {
185         logger.info(format(" Energy & Gradient: %12.6f in %6.3f (sec)", e, time * 1.0E-9));
186       } else {
187         logger.info(format(" Energy: %12.6f in %6.3f (sec)", e, time * 1.0E-9));
188       }
189 
190       minTime = time < minTime ? time : minTime;
191       if (i >= nEvals / 2) {
192         double time2 = time * 1.0E-9;
193         sumTime2 += (time2 * time2);
194       }
195     }
196 
197     ++halfnEvals;
198     double rmsTime = Math.sqrt(sumTime2 / halfnEvals);
199     logger.info(format("\n Minimum time:           %6.3f (sec)", minTime * 1.0E-9));
200     logger.info(format(" RMS time (latter half): %6.3f (sec)", rmsTime));
201 
202     return this;
203   }
204 
205   @Override
206   public List<Potential> getPotentials() {
207     return getPotentialsFromAssemblies(molecularAssemblies);
208   }
209 
210   @Override
211   public boolean destroyPotentials() {
212     return diffractionData == null ? true : diffractionData.destroy();
213   }
214 }