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-2024.
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 static java.lang.Integer.parseInt;
41  
42  import ffx.utilities.Keyword;
43  import java.io.BufferedReader;
44  import java.io.File;
45  import java.io.FileReader;
46  import java.io.IOException;
47  import java.util.Hashtable;
48  import java.util.logging.Level;
49  import java.util.logging.Logger;
50  
51  /**
52   * The KeyFilter class parses Force Field X Keyword (*.KEY) and Property (*.PROPERTIES) files.
53   *
54   * @author Michael J. Schnieders
55   * @since 1.0
56   */
57  public class KeyFilter {
58  
59    private static final Logger logger = Logger.getLogger(KeyFilter.class.getName());
60  
61    /** Constructor for KeyFilter. */
62    public KeyFilter() {
63    }
64  
65    /**
66     * open
67     *
68     * @param keyFile a {@link java.io.File} object.
69     * @return a {@link java.util.Hashtable} object.
70     */
71    public static Hashtable<String, Keyword> open(File keyFile) {
72      if (keyFile == null || !keyFile.exists() || !keyFile.canRead()) {
73        return null;
74      }
75      Hashtable<String, Keyword> keywordHash = loadSystemKeywords();
76      return open(keyFile, keywordHash);
77    }
78  
79    /**
80     * open
81     *
82     * @param keyFile a {@link java.io.File} object.
83     * @param keywordHash a {@link java.util.Hashtable} object.
84     * @return a {@link java.util.Hashtable} object.
85     */
86    public static Hashtable<String, Keyword> open(
87        File keyFile, Hashtable<String, Keyword> keywordHash) {
88      if (keyFile == null || !keyFile.exists() || !keyFile.canRead()) {
89        return null;
90      }
91      if (keywordHash == null) {
92        keywordHash = new Hashtable<>();
93      }
94      try (BufferedReader br = new BufferedReader(new FileReader(keyFile))) {
95        Keyword comments = new Keyword("COMMENTS");
96        keywordHash.put("COMMENTS", comments);
97        while (br.ready()) {
98          String s = br.readLine();
99          if (s == null) {
100           continue;
101         }
102         s = s.trim();
103         if (s.isEmpty()) {
104           continue; // Skip blank lines
105         }
106         // Store comments together
107         if (s.startsWith("#") || s.toUpperCase().startsWith("ECHO")) {
108           comments.append(s);
109         } else {
110           int firstSpace = s.indexOf(" ");
111           String keyword, data;
112           if (firstSpace == -1) { // no parameters
113             keyword = s.trim().toUpperCase();
114             // Rattle is special case, because it can be active
115             // without being checked
116             // Valid Key files can have: RATTLE
117             // or RATTLE BONDS
118             // or RATTLE & RATTLE BONDS as separate lines
119             // Each of these valid cases mean different things...
120             if (keyword.equalsIgnoreCase("rattle")) {
121               data = "RATTLE";
122             } else {
123               data = null;
124             }
125           } else {
126             keyword = s.substring(0, firstSpace).toUpperCase();
127             data = s.substring(firstSpace).trim();
128           }
129           Keyword kd = keywordHash.get(keyword);
130           if (kd == null) {
131             kd = new Keyword(keyword);
132             keywordHash.put(keyword, kd);
133           }
134           if (data != null) {
135             kd.append(data);
136           }
137           /*
138            Multipoles and TORTORS are the only keywords that span
139            multiple lines. Editing these from within Force Field X
140            seems unlikely, so they are treated as comments.
141           */
142           if (keyword.equalsIgnoreCase("MULTIPOLE")) {
143             int[] mnum = {3, 1, 2, 3};
144             for (int i = 0; i < 4; i++) {
145               if (!br.ready()) {
146                 System.out.println("Check for an invalid MULTIPOLE keyword.");
147                 return null;
148               }
149               s = br.readLine();
150               if (s == null) {
151                 logger.warning("Multipole format error.");
152                 return null;
153               }
154               s = s.trim();
155               if (s.split(" +").length != mnum[i]) {
156                 logger.warning("Multipole format error.");
157                 return null;
158               }
159               kd.append(s);
160             }
161           } else if (keyword.equalsIgnoreCase("TORTORS")) {
162             String[] res = data.split(" +");
163             if (res.length < 7) {
164               logger.warning("TORTOR format error.");
165               return null;
166             }
167             int xres = parseInt(res[5]);
168             int yres = parseInt(res[6]);
169             for (int i = 0; i < xres * yres; i++) {
170               if (!br.ready()) {
171                 System.out.println("Check for an invalid TORTOR keyword.");
172                 return null;
173               }
174               s = br.readLine();
175               if (s == null) {
176                 logger.warning("TORTOR format error.");
177                 return null;
178               }
179               s = s.trim();
180               if (s.split(" +").length != 3) {
181                 logger.warning("TORTOR format error.");
182                 return null;
183               }
184               kd.append(s);
185             }
186           }
187         }
188       }
189       return keywordHash;
190     } catch (IOException e) {
191       System.err.println("Error reading Key File: " + e);
192       return null;
193     }
194   }
195 
196   /**
197    * loadSystemKeywords
198    *
199    * @return a {@link java.util.Hashtable} object.
200    */
201   private static Hashtable<String, Keyword> loadSystemKeywords() {
202     File f = new File("/etc/ffx.conf");
203     Hashtable<String, Keyword> systemKeywords = new Hashtable<>();
204     if (f.exists() && f.canRead()) {
205       logger.info("Reading /etc/ffx.conf");
206       systemKeywords = KeyFilter.open(f, systemKeywords);
207     }
208     String path = System.getProperty("user.home") + File.separator + ".ffx/ffx.conf";
209     f = new File(path);
210     if (f.exists() && f.canRead()) {
211       logger.log(Level.INFO, "Reading {0}", path);
212       systemKeywords = KeyFilter.open(f, systemKeywords);
213     }
214     return systemKeywords;
215   }
216 }