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.potential.MolecularAssembly;
41  import ffx.potential.Utilities.FileType;
42  import ffx.potential.bonded.Atom;
43  import ffx.potential.bonded.Bond;
44  import ffx.potential.parameters.AtomType;
45  import ffx.potential.parameters.BondType;
46  import ffx.potential.parameters.ForceField;
47  import org.apache.commons.configuration2.CompositeConfiguration;
48  
49  import java.io.BufferedReader;
50  import java.io.File;
51  import java.io.FileReader;
52  import java.io.IOException;
53  import java.util.ArrayList;
54  import java.util.List;
55  import java.util.Vector;
56  import java.util.logging.Logger;
57  
58  import static ffx.potential.bonded.Bond.logNoBondType;
59  import static ffx.potential.bonded.BondedUtils.intxyz;
60  import static java.lang.Double.parseDouble;
61  import static java.lang.Integer.parseInt;
62  
63  /**
64   * The INTFilter class parses TINKER internal coordinate (*.INT) files.
65   *
66   * @author Michael J. Schnieders
67   * @since 1.0
68   */
69  public class INTFilter extends SystemFilter {
70  
71    private static final Logger logger = Logger.getLogger(INTFilter.class.getName());
72  
73    /**
74     * Constructor for INTFilter.
75     *
76     * @param files a {@link java.util.List} object.
77     * @param molecularAssembly a {@link ffx.potential.MolecularAssembly} object.
78     * @param forceField a {@link ffx.potential.parameters.ForceField} object.
79     * @param properties a {@link org.apache.commons.configuration2.CompositeConfiguration}
80     *     object.
81     */
82    public INTFilter(List<File> files, MolecularAssembly molecularAssembly, ForceField forceField,
83        CompositeConfiguration properties) {
84      super(files, molecularAssembly, forceField, properties);
85      fileType = FileType.INT;
86    }
87  
88    /**
89     * Constructor for INTFilter.
90     *
91     * @param file a {@link java.io.File} object.
92     * @param molecularAssembly a {@link ffx.potential.MolecularAssembly} object.
93     * @param forceField a {@link ffx.potential.parameters.ForceField} object.
94     * @param properties a {@link org.apache.commons.configuration2.CompositeConfiguration}
95     *     object.
96     */
97    public INTFilter(File file, MolecularAssembly molecularAssembly, ForceField forceField,
98        CompositeConfiguration properties) {
99      super(file, molecularAssembly, forceField, properties);
100     fileType = FileType.INT;
101   }
102 
103   /** {@inheritDoc} */
104   @Override
105   public void closeReader() {
106     logger.fine(" Reading trajectories not yet supported for INTFilter");
107   }
108 
109   /**
110    * {@inheritDoc}
111    *
112    * <p>Parse the INT File.
113    *
114    * @since 1.0
115    */
116   @Override
117   public boolean readFile() {
118     File intFile = activeMolecularAssembly.getFile();
119     if (forceField == null) {
120       logger.warning("No force field is associated with " + intFile.toString());
121       return false;
122     }
123 
124     logger.info(" Opening " + intFile.toString());
125 
126     // Open a data stream to the Internal Coordinate file
127     try (BufferedReader br = new BufferedReader(new FileReader(intFile))) {
128 
129       String data = br.readLine().trim();
130       // Read blank lines at the top of the file
131       while (data.isEmpty()) {
132         data = br.readLine().trim();
133       }
134       int numberOfAtoms;
135       String[] tokens = data.trim().split(" +");
136       try {
137         numberOfAtoms = parseInt(tokens[0]);
138         if (numberOfAtoms < 1) {
139           logger.warning("Invalid number of atoms: " + numberOfAtoms);
140           return false;
141         }
142       } catch (Exception e) {
143         logger.severe("Error parsing the number of atoms.\n" + e);
144         return false;
145       }
146       if (tokens.length >= 2) {
147         tokens = data.trim().split(" +", 2);
148         activeMolecularAssembly.setName(tokens[1]);
149       }
150       logger.info("  Opening " + intFile.getName() + " with " + numberOfAtoms + " atoms");
151       double[] d = {0.0d, 0.0d, 0.0d};
152       int[][] zi = new int[numberOfAtoms][4];
153       double[][] zv = new double[numberOfAtoms][3];
154       Vector<int[]> zadd = new Vector<>();
155       Vector<int[]> zdel = new Vector<>();
156       atomList = new ArrayList<>();
157       for (int i = 0; i < numberOfAtoms; i++) {
158         // Atom Data
159         if (!br.ready()) {
160           return false;
161         }
162         data = br.readLine();
163         if (data == null) {
164           logger.severe(
165               "  Check atom " + (i + 1) + " in " + activeMolecularAssembly.getFile().getName());
166           return false;
167         }
168         tokens = data.trim().split(" +");
169         if (tokens.length < 3) {
170           logger.severe(
171               "  Check atom " + (i + 1) + " in " + activeMolecularAssembly.getFile().getName());
172           return false;
173         }
174         // Atom number, name, type
175         String name = tokens[1];
176         int type = parseInt(tokens[2]);
177         AtomType atomType = forceField.getAtomType(Integer.toString(type));
178         if (atomType == null) {
179           StringBuilder message = new StringBuilder("Check atom type ");
180           message.append(type).append(" for Atom ").append(i + 1);
181           message.append(" in ").append(activeMolecularAssembly.getFile().getName());
182           logger.warning(message.toString());
183           return false;
184         }
185         Atom atom = new Atom(i + 1, name, atomType, d);
186         atomList.add(atom);
187         // Bond partner and bond value
188         if (tokens.length >= 5) {
189           zi[i][0] = parseInt(tokens[3]);
190           zv[i][0] = parseDouble(tokens[4]);
191         } else {
192           zi[i][0] = 0;
193           zv[i][0] = 0.0d;
194         }
195         // Angle partner and angle value
196         if (tokens.length >= 7) {
197           zi[i][1] = parseInt(tokens[5]);
198           zv[i][1] = parseDouble(tokens[6]);
199         } else {
200           zi[i][1] = 0;
201           zv[i][1] = 0.0d;
202         }
203         // Torsion partner and dihedral value
204         if (tokens.length >= 10) {
205           zi[i][2] = parseInt(tokens[7]);
206           zv[i][2] = parseDouble(tokens[8]);
207           zi[i][3] = parseInt(tokens[9]);
208         } else {
209           zi[i][2] = 0;
210           zv[i][2] = 0.0d;
211           zi[i][3] = 0;
212         }
213       }
214       if (br.ready()) {
215         data = br.readLine();
216         // Check for a first blank line
217         if (data.trim().equalsIgnoreCase("")) {
218           // Parse bond pairs to add until EOF or a blank line is reached
219           boolean blank = false;
220           while (br.ready() && !blank) {
221             data = br.readLine();
222             if (data.trim().equalsIgnoreCase("")) {
223               blank = true;
224             } else {
225               tokens = data.trim().split(" +");
226               if (tokens.length != 2) {
227                 logger.severe("  Check Additional Bond Pair: " + (zadd.size() + 1) + " in "
228                     + activeMolecularAssembly.getFile().getName());
229                 return false;
230               }
231               int[] pair = new int[2];
232               pair[0] = parseInt(tokens[0]);
233               pair[1] = parseInt(tokens[1]);
234               zadd.add(pair);
235             }
236           }
237           // Parse bond pairs to be removed until EOF
238           while (br.ready()) {
239             data = br.readLine();
240             tokens = data.trim().split(" +");
241             if (tokens.length != 2) {
242               logger.severe("  Check Bond Pair to Remove: " + (zadd.size() + 1) + " in "
243                   + activeMolecularAssembly.getFile().getName());
244               return false;
245             }
246             int[] pair = new int[2];
247             pair[0] = parseInt(tokens[0]);
248             pair[1] = parseInt(tokens[1]);
249             zdel.add(pair);
250           }
251         }
252       }
253       if (atomList.size() == numberOfAtoms) {
254         // Add bonds specified in the Z-matrix
255         bondList = new ArrayList<>();
256         for (int i = 1; i < numberOfAtoms; i++) {
257           int partner = zi[i][0];
258           boolean del = false;
259           for (int[] pair : zdel) {
260             if (pair[0] == i + 1 && pair[1] == partner) {
261               del = true;
262             }
263             if (pair[1] == i + 1 && pair[0] == partner) {
264               del = true;
265             }
266           }
267           if (!del) {
268             Atom atom1 = atomList.get(i);
269             Atom atom2 = atomList.get(partner - 1);
270             Bond bond = new Bond(atom1, atom2);
271             BondType bondType = forceField.getBondType(atom1.getAtomType(), atom2.getAtomType());
272             if (bondType == null) {
273               logNoBondType(atom1, atom2, forceField);
274             } else {
275               bond.setBondType(bondType);
276             }
277             bondList.add(bond);
278           }
279         }
280         // Add additional bonds
281         for (int[] pair : zadd) {
282           Atom atom1 = atomList.get(pair[0] - 1);
283           Atom atom2 = atomList.get(pair[1] - 1);
284           Bond bond = new Bond(atom1, atom2);
285           BondType bondType = forceField.getBondType(atom1.getAtomType(), atom2.getAtomType());
286           if (bondType == null) {
287             logNoBondType(atom1, atom2, forceField);
288           } else {
289             bond.setBondType(bondType);
290           }
291           bondList.add(bond);
292         }
293         // Determine coordinates from Z-matrix values
294         for (int i = 0; i < numberOfAtoms; i++) {
295           Atom atom = atomList.get(i);
296           Atom ia = null;
297           Atom ib = null;
298           Atom ic = null;
299           int[] atoms = zi[i];
300           if (atoms[0] > 0) {
301             ia = atomList.get(atoms[0] - 1);
302           }
303           if (atoms[1] > 0) {
304             ib = atomList.get(atoms[1] - 1);
305           }
306           if (atoms[2] > 0) {
307             ic = atomList.get(atoms[2] - 1);
308           }
309           double bond = zv[i][0];
310           double angle1 = zv[i][1];
311           double angle2 = zv[i][2];
312           int chiral = atoms[3];
313           intxyz(atom, ia, bond, ib, angle1, ic, angle2, chiral);
314         }
315         return true;
316       }
317       logger.warning("\n Reported number of Atoms: " + numberOfAtoms + "\n Number of Atoms Found: "
318           + atomList.size());
319     } catch (IOException e) {
320       logger.severe(e.toString());
321     }
322     return false;
323   }
324 
325   /** {@inheritDoc} */
326   @Override
327   public boolean readNext(boolean resetPosition) {
328     return false;
329   }
330 
331   /** {@inheritDoc} */
332   @Override
333   public boolean readNext(boolean resetPosition, boolean print) {
334     return false;
335   }
336 
337   /** {@inheritDoc} */
338   @Override
339   public boolean readNext(boolean resetPosition, boolean print, boolean parse) {
340     return false;
341   }
342 
343   /** {@inheritDoc} */
344   @Override
345   public boolean readNext() {
346     return readNext(false);
347   }
348 
349   /** {@inheritDoc} */
350   @Override
351   public boolean writeFile(File saveFile, boolean append, String[] extraLines) {
352     return false;
353   }
354 }