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 ffx.crystal.Crystal;
41  
42  import java.io.BufferedReader;
43  import java.io.BufferedWriter;
44  import java.io.File;
45  import java.io.FileReader;
46  import java.io.FileWriter;
47  import java.io.IOException;
48  import java.util.logging.Level;
49  import java.util.logging.Logger;
50  
51  import static java.lang.Double.parseDouble;
52  import static java.lang.String.format;
53  
54  /**
55   * The DYNFilter class parses TINKER Restart (*.DYN) files.
56   *
57   * @author Michael J. Schnieders
58   * @since 1.0
59   */
60  public class DYNFilter {
61  
62    private static final Logger logger = Logger.getLogger(DYNFilter.class.getName());
63    private final String label;
64  
65    /**
66     * Constructor for DYNFilter.
67     *
68     * @param label a Label for the restart file.
69     */
70    public DYNFilter(String label) {
71      this.label = label;
72    }
73  
74    /**
75     * readDYN
76     *
77     * @param dynFile a {@link java.io.File} object.
78     * @param crystal a {@link ffx.crystal.Crystal} object.
79     * @param x an array of double.
80     * @param v an array of double.
81     * @param a an array of double.
82     * @param ap an array of double.
83     * @return a boolean.
84     */
85    public boolean readDYN(File dynFile, Crystal crystal, double[] x, double[] v, double[] a,
86        double[] ap) {
87      if (!dynFile.exists() || !dynFile.canRead()) {
88        return false;
89      }
90      try (BufferedReader br = new BufferedReader(new FileReader(dynFile))) {
91  
92        br.readLine();
93        String data = br.readLine().trim();
94        String[] tokens = data.split(" +");
95        if (tokens.length == 0) {
96          return false;
97        }
98        int numAtoms = Integer.parseInt(tokens[0]);
99  
100       // Box size and angles
101       br.readLine();
102       data = br.readLine().trim();
103       tokens = data.split(" +");
104       if (tokens.length != 3) {
105         return false;
106       }
107       double aAxis = parseDouble(tokens[0]);
108       double bAxis = parseDouble(tokens[1]);
109       double cAxis = parseDouble(tokens[2]);
110 
111       data = br.readLine().trim();
112       tokens = data.split(" +");
113       if (tokens.length != 3) {
114         return false;
115       }
116       double alpha = parseDouble(tokens[0]);
117       double beta = parseDouble(tokens[1]);
118       double gamma = parseDouble(tokens[2]);
119 
120       crystal.changeUnitCellParameters(aAxis, bAxis, cAxis, alpha, beta, gamma);
121 
122       // Atomic coordinates
123       br.readLine();
124       for (int i = 0; i < numAtoms; i++) {
125         data = br.readLine().trim();
126         tokens = data.split(" +");
127         if (tokens.length != 3) {
128           return false;
129         }
130         int j = i * 3;
131         x[j] = parseDouble(tokens[0]);
132         x[j + 1] = parseDouble(tokens[1]);
133         x[j + 2] = parseDouble(tokens[2]);
134       }
135 
136       // Velocities
137       br.readLine();
138       for (int i = 0; i < numAtoms; i++) {
139         data = br.readLine().trim();
140         tokens = data.split(" +");
141         if (tokens.length != 3) {
142           return false;
143         }
144         int j = i * 3;
145         v[j] = parseDouble(tokens[0]);
146         v[j + 1] = parseDouble(tokens[1]);
147         v[j + 2] = parseDouble(tokens[2]);
148       }
149 
150       // Accelerations
151       br.readLine();
152       for (int i = 0; i < numAtoms; i++) {
153         data = br.readLine().trim();
154         tokens = data.split(" +");
155         if (tokens.length != 3) {
156           return false;
157         }
158         int j = i * 3;
159         a[j] = parseDouble(tokens[0]);
160         a[j + 1] = parseDouble(tokens[1]);
161         a[j + 2] = parseDouble(tokens[2]);
162       }
163 
164       // Previous Accelerations
165       br.readLine();
166       for (int i = 0; i < numAtoms; i++) {
167         data = br.readLine().trim();
168         tokens = data.split(" +");
169         if (tokens.length != 3) {
170           return false;
171         }
172         int j = i * 3;
173         ap[j] = parseDouble(tokens[0]);
174         ap[j + 1] = parseDouble(tokens[1]);
175         ap[j + 2] = parseDouble(tokens[2]);
176       }
177     } catch (Exception e) {
178       String message = "Exception reading dynamic restart file: " + dynFile;
179       logger.log(Level.WARNING, message, e);
180     }
181     return true;
182   }
183 
184   /**
185    * writeDYN
186    *
187    * @param dynFile The file to write.
188    * @param x The atomic coordinates.
189    * @param v The atomic velocities.
190    * @param a The atomic accelerations.
191    * @param ap The atomic previous accelerations.
192    * @param crystal The crystal unit cell.
193    * @return Returns true if the file was written successfully.
194    */
195   public boolean writeDYN(File dynFile, Crystal crystal, double[] x, double[] v, double[] a,
196       double[] ap) {
197     try (FileWriter fw = new FileWriter(dynFile); BufferedWriter bw = new BufferedWriter(fw)) {
198       bw.write(" Number of Atoms and Title :\n");
199       assert (x.length % 3 == 0);
200       int numberOfAtoms = x.length / 3;
201       String output = format("%7d  %s\n", numberOfAtoms, label);
202       bw.write(output);
203       bw.write(" Periodic Box Dimensions :\n");
204       Crystal unitCell = crystal.getUnitCell();
205       bw.write(format("%26.16E%26.16E%26.16E\n", unitCell.a, unitCell.b, unitCell.c));
206       bw.write(format("%26.16E%26.16E%26.16E\n", unitCell.alpha, unitCell.beta, unitCell.gamma));
207       bw.write(" Current Atomic Positions :\n");
208       for (int i = 0; i < numberOfAtoms; i++) {
209         int k = i * 3;
210         bw.write(format("%26.16E%26.16E%26.16E\n", x[k], x[k + 1], x[k + 2]));
211       }
212       bw.write(" Current Atomic Velocities :\n");
213       for (int i = 0; i < numberOfAtoms; i++) {
214         int k = i * 3;
215         bw.write(format("%26.16E%26.16E%26.16E\n", v[k], v[k + 1], v[k + 2]));
216       }
217       bw.write(" Current Atomic Accelerations :\n");
218       for (int i = 0; i < numberOfAtoms; i++) {
219         int k = i * 3;
220         bw.write(format("%26.16E%26.16E%26.16E\n", a[k], a[k + 1], a[k + 2]));
221       }
222       bw.write(" Previous Atomic Accelerations :\n");
223       for (int i = 0; i < numberOfAtoms; i++) {
224         int k = i * 3;
225         bw.write(format("%26.16E%26.16E%26.16E\n", ap[k], ap[k + 1], ap[k + 2]));
226       }
227     } catch (IOException e) {
228       String message = " Exception writing dynamic restart file " + dynFile;
229       logger.log(Level.SEVERE, message, e);
230       return false;
231     }
232     return true;
233   }
234 }