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.potential.parsers;
39  
40  import java.io.BufferedReader;
41  import java.io.BufferedWriter;
42  import java.io.File;
43  import java.io.FileReader;
44  import java.io.FileWriter;
45  import java.io.IOException;
46  import java.util.ArrayList;
47  import java.util.logging.Logger;
48  
49  import static ffx.potential.parsers.SystemFilter.version;
50  import static java.lang.Double.isNaN;
51  import static java.lang.Double.parseDouble;
52  import static java.lang.Integer.parseInt;
53  import static java.lang.String.format;
54  
55  /**
56   * The BARFilter class parses TINKER bar(*.BAR) files.
57   *
58   * @author Rose A. Gogal
59   * @since 1.0
60   */
61  
62  public class BARFilter {
63  
64    private static final Logger logger = Logger.getLogger(XYZFilter.class.getName());
65    private final File barFile;
66  
67    private int snaps1;
68    private double temperature1;
69    private double[] e1l1;
70    private double[] e1l2;
71    private double[] volume1;
72  
73    private int snaps2;
74    private double temperature2;
75    private double[] e2l1;
76    private double[] e2l2;
77    private double[] volume2;
78  
79    private int startingSnap = 0;
80    private int endingSnap = 0;
81    private int count = 0;
82  
83  
84    /**
85     * BARFilter constructor
86     *
87     * @param barFile a {@link java.util.List} object.
88     */
89    public BARFilter(File barFile) {
90      this.barFile = barFile;
91    }
92  
93    /**
94     * BARFilter constructor
95     *
96     * @param barFile      a {@link java.util.List} object.
97     * @param startingSnap a {@link java.util.List} object.
98     * @param endingSnap   a {@link java.util.List} object.
99     */
100   public BARFilter(File barFile, int startingSnap, int endingSnap) {
101     this.barFile = barFile;
102     this.startingSnap = startingSnap;
103     this.endingSnap = endingSnap;
104   }
105 
106   /**
107    * BARFilter constructor
108    *
109    * @param xyzFile      a {@link java.util.List} object.
110    * @param e1l1         energy in ensemble 1 at lambda 1
111    * @param e1l2         energy in ensemble 1 at lambda 2
112    * @param e2l1         energy in ensemble 2 at lambda 1
113    * @param e2l2         energy in ensemble 2 at lambda 2
114    * @param volume1      volume in ensemble 1
115    * @param volume2      volume in ensemble 2
116    * @param temperature1 temperature of ensemble 1
117    * @param temperature2 temperature of ensemble 2
118    */
119   public BARFilter(File xyzFile, double[] e1l1, double[] e1l2, double[] e2l1, double[] e2l2,
120                    double[] volume1, double[] volume2, double temperature1, double temperature2) {
121     this.barFile = xyzFile;
122 
123     this.temperature1 = temperature1;
124     this.e1l1 = e1l1;
125     this.e1l2 = e1l2;
126     this.volume1 = volume1;
127 
128     this.e2l1 = e2l1;
129     this.e2l2 = e2l2;
130     this.volume2 = volume2;
131     this.temperature2 = temperature2;
132   }
133 
134 
135   /**
136    * Read TINKER bar files and parse the snapshots into energy arrays
137    *
138    * @return True if the file was read successfully.
139    */
140   public boolean readFile() {
141     ArrayList<Double> ens1lam1 = new ArrayList<>();
142     ArrayList<Double> ens1lam2 = new ArrayList<>();
143     ArrayList<Double> ens2lam1 = new ArrayList<>();
144     ArrayList<Double> ens2lam2 = new ArrayList<>();
145     ArrayList<Double> vol1 = new ArrayList<>();
146     ArrayList<Double> vol2 = new ArrayList<>();
147     // Processes all snapshots in a file.
148     int snapshots = 0;
149     int xyzCount = 0;
150     try (BufferedReader br = new BufferedReader(new FileReader(barFile))) {
151       String data;
152       while ((data = br.readLine()) != null) {
153         String[] tokens = data.trim().split(" +");
154         int numTokens = tokens.length;
155         if (data.contains(".xyz") || data.contains(".pdb") || numTokens < 3) {
156           xyzCount++;
157           if (xyzCount == 1) {
158             snaps1 = parseInt(tokens[0]);
159             temperature1 = parseDouble(tokens[1]);
160           } else if (xyzCount == 2) {
161             snaps2 = parseInt(tokens[0]);
162             temperature2 = parseDouble(tokens[1]);
163           }
164         } else if (endingSnap != 0) {
165           count++;
166           snapshots = (endingSnap - startingSnap) + 1;
167           if (count >= startingSnap + 1 && count <= endingSnap + 1) {
168             if (count <= snaps1) {
169               if (numTokens == 4) {
170                 vol1.add(parseDouble(tokens[3]));
171               }
172               ens1lam1.add(parseDouble(tokens[1]));
173               ens1lam2.add(parseDouble(tokens[2]));
174             } else {
175               logger.warning(format(" BAR entry of (%3d) is larger than total entries (%3d).", count, snaps1));
176             }
177           } else if (count >= snaps1 + startingSnap + 1 && count <= snaps1 + endingSnap + 1) {
178             if (count <= snaps1 + snaps2 + 1) {
179               if (numTokens == 4) {
180                 vol2.add(parseDouble(tokens[3]));
181               }
182               ens2lam1.add(parseDouble(tokens[1]));
183               ens2lam2.add(parseDouble(tokens[2]));
184             } else {
185               logger.warning(format(" BAR entry of (%3d) is larger than total entries (%3d).", count, snaps1 + snaps2));
186             }
187           }
188         } else {
189           count++;
190           if (count <= snaps1) {
191             if (numTokens == 4) {
192               vol1.add(parseDouble(tokens[3]));
193             }
194             ens1lam1.add(parseDouble(tokens[1]));
195             ens1lam2.add(parseDouble(tokens[2]));
196           } else {
197             if (numTokens == 4) {
198               vol2.add(parseDouble(tokens[3]));
199             }
200             ens2lam1.add(parseDouble(tokens[1]));
201             ens2lam2.add(parseDouble(tokens[2]));
202           }
203         }
204       }
205       if (snapshots != 0) {
206         e1l1 = new double[snapshots];
207         e1l2 = new double[snapshots];
208         e2l1 = new double[snapshots];
209         e2l2 = new double[snapshots];
210         volume1 = new double[snapshots];
211         volume2 = new double[snapshots];
212         snaps1 = snapshots;
213       } else {
214         e1l1 = new double[snaps1];
215         e1l2 = new double[snaps1];
216         e2l1 = new double[snaps2];
217         e2l2 = new double[snaps2];
218         volume1 = new double[snaps1];
219         volume2 = new double[snaps2];
220       }
221       for (int i = 0; i < ens1lam1.size(); i++) {
222         e1l1[i] = ens1lam1.get(i);
223         e1l2[i] = ens1lam2.get(i);
224         if (!vol1.isEmpty()) {
225           volume1[i] = vol1.get(i);
226         }
227       }
228       for (int i = 0; i < ens2lam1.size(); i++) {
229         e2l1[i] = ens2lam1.get(i);
230         e2l2[i] = ens2lam2.get(i);
231         if (!vol1.isEmpty()) {
232           volume2[i] = vol2.get(i);
233         }
234       }
235       // Read blank lines at the top of the file
236       if (data == null) {
237         return false;
238       }
239     } catch (IOException fileNotFoundException) {
240       logger.warning(format(" Exception reading %s:\n %s", barFile, fileNotFoundException));
241     }
242     return true;
243   }
244 
245   /**
246    * Write TINKER bar files
247    *
248    * @param saveFile The file to write to.
249    * @param isPBC    include volume in the output file.
250    * @return True if successful.
251    */
252   public boolean writeFile(String saveFile, boolean isPBC) {
253     return writeFile(saveFile, isPBC, true);
254   }
255 
256   /**
257    * Write TINKER bar files
258    *
259    * @param saveFile The file to write to.
260    * @param isPBC    include volume in the output file.
261    * @param append   If the append flag is true, "saveFile" will be appended to. Otherwise, the default versioning scheme will be applied.
262    * @return True if successful.
263    */
264   public boolean writeFile(String saveFile, boolean isPBC, boolean append) {
265     int snaps = e1l1.length;
266     int snaps2 = e2l1.length;
267     String name = barFile.getName();
268 
269     File newFile = new File(saveFile);
270     if (!append) {
271       newFile = version(newFile);
272     }
273 
274     logger.info(format(" Writing BAR file: %s", newFile));
275     try (FileWriter fw = new FileWriter(newFile,
276         append && newFile.exists()); BufferedWriter bw = new BufferedWriter(fw)) {
277       bw.write(format("%8d %9.3f %s\n", snaps, temperature1, name));
278       for (int i = 0; i < snaps; i++) {
279         if (isNaN(e1l1[i]) || isNaN(e1l2[i])) {
280           continue;
281         }
282         if (isPBC) {
283           bw.write(format("%8d %20.10f %20.10f %20.10f\n", i + 1, e1l1[i], e1l2[i], volume2[i]));
284         } else {
285           bw.write(format("%8d %20.10f %20.10f\n", i + 1, e1l1[i], e1l2[i]));
286         }
287       }
288 
289       bw.write(format("%8d %9.3f  %s\n", snaps2, temperature1, name));
290       for (int i = 0; i < snaps2; i++) {
291         if (isNaN(e2l1[i]) || isNaN(e2l2[i])) {
292           continue;
293         }
294         if (isPBC) {
295           bw.write(format("%8d %20.10f %20.10f %20.10f\n", i + 1, e2l1[i], e2l2[i], volume2[i]));
296         } else {
297           bw.write(format("%8d %20.10f %20.10f\n", i + 1, e2l1[i], e2l2[i]));
298         }
299       }
300     } catch (IOException e) {
301       logger.warning(format(" Exception writing %s", newFile));
302       return false;
303     }
304     return true;
305   }
306 
307   /**
308    * Returns the temperature for ensemble 1.
309    *
310    * @return The temperature.
311    */
312   public double getTemperature1() {
313     return temperature1;
314   }
315 
316   /**
317    * Returns the temperature for ensemble 2.
318    *
319    * @return The temperature.
320    */
321   public double getTemperature2() {
322     return temperature2;
323   }
324 
325   /**
326    * Return the potential energy for each snapshot of ensemble 1 at lambda 1.
327    *
328    * @return The potential energy for each snapshot of ensemble 1 at lambda 1.
329    */
330   public double[] getE1l1() {
331     return e1l1;
332   }
333 
334   /**
335    * Return the potential energy for each snapshot of ensemble 1 at lambda 2.
336    *
337    * @return The potential energy for each snapshot of ensemble 1 at lambda 2.
338    */
339   public double[] getE1l2() {
340     return e1l2;
341   }
342 
343   /**
344    * Return the potential energy for each snapshot of ensemble 2 at lambda 1.
345    *
346    * @return The potential energy for each snapshot of ensemble 2 at lambda 1.
347    */
348   public double[] getE2l1() {
349     return e2l1;
350   }
351 
352   /**
353    * Return the potential energy for each snapshot of ensemble 2 at lambda 2.
354    *
355    * @return The potential energy for each snapshot of ensemble 2 at lambda 2.
356    */
357   public double[] getE2l2() {
358     return e2l2;
359   }
360 
361   /**
362    * Return the volume for each snapshot of ensemble 1.
363    *
364    * @return The volume for each snapshot of ensemble 1.
365    */
366   public double[] getVolume1() {
367     return volume1;
368   }
369 
370   /**
371    * Return the volume for each snapshot of ensemble 2.
372    *
373    * @return The volume for each snapshot of ensemble 2.
374    */
375   public double[] getVolume2() {
376     return volume2;
377   }
378 
379   /**
380    * Return the number of snapshots in the BAR file.
381    *
382    * @return The number of snapshots in the BAR file.
383    */
384   public int getNumberOfSnapshots() {
385     return snaps1;
386   }
387 
388   /**
389    * Return the number of snapshots in the BAR file.
390    *
391    * @return The number of snapshots in the BAR file.
392    */
393   public File getFile() {
394     return barFile;
395   }
396 }