1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2006-09-11 23:56:13 -0500 (Mon, 11 Sep 2006) $
4  * $Revision: 5499 $
5  *
6  * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
7  *
8  * Contact: jmol-developers@lists.sf.net
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 package org.jmol.adapter.readers.spartan;
26 
27 import java.util.Hashtable;
28 import java.util.Map;
29 
30 import org.jmol.util.Logger;
31 
32 import javajs.util.BC;
33 import javajs.util.PT;
34 import javajs.util.SB;
35 
36 /*
37  * Spartan SMOL and .spartan compound document reader and .spartan06 zip files
38  *
39  */
40 
41 public class SpartanSmolReader extends SpartanInputReader {
42 
43   private boolean iHaveModelStatement;
44   private boolean isCompoundDocument;
45   private boolean inputOnly;
46   private boolean espCharges;
47   private boolean natCharges;
48   private boolean isInputFirst;
49   private boolean iHaveNewDir;
50 
51   @Override
initializeReader()52   protected void initializeReader() throws Exception {
53     isCompoundDocument = (rd()
54         .indexOf("Compound Document File Directory") >= 0);
55     inputOnly = checkFilterKey("INPUT");
56     natCharges = checkFilterKey("NATCHAR");
57     espCharges = !natCharges && !checkFilterKey("MULLIKEN"); // changed default in Jmol 12.1.41, 12.0.38
58 
59   }
60 
61   @Override
checkLine()62   protected boolean checkLine() throws Exception {
63     // BH Note: I will be the first to say that this coding is way too complicated.
64     // The original design accommodates too many variations. There are
65     // the Spartan for Windows compound document, the MacSpartan directory, and
66     // the Jmol translation of each of those.
67 
68     // JMOL_MODEL is a bogus type added by Jmol as a marker only,
69     // added only to the MacSpartan directory format.
70     // That record is placed BEFORE the Input record, while
71     // for the compound document, Input comes before Molecule.
72 
73     // MacSpartan:
74     //       c:/temp/cyclohexane_movie.spardir/M0001/#JMOL_MODEL M0001
75     //       BEGIN Directory Entry c:/temp/cyclohexane_movie.spardir/M0001/input
76     //       BEGIN Directory Entry c:/temp/cyclohexane_movie.spardir/M0001/Molecule:asBinaryString
77     // Spartan for Windows; Spartan 14:
78     //       BEGIN Directory Entry Input
79     //       BEGIN Directory Entry Molecule
80     //
81     int pt = 3;
82     boolean isNewDir = (isCompoundDocument
83         && line.startsWith("NEW Directory M")
84         && !line.startsWith("NEW Directory Molecules"));
85     if (isNewDir)
86       iHaveNewDir = true;
87     boolean isMolecule = (!iHaveNewDir && !isNewDir && isCompoundDocument && line
88         .equals("BEGIN Directory Entry Molecule"));
89     boolean isMacDir = (!isCompoundDocument && (pt = line.indexOf("#JMOL_MODEL")) >= 0);
90     if (isNewDir || isMolecule || isMacDir) {
91       if (modelNumber > 0 && !isInputFirst)
92         applySymmetryAndSetTrajectory();
93       iHaveModelStatement = true;
94       int modelNo = (isMolecule ? 0 : parseIntAt(line, pt + 12));
95       modelNumber = (bsModels == null && modelNo != Integer.MIN_VALUE && modelNo != 0 ? modelNo
96           : modelNumber + 1);
97       bondData = "";
98       if (!doGetModel(modelNumber, null)) {
99         if (isInputFirst) {
100           asc.removeCurrentAtomSet();
101           discardLinesUntilContains("BEGIN Directory Entry Input");
102         } else if (isNewDir) {
103           discardLinesUntilContains("NEW Directory M");
104         } else if (isMolecule) {
105           discardLinesUntilContains("BEGIN Directory Entry M");
106         } else {
107           discardLinesUntilContains("#JMOL_MODEL");
108         }
109         checkLastModel();
110         return false;
111       }
112       if (!isInputFirst) {
113         makeNewAtomSet();
114       }
115       moData = new Hashtable<String, Object>();
116       moData.put("isNormalized", Boolean.TRUE);
117       boolean isOK = false;
118       if (modelNo == Integer.MIN_VALUE || titles == null) {
119         modelNo = modelNumber;
120         title = "Model " + modelNo;
121       } else {
122         isOK = true;
123         title = titles.get("Title" + modelNo);
124         title = "Profile " + modelNo + (title == null ? "" : ": " + title);
125       }
126       if (constraints == null  && (isOK || !isInputFirst))
127         asc.setAtomSetName(title);
128       setModelPDB(false);
129       asc.setCurrentAtomSetNumber(modelNo);
130       if (isMolecule)
131         readMyTransform();
132       return true;
133     }
134     if (iHaveModelStatement && !doProcessLines)
135       return true;
136     if ((line.indexOf("BEGIN") == 0)) {
137       String lcline = line.toLowerCase();
138       if (lcline.endsWith("input")) {
139         if (!iHaveModelStatement)
140           isInputFirst = true;
141         if (isInputFirst) {
142           makeNewAtomSet();
143         }
144         bondData = "";
145         title = readInputRecords();
146         if (asc.errorMessage != null) {
147           continuing = false;
148           return false;
149         }
150         if (title != null && constraints == null)
151           asc.setAtomSetName(title);
152         setCharges();
153         if (inputOnly) {
154           continuing = false;
155           return false;
156         }
157       } else if (lcline.endsWith("_output")) {
158         return true;
159       } else if (lcline.endsWith("output")) {
160         readOutput();
161         return false;
162       } else if (lcline.endsWith("molecule")
163           || lcline.endsWith("molecule:asbinarystring")) {
164         readMyTransform();
165         return false;
166       } else if (lcline.endsWith("proparc")
167           || lcline.endsWith("propertyarchive")) {
168         readProperties();
169         return false;
170       } else if (lcline.endsWith("molstate")) {
171           readTransform();
172           return false;
173       } else if (lcline.endsWith("archive")) {
174         asc.setAtomSetName(readArchive());
175         return false;
176       }
177       return true;
178     }
179     if (line.indexOf("5D shell") >= 0)
180       moData.put("calculationType", calculationType = line);
181     return true;
182   }
183 
makeNewAtomSet()184   private void makeNewAtomSet() {
185     // Spartan 16 files may have an empty first model
186     if (asc.ac == 0)
187       asc.removeCurrentAtomSet();
188     asc.newAtomSet();
189   }
190 
191   @Override
finalizeSubclassReader()192   protected void finalizeSubclassReader() throws Exception {
193     finalizeReaderASCR();
194     // info out of order -- still a chance, at least for first model
195     if (asc.ac > 0 && spartanArchive != null && asc.bondCount == 0
196         && bondData != null)
197       spartanArchive.addBonds(bondData, 0);
198     if (moData != null) {
199       Float n = (Float) asc.atomSetInfo.get("HOMO_N");
200       if (n != null) {
201         int i = n.intValue();
202         moData.put("HOMO", Integer.valueOf(i));
203         // TODO: This would take some work -- SOMO, degenerate HOMO etc.
204         //for (int j = orbitals.size(); --j >= 0;)
205           //orbitals.get(j).put("occupancy", Float.valueOf(j > i ? 0 : 2));
206 
207       }
208     }
209   }
210 
readMyTransform()211   private void readMyTransform() throws Exception {
212     float[] mat;
213     String binaryCodes = rd();
214     // last 16x4 bytes constitutes the 4x4 matrix, using doubles
215     String[] tokens = PT.getTokens(binaryCodes.trim());
216     if (tokens.length < 16)
217       return;
218     byte[] bytes = new byte[tokens.length];
219     for (int i = 0; i < tokens.length; i++)
220       bytes[i] = (byte) PT.parseIntRadix(tokens[i], 16);
221     mat = new float[16];
222     for (int i = 16, j = bytes.length - 8; --i >= 0; j -= 8)
223       mat[i] = BC.bytesToDoubleToFloat(bytes, j, false);
224     setTransform(mat[0], mat[1], mat[2], mat[4], mat[5], mat[6], mat[8],
225         mat[9], mat[10]);
226   }
227 
228   private final static String endCheck = "END Directory Entry ";
229   private String title;
230 
231   SpartanArchive spartanArchive;
232 
233   Map<String, String> titles;
234 
readOutput()235   private void readOutput() throws Exception {
236     titles = new Hashtable<String, String>();
237     SB header = new SB();
238     int pt;
239     while (rd() != null && !line.startsWith("END ") && !line.startsWith("ENDOUTPUT")) {
240       header.append(line).append("\n");
241       if ((pt = line.indexOf(")")) > 0)
242         titles.put("Title" + parseIntRange(line, 0, pt), (line
243             .substring(pt + 1).trim()));
244     }
245     asc.setInfo("fileHeader", header
246         .toString());
247   }
248 
readArchive()249   private String readArchive() throws Exception {
250     spartanArchive = new SpartanArchive(this, bondData, endCheck, 0);
251     String modelName = readArchiveHeader();
252     if (modelName != null)
253       modelAtomCount = spartanArchive.readArchive(line, false, asc.ac, false);
254     return (constraints == null ? modelName : null);
255   }
256 
257   private boolean haveCharges;
258 
setCharges()259   private void setCharges() {
260     if (haveCharges || asc.ac == 0)
261       return;
262     haveCharges = (espCharges
263         && asc.setAtomSetCollectionPartialCharges("ESPCHARGES")
264         || natCharges && asc.setAtomSetCollectionPartialCharges("NATCHARGES")
265         || asc.setAtomSetCollectionPartialCharges("MULCHARGES")
266         || asc.setAtomSetCollectionPartialCharges("Q1_CHARGES") || asc
267         .setAtomSetCollectionPartialCharges("ESPCHARGES"));
268   }
269 
readProperties()270   private void readProperties() throws Exception {
271     if (modelAtomCount == 0) {
272       rd();
273       return;
274     }
275     if (spartanArchive == null)
276       spartanArchive = new SpartanArchive(this, bondData, endCheck,
277           modelAtomCount);
278     spartanArchive.readProperties();
279     rd();
280     setCharges();
281   }
282 
readArchiveHeader()283   private String readArchiveHeader() throws Exception {
284     String modelInfo = rd();
285     if (debugging)
286       Logger.debug(modelInfo);
287     if (modelInfo.indexOf("Error:") == 0) // no archive here
288       return null;
289     asc.setCollectionName(modelInfo);
290     asc.setAtomSetName(modelInfo);
291     String modelName = rd();
292     if (debugging)
293       Logger.debug(modelName);
294     //    5  17  11  18   0   1  17   0 RHF      3-21G(d)           NOOPT FREQ
295     rd();
296     return modelName;
297   }
298 
setEnergy(float value)299   public void setEnergy(float value) {
300     asc.setAtomSetName(constraints + (constraints.length() == 0 ? "" : " ") + "Energy=" + value + " KJ");
301   }
302 
303 }
304