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.ui;
39  
40  import static java.lang.String.format;
41  
42  import ffx.potential.ForceFieldEnergy;
43  import ffx.potential.MolecularAssembly;
44  import ffx.potential.Utilities;
45  import ffx.potential.parsers.FileOpener;
46  import ffx.potential.parsers.PDBFilter;
47  import ffx.potential.parsers.SystemFilter;
48  import ffx.utilities.Resources;
49  
50  import java.awt.Cursor;
51  import java.util.List;
52  import java.util.logging.Level;
53  import java.util.logging.Logger;
54  
55  import org.apache.commons.configuration2.CompositeConfiguration;
56  import org.apache.commons.io.FilenameUtils;
57  
58  /**
59   * The UIFileOpener class opens a file into Force Field X using a filter from the
60   * ffx.potential.parsers package. To avoid freezing the FFX GUI, it implements the FileOpener
61   * interface, which extends Runnable.
62   *
63   * @author Michael J. Schnieders
64   */
65  public class UIFileOpener implements FileOpener {
66  
67    private static final Logger logger = Logger.getLogger(UIFileOpener.class.getName());
68    private static final long KB = 1024;
69    SystemFilter systemFilter;
70    MainPanel mainPanel;
71    private boolean timer = true;
72    private boolean gc = true;
73    private long occupiedMemory;
74    private long time;
75    private int nThreads = -1;
76  
77    /**
78     * Constructor for UIFileOpener.
79     *
80     * @param systemFilter a {@link ffx.potential.parsers.SystemFilter} object.
81     * @param mainPanel    a {@link ffx.ui.MainPanel} object.
82     */
83    UIFileOpener(SystemFilter systemFilter, MainPanel mainPanel) {
84      this.systemFilter = systemFilter;
85      this.mainPanel = mainPanel;
86      if (System.getProperty("ffx.timer", "false").equalsIgnoreCase("true")) {
87        timer = true;
88        if (System.getProperty("ffx.timer.gc", "false").equalsIgnoreCase("true")) {
89          gc = true;
90        }
91      }
92    }
93  
94    /**
95     * Returns all MolecularAssemblys in the user interface hierarchy.
96     *
97     * @return All MolecularAssembly objects stored by the hierarchy.
98     * @throws NullPointerException If hierarchy has a null or empty list of assemblies.
99     */
100   @Override
101   public MolecularAssembly[] getAllAssemblies() throws NullPointerException {
102     MolecularAssembly[] assemblies = mainPanel.getHierarchy().getSystems();
103     if (assemblies == null) {
104       throw new NullPointerException(" FFX hierarchy has a null list of assemblies.");
105     } else if (assemblies.length == 0) {
106       throw new NullPointerException(" FFX hierarchy has an empty list of assemblies.");
107     } else {
108       return assemblies;
109     }
110   }
111 
112   /**
113    * Returns the properties of all FFXSystems in the hierarchy.
114    *
115    * @return Properties for all systems.
116    */
117   @Override
118   public CompositeConfiguration[] getAllProperties() {
119     FFXSystem[] allSystems = mainPanel.getHierarchy().getSystems();
120     int numSystems = allSystems.length;
121     CompositeConfiguration[] allProperties = new CompositeConfiguration[numSystems];
122     for (int i = 0; i < numSystems; i++) {
123       allProperties[i] = allSystems[i].getProperties();
124     }
125     return allProperties;
126   }
127 
128   /**
129    * Returns the active MolecularAssembly from the user interface hierarchy.
130    *
131    * @return Active MolecularAssembly
132    * @throws NullPointerException If no active MolecularAssembly
133    */
134   @Override
135   public MolecularAssembly getAssembly() throws NullPointerException {
136     MolecularAssembly assembly = mainPanel.getHierarchy().getActive();
137     if (assembly == null) {
138       throw new NullPointerException(" FFX hierarchy does not have an active assembly.");
139     }
140     return assembly;
141   }
142 
143   /**
144    * Returns the properties of the hierarchy's active FFXSystem.
145    *
146    * @return Active properties
147    */
148   @Override
149   public CompositeConfiguration getProperties() {
150     return mainPanel.getHierarchy().getActive().getProperties();
151   }
152 
153   /**
154    * {@inheritDoc}
155    */
156   @Override
157   public void run() {
158     if (mainPanel != null && systemFilter != null) {
159       open();
160     }
161   }
162 
163   void setNThreads(int nThreads) {
164     this.nThreads = nThreads;
165   }
166 
167   private void open() {
168     if (timer) {
169       startTimer();
170     }
171     FFXSystem ffxSystem = null;
172     // Continue if the file was read in successfully.
173     if (systemFilter.readFile()) {
174       ffxSystem = (FFXSystem) systemFilter.getActiveMolecularSystem();
175       if (!(systemFilter instanceof PDBFilter)) {
176         Utilities.biochemistry(ffxSystem, systemFilter.getAtomList());
177       }
178       systemFilter.applyAtomProperties();
179       // Add the system to the multiscale hierarchy.
180       mainPanel.getHierarchy().addSystemNode(ffxSystem);
181       ForceFieldEnergy energy;
182       if (nThreads > 0) {
183         energy = ForceFieldEnergy.energyFactory(ffxSystem, nThreads);
184       } else {
185         energy = ForceFieldEnergy.energyFactory(ffxSystem);
186       }
187       ffxSystem.setPotential(energy);
188       mainPanel.getHierarchy().setActive(ffxSystem);
189 
190       // Check if there are alternate conformers
191       if (systemFilter instanceof PDBFilter) {
192         PDBFilter pdbFilter = (PDBFilter) systemFilter;
193         List<Character> altLocs = pdbFilter.getAltLocs();
194         if (altLocs.size() > 1 || altLocs.get(0) != ' ') {
195           StringBuilder altLocString = new StringBuilder("\n Alternate locations found [ ");
196           for (Character c : altLocs) {
197             // Do not report the root conformer.
198             if (c == ' ') {
199               continue;
200             }
201             altLocString.append(format("(%s) ", c));
202           }
203           altLocString.append("]\n");
204           logger.info(altLocString.toString());
205         }
206 
207         // Alternate conformers may have different chemistry,
208         // so they each need to be their own FFX system.
209         for (Character c : altLocs) {
210           if (c.equals(' ') || c.equals('A')) {
211             continue;
212           }
213           FFXSystem newSystem = new FFXSystem(
214               ffxSystem.getFile(), "Alternate Location " + c, ffxSystem.getProperties());
215           newSystem.setForceField(ffxSystem.getForceField());
216           pdbFilter.setAltID(newSystem, c);
217           pdbFilter.clearSegIDs();
218           if (pdbFilter.readFile()) {
219             pdbFilter.applyAtomProperties();
220             String fileName = ffxSystem.getFile().getAbsolutePath();
221             newSystem.setName(FilenameUtils.getBaseName(fileName) + " " + c);
222             mainPanel.getHierarchy().addSystemNode(newSystem);
223             if (nThreads > 0) {
224               energy = ForceFieldEnergy.energyFactory(newSystem, nThreads);
225             } else {
226               energy = ForceFieldEnergy.energyFactory(newSystem);
227             }
228             newSystem.setPotential(energy);
229           }
230         }
231       }
232     } else {
233       logger.warning(String.format(" Failed to read file %s", systemFilter.getFile().getName()));
234     }
235     mainPanel.setCursor(Cursor.getDefaultCursor());
236     if (timer) {
237       stopTimer(ffxSystem);
238     }
239   }
240 
241   /**
242    * Rather verbose output for timed File Operations makes it easy to grep log files for specific
243    * information.
244    */
245   private void startTimer() {
246     Runtime runtime = Runtime.getRuntime();
247     if (gc) {
248       runtime.gc();
249     }
250     occupiedMemory = runtime.totalMemory() - runtime.freeMemory();
251     time -= System.nanoTime();
252   }
253 
254   private void stopTimer(FFXSystem ffxSystem) {
255     time += System.nanoTime();
256     logger.log(
257         Level.INFO,
258         "\n Opened {0} in {1} sec.",
259         new Object[]{ffxSystem.toString(), time * 1.0e-9});
260     Resources.logResources();
261   }
262 }