1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2006-09-12 00:46:22 -0500 (Tue, 12 Sep 2006) $
4  * $Revision: 5501 $
5  *
6  * Copyright (C) 2004-2005  The Jmol Development Team
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.quantum;
26 
27 import java.io.BufferedReader;
28 import java.util.Hashtable;
29 import java.util.Map;
30 
31 import javajs.util.AU;
32 import javajs.util.Lst;
33 import javajs.util.P3;
34 import javajs.util.PT;
35 import javajs.util.Rdr;
36 import javajs.util.SB;
37 
38 import org.jmol.adapter.smarter.Atom;
39 import org.jmol.quantum.QS;
40 import org.jmol.util.Logger;
41 import org.jmol.viewer.FileManager;
42 import org.jmol.viewer.JC;
43 import org.jmol.viewer.Viewer;
44 
45 
46 /**
47  * NBO file nn reader will pull in other files as necessary
48  *
49  * acknowledgments: Grange Hermitage, Frank Weinhold
50  *
51  *
52  * upgrade to NBO 6 allows reading of resonance structures, including base structure
53  *
54  *
55  * @author hansonr
56  **/
57 
58 
59 public class GenNBOReader extends MOReader {
60 
61 
62 //
63 //  *********************************** NBO 6.0 ***********************************
64 //              N A T U R A L   A T O M I C   O R B I T A L   A N D
65 //           N A T U R A L   B O N D   O R B I T A L   A N A L Y S I S
66 //  **************************** Robert Hanson (100634) ***************************
67 //   (c) Copyright 1996-2014 Board of Regents of the University of Wisconsin System
68 //       on behalf of the Theoretical Chemistry Institute.  All rights reserved.
69 //
70 //           Cite this program as:
71 //
72 //           NBO 6.0.  E. D. Glendening, J. K. Badenhoop, A. E. Reed,
73 //           J. E. Carpenter, J. A. Bohmann, C. M. Morales, C. R. Landis,
74 //           and F. Weinhold (Theoretical Chemistry Institute, University
75 //           of Wisconsin, Madison, WI, 2013); http://nbo6.chem.wisc.edu/
76 //
77 //        /NLMO   / : Form natural localized molecular orbitals
78 //        /NRT    / : Natural Resonance Theory Analysis
79 //        /AOPNAO / : Print the AO to PNAO transformation
80 //        /SAO    / : Print the AO overlap matrix
81 //        /STERIC / : Print NBO/NLMO steric analysis
82 //        /CMO    / : Print analysis of canonical MOs
83 //        /PLOT   / : Write information for the orbital plotter
84 //        /FILE   / : Set to co2_p
85 //
86 //  Filename set to co2_p
87 
88   private boolean isOutputFile;
89   private String nboType = "";
90   private int nOrbitals0;
91   private boolean is47File;
92   private boolean isOpenShell;
93   private boolean alphaOnly, betaOnly;
94 
95   private int nAOs, nNOs;
96 
97   @Override
initializeReader()98   protected void initializeReader() throws Exception {
99     /*
100      * molname.31 AO
101      * molname.32 PNAO
102      * molname.33 NAO
103      * molname.34 PNHO
104      * molname.35 NHO
105      * molname.36 PNBO
106      * molname.37 NBO
107      * molname.38 PNLMO
108      * molname.39 NLMO
109      * molname.40 MO
110      * molname.41 AO density matrix
111      * molname.44 RNBO
112      * molname.45 PRNBO
113      * molname.46 Basis label file
114      * molname.47 archive file
115      * molname.nbo output file
116      *
117      */
118     String line1 = rd().trim().toUpperCase();
119     is47File = (line1.indexOf("$GENNBO") >= 0 || line1.indexOf("$NBO") >= 0); // GENNBO 6
120     if (is47File) {
121       if (line1.indexOf("BOHR") >= 0) {
122         fileOffset = new P3();
123         fileScaling = P3.new3(ANGSTROMS_PER_BOHR,ANGSTROMS_PER_BOHR,ANGSTROMS_PER_BOHR);
124       }
125       readData47();
126       return;
127     }
128     alphaOnly = checkFilterKey("ALPHA");
129     betaOnly =  checkFilterKey("BETA");
130     boolean isOK;
131     String line2 = rd();
132     line = line1 + line2;
133     isOutputFile = (line2.indexOf("****") >= 0);
134     if (isOutputFile) {
135       // this may or may not work.
136       isOK = getFile31();
137       super.initializeReader();
138       // keep going -- we need to read the file using MOReader
139       //moData.put("isNormalized", Boolean.TRUE);
140     } else if (line2.indexOf("s in the AO basis:") >= 0) {
141       nboType = line2.substring(1, line2.indexOf("s"));
142       asc.setCollectionName(line1 + ": " + nboType + "s");
143       isOK = getFile31();
144     } else {//if (line.indexOf("Basis set information") >= 0) {
145       nboType = "AO";
146       asc.setCollectionName(line1 + ": " + nboType + "s");
147       isOK = readData31(line1);
148     }
149     if (!isOK)
150       Logger.error("Unimplemented shell type -- no orbitals available: " + line);
151     if (isOutputFile)
152       return;
153     if (isOK)
154       readMOs();
155     continuing = false;
156   }
157 
158   @Override
finalizeSubclassReader()159   protected void finalizeSubclassReader() throws Exception {
160     appendLoadNote("NBO type " + nboType);
161     if (isOpenShell)
162       asc.setCurrentModelInfo("isOpenShell", Boolean.TRUE);
163     finalizeReaderASCR();
164   }
165 
166   private String topoType = "A";
167 
168 //$GENNBO  NATOMS=7  NBAS=28  UPPER  BODM  FORMAT  $END
169 //$NBO  $END
170 //$COORD
171 //Methylamine...RHF/3-21G//Pople-Gordon geometry
172 //    6    6       0.745914       0.011106       0.000000
173 //    7    7      -0.721743      -0.071848       0.000000
174 //    1    1       1.042059       1.060105       0.000000
175 //    1    1       1.129298      -0.483355       0.892539
176 //    1    1       1.129298      -0.483355      -0.892539
177 //    1    1      -1.076988       0.386322      -0.827032
178 //    1    1      -1.076988       0.386322       0.827032
179 //$END
180 
181 
182   @Override
checkLine()183   protected boolean checkLine() throws Exception {
184     // for .nbo only
185     if (line.indexOf("SECOND ORDER PERTURBATION THEORY ANALYSIS") >= 0
186         && !orbitalsRead) {
187       // Frank Weinhold suggests that NBO/.37 is not the best choice for a default.
188       // PNBOs (pre-NBOs) are not orthogonalized and so "look better." But we are already
189       // reading NBOs, and they are fine as well. I'd rather not change this
190       // default and risk changes in PNGJ files already saved.
191       nboType = "NBO";
192       String data = getFileData(".37");
193       if (data == null)
194         return true;
195       BufferedReader readerSave = reader;
196       reader = Rdr.getBR(data);
197       rd();
198       rd();
199       readMOs();
200       reader = readerSave;
201       orbitalsRead = false;
202       return true;
203     }
204     if (line.indexOf("$NRTSTRA") >= 0) {
205       getStructures("NRTSTRA");
206       return true;
207     }
208     if (line.indexOf("$NRTSTRB") >= 0) {
209       getStructures("NRTSTRB");
210       return true;
211     }
212     if (line.indexOf("$NRTSTR") >= 0) {
213         getStructures("NRTSTR");
214         return true;
215     }
216     if (line.indexOf(" TOPO ") >= 0) {
217       getStructures("TOPO" + topoType);
218       topoType = "B";
219       return true;
220     }
221     if (line.indexOf("$CHOOSE") >= 0) {
222       getStructures("CHOOSE");
223       return true;
224     }
225     return checkNboLine();
226   }
227 
228   private int nStructures = 0;
229   NBOParser nboParser;
230   private boolean addBetaSet;
231 
getStructures(String type)232   private void getStructures(String type) throws Exception {
233     if (nboParser == null)
234       nboParser = new NBOParser();
235 
236     Lst<Object> structures = getStructureList();
237     SB sb = new SB();
238     while (!rd().trim().equals("$END"))
239       sb.append(line).append("\n");
240     nStructures = nboParser.getStructures(sb.toString(), type, structures);
241     appendLoadNote(nStructures + " NBO " + type + " resonance structures");
242   }
243 
244   @SuppressWarnings("unchecked")
getStructureList()245   private Lst<Object> getStructureList() {
246     Lst<Object> structures = (Lst<Object>) asc.getAtomSetAuxiliaryInfo(asc.iSet).get("nboStructures");
247     if (structures  == null)
248       asc.setCurrentModelInfo("nboStructures", structures = new Lst<Object>());
249     return structures;
250   }
251 
getFileData(String ext)252   private String getFileData(String ext) throws Exception {
253     String fileName = FileManager.stripTypePrefix((String) htParams.get("fullPathName"));
254     int pt = fileName.lastIndexOf(".");
255     if (pt < 0)
256       pt = fileName.length();
257     fileName = fileName.substring(0, pt);
258     moData.put("nboRoot", fileName);
259     if (ext.startsWith(".")) {
260       fileName += ext;
261     } else {
262       pt = fileName.lastIndexOf("/");
263       fileName = fileName.substring(0, pt + 1) + ext;
264     }
265     String data = vwr.getFileAsString3(fileName, false, null);
266     Logger.info(data.length() + " bytes read from " + fileName);
267     boolean isError = (data.indexOf("java.io.") >= 0);
268     if (data.length() == 0 || isError && nboType != "AO")
269       throw new Exception(" supplemental file " + fileName + " was not found");
270     if (!isError)
271       addAuxFile(moData, fileName, htParams);
272     return (isError ? null : data);
273   }
274 
275   // 14_a Basis set information needed for plotting orbitals
276   // ---------------------------------------------------------------------------
277   // 36 90 162
278   // ---------------------------------------------------------------------------
279   // 6 -2.992884000 -1.750577000 1.960024000
280   // 6 -2.378528000 -1.339374000 0.620578000
281   //
282 
getFile31()283   private boolean getFile31() throws Exception {
284     try {
285       String data = getFileData(".31");
286       if (data == null)
287         return false;
288       BufferedReader readerSave = reader;
289       reader = Rdr.getBR(data);
290       return (readData31(null) && (reader = readerSave) != null);
291     } catch (Exception e) {
292       return false;
293     }
294   }
295 
296   /**
297    * read the labels from xxxx.46
298    *
299    * @throws Exception
300    */
getFile46()301   private void getFile46() {
302     nNOs = nAOs = nOrbitals;
303     String labelKey = getLabelKey(nboType);
304     Map<String, String[]> map = null;
305     BufferedReader readerSave = reader;
306     try {
307       reader = Rdr.getBR(getFileData(".46"));
308       map = readData46(labelKey);
309     } catch (Exception e) {
310       try {
311         map = readOutputProperties(getFileData("output.properties"));
312       } catch (Exception ee) {
313         map = new Hashtable<String, String[]>();
314         setMap(map, "NHO", nNOs, false);
315         setMap(map, "NBO", nNOs, false);
316         setMap(map, "NAO", nNOs, false);
317       }
318     }
319     setMap(map, labelKey, nNOs, true);
320     reader = readerSave;
321   }
322 
readOutputProperties(String data)323   private Map<String, String[]> readOutputProperties(String data) {
324     Map<String, String[]> map = new Hashtable<String, String[]>();
325     String[] lines = data.split("\n");
326     for (int i = lines.length; --i >= 0;) {
327       String line = lines[i];
328       if (line.startsWith("Natural Atomic Orbitals=")) {
329         setLabels(map, "NAO", line);
330       } else if (line.startsWith("Natural Hybrid Orbitals=")) {
331         setLabels(map, "NHO", line);
332       } else if (line.startsWith("Natural Bond Orbitals=")) {
333         setLabels(map, "NBO", line);
334       }
335     }
336     return map;
337   }
338 
setLabels(Map<String, String[]> map, String key, String line)339   private void setLabels(Map<String, String[]> map, String key, String line) {
340     String[] tokens = PT.split(line, ":");
341     for (int i = tokens.length; --i >= 0;) {
342       String s = PT.split(tokens[i], ",")[1];
343       tokens[i] = (s.indexOf("%") >= 0 ? s.substring(0, s.indexOf(" "))
344           : PT.rep(s, " ",""));
345     }
346     map.put(key, tokens);
347   }
348 
349   private static String P_LIST =  "101   102   103";
350   private static String PS_LIST =  "151   152   153";
351   // GenNBO may be 103 101 102
352 
353   private static String SP_LIST = "1     101   102   103";
354   private static String SPS_LIST =  "51    151   152   153";
355 
356   private static String DS_LIST = "255   252   253   254   251";
357   // GenNBO is 251 252 253 254 255
358   //   for     Dxy Dxz Dyz Dx2-y2 D2z2-x2-y2
359   // org.jmol.quantum.MOCalculation expects
360   //   d2z^2-x2-y2, dxz, dyz, dx2-y2, dxy
361 
362   private static String DC_LIST = "201   204   206   202   203   205";
363   // GenNBO is 201 202 203 204 205 206
364   //       for Dxx Dxy Dxz Dyy Dyz Dzz
365   // org.jmol.quantum.MOCalculation expects
366   //      Dxx Dyy Dzz Dxy Dxz Dyz
367 
368   private static String FS_LIST = "351   352   353   354   355   356   357";
369   // GenNBO is 351 352 353 354 355 356 357
370   //  f(0)     2z3-3x2z-3y2z
371   //  f(c1)        4xz2-x3-xy2
372   //  f(s1)            4yz2-x2y-y3
373   //  f(c2)                x2z-y2z
374   //  f(s2)                    xyz
375   //  f(c3)                        x3-3xy2
376   //  f(s3)                            3x2y-y3
377   // org.jmol.quantum.MOCalculation expects the same
378   private static String FC_LIST = "301   307   310   304   302   303   306   309   308   305";
379   // GenNBO is 301 302 303 304 305 306 307 308 309 310
380   //       for xxx xxy xxz xyy xyz xzz yyy yyz yzz zzz
381   // org.jmol.quantum.MOCalculation expects
382   //           xxx yyy zzz xyy xxy xxz xzz yzz yyz xyz
383   //           301 307 310 304 302 303 306 309 308 305
384 
385   private static String GS_LIST = "451   452   453   454   455   456   457   458   459";
386   // GenNBO assumes same
387   // org.jmol.quantum.MOCalculation expects
388   //  9G: G 0, G+1, G-1, G+2, G-2, G+3, G-3, G+4, G-4
389 
390   private static String GC_LIST = "415   414   413   412   411   410   409   408   407   406   405   404   403   402   401";
391   // GenNBO 401  402  403  404  405  406  407  408  409  410
392   //    for xxxx xxxy xxxz xxyy xxyz xxzz xyyy xyyz xyzz xzzz
393   // GenNBO 411  412  413  414  415
394   //        yyyy yyyz yyzz yzzz zzzz
395   //
396   // Gaussian is exactly opposite this.
397 
398 
399   private static String HS_LIST = "551   552   553   554   555   556   557   558   559   560   561";
400 
401   private static String HC_LIST =
402       "521   520   519   518   517   516   515   514   513   512   " +
403       "511   510   509   508   507   506   505   504   503   502   501";
404   // GenNBO is 501-521
405   //        501   502   503   504   505   506   507   508   509   510
406   //    for xxxxx xxxxy xxxxz xxxyy xxxyz xxxzz xxyyy xxyyz xxyzz xxzzz
407   //        511   512   513   514   515   516   517   518   519   520
408   //        xyyyy xyyyz xyyzz xyzzz xzzzz yyyyy yyyyz yyyzz yyzzz yzzzz
409   //        521
410   //        zzzzz
411   //
412   // Gaussian is opposite
413 
414   private static String IS_LIST = "651   652   653   654   655   656   657   658   659   660   661   662   663";
415 
416   private static String IC_LIST =
417       "628   627   626   625   624   623   622   621   620   " +
418       "619   618   617   616   615   614   613   612   611   610   " +
419       "609   608   607   606   605   604   603   602   601";
420   // GenNBO is 601-628
421   // for xxxxxx xxxxxy xxxxxz xxxxyy xxxxyz xxxxzz xxxyyy xxxyyz xxxyzz xxxzzz
422   //     xxyyyy xxyyyz xxyyzz xxyzzz xxzzzz xyyyyy xyyyyz xyyyzz xyyzzz xyzzzz
423   //     xzzzzz yyyyyy yyyyyz yyyyzz yyyzzz yyzzzz yzzzzz zzzzzz
424   //
425   // Gaussian is opposite this
426 
readData47()427   private void readData47() throws Exception {
428     allowNoOrbitals = true;
429     discardLinesUntilContains("$COORD");
430     asc.newAtomSet();
431     asc.setAtomSetName(rd().trim());
432     while (rd().indexOf("$END") < 0) {
433       String[] tokens = getTokens();
434       addAtomXYZSymName(tokens, 2, null, null).elementNumber = (short) parseIntStr(tokens[0]);
435     }
436 
437     //Commented out by fzy
438     //This fixes the issue of NRT (SEARCH module) stuck in "getting list r" operation/ NBOServe dies for open shell molecules.
439     //This also fixes the issue of switching from RUN module(after inputting a .47 file) to MODEL module, which results in NBOServe throwing
440     //warning. The reason lies in Jmol sending CMD <empty string> to NBOServe.
441     // if (doReadMolecularOrbitals && !getFile31()) {
442     //   alphaOnly =  true;
443     //   betaOnly =  false;
444 
445       discardLinesUntilContains("$BASIS");
446       appendLoadNote("basis AOs are unnormalized");
447       int[] centers = getIntData();
448       int[] labels = getIntData();
449 
450       discardLinesUntilContains("NSHELL =");
451 
452 
453 
454       shellCount = parseIntAt(line, 10);
455       gaussianCount = parseIntAt(rd(), 10);
456       rd();
457       int[] ncomp = getIntData();
458       int[] nprim = getIntData();
459       int[] nptr = getIntData();
460       // read basis functions
461       shells = new  Lst<int[]>();
462       gaussians = AU.newFloat2(gaussianCount);
463       for (int i = 0; i < gaussianCount; i++)
464         gaussians[i] = new float[6];
465       nOrbitals = 0;
466       int ptCenter = 0;
467       String l = line;
468       for (int i = 0; i < shellCount; i++) {
469         int[] slater = new int[4];
470         int nc = ncomp[i];
471         slater[0] = centers[ptCenter];
472         line = "";
473         for (int ii = 0; ii < nc; ii++)
474           line += labels[ptCenter++] + " ";
475         if (!fillSlater(slater, nc, nptr[i] - 1, nprim[i]))
476           return;
477       }
478       line = l;
479       getAlphasAndExponents();
480       nboType = "AO";
481       readMOs();
482     // }
483     continuing = false;
484   }
485 
getIntData()486   private int[] getIntData() throws Exception {
487     while (line.indexOf("=") < 0)
488       rd();
489     String s = line.substring(line.indexOf("=") + 1);
490     line = "";
491     while (rd().indexOf("=") < 0 && line.indexOf("$") < 0)
492       s += line;
493     String[] tokens = PT.getTokens(s);
494     int[] f = new int[tokens.length];
495     for (int i = f.length; --i >= 0;)
496       f[i] = parseIntStr(tokens[i]);
497     return f;
498   }
499 
fillSlater(int[] slater, int n, int pt, int ng)500   private boolean fillSlater(int[] slater, int n, int pt, int ng) {
501     nOrbitals += n;
502     switch (n) {
503     case 1:
504       slater[1] = QS.S;
505       break;
506     case 3:
507       if (!getDFMap("P", line, QS.P, P_LIST, 3) && resetDF() && !getDFMap("P", line, QS.P, PS_LIST, 3))
508         return false;
509       slater[1] = QS.P;
510       break;
511     case 4:
512       if (!getDFMap("SP", line, QS.SP, SP_LIST, 1) && resetDF() && !getDFMap("SP", line, QS.SP, SPS_LIST, 2))
513         return false;
514       slater[1] = QS.SP;
515       break;
516 
517     case 5:
518       if (!getDFMap("DS", line, QS.DS, DS_LIST, 3))
519         return false;
520       slater[1] = QS.DS;
521       break;
522     case 6:
523       if (!getDFMap("DC", line, QS.DC, DC_LIST, 3))
524         return false;
525       slater[1] = QS.DC;
526       break;
527 
528     case 7:
529       if (!getDFMap("FS", line, QS.FS, FS_LIST, 3))
530         return false;
531       slater[1] = QS.FS;
532       break;
533     case 10:
534       if (!getDFMap("FC", line, QS.FC, FC_LIST, 3))
535         return false;
536       slater[1] = QS.FC;
537       break;
538 
539     case 9:
540       if (!getDFMap("GS", line, QS.GS, GS_LIST, 3))
541         return false;
542       slater[1] = QS.GS;
543       break;
544     case 15:
545       if (!getDFMap("GC", line, QS.GC, GC_LIST, 3))
546         return false;
547       slater[1] = QS.GC;
548       break;
549 
550     case 11:
551       if (!getDFMap("HS", line, QS.HS, HS_LIST, 3))
552         return false;
553       slater[1] = QS.HS;
554       break;
555     case 21:
556       if (!getDFMap("HC", line, QS.HC, HC_LIST, 3))
557         return false;
558       slater[1] = QS.HC;
559       break;
560 
561     case 13:
562       if (!getDFMap("IS", line, QS.IS, IS_LIST, 3))
563         return false;
564       slater[1] = QS.IS;
565       break;
566     case 28:
567       if (!getDFMap("IC", line, QS.IC, IC_LIST, 3))
568         return false;
569       slater[1] = QS.IC;
570       break;
571     default:
572       Logger.error("Unrecognized orbital slater count: " + n);
573       break;
574     }
575     slater[2] = pt + 1; // gaussian list pointer
576     slater[3] = ng; // number of gaussians
577     shells.addLast(slater);
578     return true;
579   }
580 
resetDF()581   private boolean resetDF() {
582     dfCoefMaps[QS.P][0] = 0;
583     return true;
584   }
585 
getAlphasAndExponents()586   private void getAlphasAndExponents() throws Exception {
587     // EXP  CS  CP  CD  ??
588     for (int j = 0; j < 5; j++) {
589       if (line.indexOf("=") < 0)
590         rd();
591       if (line.indexOf("$END") >= 0)
592         break;
593       line = line.substring(line.indexOf("=") + 1);
594       float[] temp = fillFloatArray(line, 0, new float[gaussianCount]);
595       for (int i = 0; i < gaussianCount; i++) {
596         gaussians[i][j] = temp[i];
597         if (j > 1)
598           gaussians[i][5] += temp[i];
599       }
600     }
601     // GenNBO lists S, P, D, F, G orbital coefficients separately
602     // we need all of them in [1] if [1] is zero (not S or SP)
603     for (int i = 0; i < gaussianCount; i++) {
604       if (gaussians[i][1] == 0)
605         gaussians[i][1] = gaussians[i][5];
606     }
607     if (debugging) {
608       Logger.debug(shells.size() + " slater shells read");
609       Logger.debug(gaussians.length + " gaussian primitives read");
610     }
611   }
612 
readData31(String line1)613   private boolean readData31(String line1) throws Exception {
614 
615 // HCN(-), E(UB3LYP) = -93.4597027357 [nu: 804(2),2186,3329] Vibrational te
616 //     Basis set information needed for plotting orbitals
617 //     ---------------------------------------------------------------------------
618 //          3    74   111
619 //     ---------------------------------------------------------------------------
620 //        1      0.000000      0.000000     -1.567118
621 //        6      0.000000      0.000000     -0.496424
622 //        7      0.000000      0.000000      0.649380
623 //     ---------------------------------------------------------------------------
624 //          1     1     1     4
625 //          1
626 //          1     1     5     1
627 //          1
628 //          1     1     6     1
629 //          1
630 //          1     1     7     1
631 //          1
632 //          1     1     8     1
633 //          1
634 //          1     1     9     1
635 //          1
636 //          1     3    10     1
637 //        101   102   103
638 // ...
639 //          2    11    66     1
640 //        551   552   553   554   555   556   557   558   559   560
641 //        561
642 
643 
644     if (line1 == null) {
645       line1 = rd();
646       rd();
647     }
648     rd(); // ----------
649 
650     // read ac, shellCount, and gaussianCount
651     String[] tokens = PT.getTokens(rd());
652     int ac = parseIntStr(tokens[0]);
653     shellCount = parseIntStr(tokens[1]);
654     gaussianCount = parseIntStr(tokens[2]);
655     if (tokens.length < 4)
656       Logger.error("NOTE! .31 file is old; d orbitals are not normalized");
657 
658     // read atom types and positions
659     rd(); // ----------
660     asc.newAtomSet();
661     asc.setAtomSetName(nboType + "s: " + line1.trim());
662     asc.setCurrentModelInfo("nboType", nboType);
663     for (int i = 0; i < ac; i++) {
664       tokens = PT.getTokens(rd());
665       int z = parseIntStr(tokens[0]);
666       if (z < 0) // dummy atom
667         continue;
668       Atom atom = asc.addNewAtom();
669       atom.elementNumber = (short) z;
670       setAtomCoordTokens(atom, tokens, 1);
671     }
672 
673     // read basis functions
674     shells = new  Lst<int[]>();
675     gaussians = AU.newFloat2(gaussianCount);
676     for (int i = 0; i < gaussianCount; i++)
677       gaussians[i] = new float[6];
678     rd(); // ----------
679     nOrbitals = 0;
680     for (int i = 0; i < shellCount; i++) {
681       tokens = PT.getTokens(rd());
682       int[] slater = new int[4];
683       slater[0] = parseIntStr(tokens[0]); // atom pointer; 1-based
684       int n = parseIntStr(tokens[1]);
685       int pt = parseIntStr(tokens[2]) - 1; // gaussian list pointer
686       int ng = parseIntStr(tokens[3]);     // number of gaussians
687       line = rd();
688       for (int j = (n - 1) / 10; --j >= 0;)
689         line += rd().substring(1);
690       line = line.trim();
691       //System.out.println(line);
692       if (!fillSlater(slater, n, pt, ng))
693         return false;
694     }
695     rd();
696     getAlphasAndExponents();
697     return true;
698   }
699 
700   /**
701    * read labels and not proper number of NOs, nNOs, for this nboType
702    * @return
703    *
704    * @throws Exception
705    */
readData46(String labelKey)706   private Map<String, String[]> readData46(String labelKey) throws Exception {
707     Map<String, String[]> map = new Hashtable<String, String[]>();
708     String[] tokens = new String[0];
709     rd();
710     int nNOs = this.nNOs;
711     while (line != null && line.length() > 0) {
712       tokens = PT.getTokens(line);
713       String type = tokens[0];
714       isOpenShell = (tokens.length == 3);
715       String ab = (isOpenShell ? tokens[1] : "");
716       String count = tokens[tokens.length - 1];
717       String key = (ab.equals("BETA") ? "beta_" : "") + type;
718       if (parseIntStr(count) != nOrbitals) {
719         Logger.error("file 46 number of orbitals for " + line + " (" + count + ") does not match nOrbitals: "
720             + nOrbitals + "\n");
721         nNOs = parseIntStr(count);
722       }
723       if (type.equals(labelKey))
724         this.nNOs = nNOs;
725       SB sb = new SB();
726       while (rd() != null && line.length() > 4 && " NA NB AO NH".indexOf(line.substring(1, 4)) < 0)
727         sb.append(line.substring(1));
728       //System.out.println(sb.length());
729       tokens = new String[sb.length() / 10];
730       for (int i = 0, pt = 0; i < tokens.length; i++, pt += 10)
731         tokens[i] = PT.rep(sb.substring2(pt, pt + 10), " ","");
732       map.put(key, tokens);
733     }
734     return map;
735   }
736 
setMap(Map<String, String[]> map, String labelKey, int nNOs, boolean doAll)737   private void setMap(Map<String, String[]> map, String labelKey, int nNOs, boolean doAll) {
738     String[] tokens = map.get((betaOnly ? "beta_" : "") + labelKey);
739     moData.put("nboLabelMap", map);
740     if (tokens == null) {
741       tokens = new String[nNOs];
742       for (int i = 0; i < nNOs; i++)
743         tokens[i] = nboType + (i + 1);
744       map.put(labelKey, tokens);
745       if (isOpenShell)
746         map.put("beta_" + labelKey, tokens);
747     }
748     if (!doAll)
749       return;
750     moData.put("nboLabels", tokens);
751     addBetaSet = (isOpenShell && !betaOnly && !is47File);
752     if (addBetaSet)
753       nOrbitals *= 2;
754     for (int i = 0; i < nOrbitals; i++)
755       setMO(new Hashtable<String, Object>());
756     setNboLabels(tokens, nNOs, orbitals, nOrbitals0, nboType);
757     if (addBetaSet) {
758       moData.put("firstBeta", Integer.valueOf(nNOs));
759       setNboLabels( map.get("beta_" + labelKey), nNOs, orbitals, nOrbitals0 + nNOs, nboType);
760     }
761     Lst<Object> structures = getStructureList();
762     NBOParser.getStructures46(map.get("NBO"), "alpha", structures, asc.ac);
763     NBOParser.getStructures46(map.get("beta_NBO"), "beta", structures, asc.ac);
764 
765   }
766 
getLabelKey(String labelKey)767   private static String getLabelKey(String labelKey) {
768     if (labelKey.startsWith("P"))
769       labelKey = labelKey.substring(1);
770     if (labelKey.equals("NLMO"))
771       labelKey = "NBO";
772     if (labelKey.equals("MO")) // no longer?
773       labelKey = "NO";
774     return labelKey;
775   }
776 
777   /**
778    * Called by setNBOType in IsoExt when use issues NBO TYPE xxx
779    *
780    * @param moData
781    * @param nboType
782    * @param vwr
783    * @return true if sucessful or false if required file is missing
784    */
785   @SuppressWarnings("unchecked")
readNBOCoefficients(Map<String, Object> moData, String nboType, Viewer vwr)786   public static boolean readNBOCoefficients(Map<String, Object> moData, String nboType,
787                                    Viewer vwr) {
788     int ext = JC.getNBOTypeFromName(nboType);
789     boolean isAO = nboType.equals("AO");
790     boolean isNBO = nboType.equals("NBO");
791     //boolean discardExtra = PT.isOneOf(nboType, ";NBO;NLMO;");
792     boolean hasNoBeta = PT.isOneOf(nboType, ";AO;PNAO;NAO;");
793     Map<String, String[]> map = (Map<String, String[]>) moData.get("nboLabelMap");
794     int nAOs = map.get("AO").length;
795     String labelKey = getLabelKey(nboType);
796     String[] nboLabels = map.get(labelKey);
797     if (nboLabels == null) {
798       // MO and NO need simple MO1 MO2 .. labels
799       nboLabels = new String[nAOs];
800       for (int i = 0; i < nAOs; i++)
801         nboLabels[i] = nboType + (i + 1);
802       labelKey = nboType;
803       map.put(labelKey, nboLabels);
804       if (!hasNoBeta)
805         map.put("beta_" + labelKey, nboLabels);
806     }
807     // It is possible for nAOs > nMOs. See, for example,
808     // http://nbo6.chem.wisc.edu/jmol_nborxiv/ketamine.47
809     int nMOs = nboLabels.length;
810     try {
811       Lst<Map<String, Object>> orbitals = (Lst<Map<String, Object>>) moData
812           .get(nboType + "_coefs");
813       if (orbitals == null) {
814         String data = null;
815         if (!isAO) {
816           String fileName = moData.get("nboRoot") + "." + ext;
817           if ((data = vwr.getFileAsString3(fileName, true, null)) == null
818               || data.indexOf("Exception:") >= 0)
819             return false;
820           addAuxFile(moData, fileName, null);
821           data = data.substring(data.indexOf("--\n") + 3).toLowerCase();
822           if (ext == 33)
823             data = data.substring(0, data.indexOf("--\n") + 3);
824         }
825         orbitals = (Lst<Map<String, Object>>) moData.get("mos");
826         Object dfCoefMaps = orbitals.get(0).get("dfCoefMaps");
827         orbitals = new Lst<Map<String, Object>>();
828         int len = 0;
829         int[] next = null;
830         int nOrbitals = nMOs;
831         if (!isAO) {
832           if (data.indexOf("alpha") >= 0) {
833             nOrbitals *= 2;
834             data = data.substring(data.indexOf("alpha") + 10); // "alpha spin"
835           }
836           len = data.length();
837           next = new int[1];
838         }
839         for (int i = nOrbitals; --i >= 0;) {
840           Map<String, Object> mo = new Hashtable<String, Object>();
841           orbitals.addLast(mo);
842           if (dfCoefMaps != null)
843             mo.put("dfCoefMaps", dfCoefMaps);
844         }
845         setNboLabels(nboLabels, nMOs, orbitals, 0, nboType);
846         for (int i = 0; i < nOrbitals; i++) {
847           if (!isAO && i == nMOs) {
848             if (isNBO)
849               getNBOOccupanciesStatic(orbitals, nMOs, 0, data, len, next);
850             nboLabels = map.get("beta_" + labelKey);
851             // always discarding extra here
852 
853             next[0] = (hasNoBeta ? 0 : data.indexOf("beta  spin") + 12);
854             // do skips, occupancy here
855             // must skip "beta  spin"
856           }
857           Map<String, Object> mo = orbitals.get(i);
858           float[] coefs = new float[nAOs];
859           if (isAO) {
860             coefs[i % nAOs] = 1;
861           } else if (i >= nAOs && hasNoBeta){
862             coefs = (float[]) orbitals.get(i % nAOs).get("coefficients");
863           } else {
864             for (int j = 0; j < nAOs; j++) {
865               coefs[j] = PT.parseFloatChecked(data, len, next, false);
866               if (Float.isNaN(coefs[j]))
867                 System.out.println("oops = IsoExt ");
868             }
869           }
870           mo.put("coefficients", coefs);
871         }
872         if (isNBO)
873           getNBOOccupanciesStatic(orbitals, nMOs, nOrbitals - nMOs, data, len, next);
874         moData.put(nboType + "_coefs", orbitals);
875       }
876       moData.put("nboType", nboType);
877       moData.put("nboLabels", nboLabels);
878       moData.put("mos", orbitals);
879     } catch (Exception e) {
880      e.printStackTrace();
881       return false;
882     }
883     return true;
884   }
885 
addAuxFile(Map<String, Object> moData, String fileName, Map<String, Object> htParams)886   private static void addAuxFile(Map<String, Object> moData, String fileName, Map<String, Object> htParams) {
887     @SuppressWarnings("unchecked")
888     Lst<String> auxFiles = (Lst<String>) moData.get("auxFiles");
889     if (auxFiles == null)
890       moData.put("auxFiles", auxFiles = new Lst<String>());
891     auxFiles.addLast(fileName);
892     if (htParams != null)
893       htParams.put("auxFiles", auxFiles);
894   }
895 
getNBOOccupanciesStatic(Lst<Map<String, Object>> orbitals, int nAOs, int pt, String data, int len, int[] next)896   private static void getNBOOccupanciesStatic(Lst<Map<String, Object>> orbitals,
897                                               int nAOs, int pt, String data,
898                                               int len, int[] next) {
899     float[] occupancies = new float[nAOs];
900     for (int j = 0; j < nAOs; j++)
901       occupancies[j] = PT.parseFloatChecked(data, len, next, false);
902     for (int i = 0; i < nAOs; i++) {
903       Map<String, Object> mo = orbitals.get(pt + i);
904       mo.put("occupancy", Float.valueOf(occupancies[i]));
905     }
906   }
907 
readMOs()908   private void readMOs() throws Exception {
909 
910     // .31 AO basis
911     // .32 PNAO no beta coef
912     // .33 NAO no beta coef ; adds orbital types
913     // .34 PNHO alpha+beta
914     // .35 NHO alpha+beta
915     // .36 PNBO alpha+beta
916     // .37 NBO alpha+extra+beta+extra
917     // .38 PNLMO alpha+beta
918     // .39 NLMO alpha+extra+beta+extra
919     // .40 MO alpha+beta
920     // .41 NO alpha+beta
921     // .42 (density matrix)
922     // .44 RNBO alpha+beta
923     // .45 PRNBO alpha+beta
924     // .46 (labels)
925     // .47 (coords)
926 
927     boolean isAO = nboType.equals("AO");
928     boolean isNBO = nboType.equals("NBO");
929     boolean discardExtra = PT.isOneOf(nboType, ";NBO;NLMO;");
930     boolean hasNoBeta = PT.isOneOf(nboType, ";AO;PNAO;NAO;");
931     nOrbitals0 = orbitals.size();
932     // get the labels
933     getFile46();
934     if (betaOnly) {
935       discardLinesUntilContains("BETA");
936       filterMO();
937     }
938     nOrbitals = orbitals.size();
939     if (nOrbitals == 0)
940       return;
941     line = null;
942     int pt = 0;
943     for (int i = nOrbitals0, n = nOrbitals0 + nOrbitals; i < n; i++, pt++) {
944       if (pt == nNOs) {
945         if (isNBO) {
946           readNBO37Occupancies(pt);
947         }
948         if (discardExtra)
949           discardLinesUntilContains2("BETA", "beta");
950       }
951       Map<String, Object> mo = orbitals.get(i);
952       float[] coefs = new float[nAOs];
953       if (isAO) {
954         coefs[pt % nAOs] = 1;
955       } else if (pt >= nNOs && hasNoBeta){
956         coefs = (float[]) orbitals.get(pt % nNOs).get("coefficients");
957       } else {
958         if (line == null) {
959           while (rd() != null && Float.isNaN(parseFloatStr(line))) {
960             filterMO(); //switch a/b
961           }
962         } else {
963           line = null;
964         }
965         fillFloatArray(line, 0, coefs);
966         line = null;
967       }
968       mo.put("coefficients", coefs);
969     }
970     if (isNBO)
971       readNBO37Occupancies(pt);
972     moData.put(nboType + "_coefs", orbitals);
973     setMOData(false);
974     moData.put("nboType", nboType);
975     Logger.info((orbitals.size() - nOrbitals0) + " orbitals read");
976 
977   }
978 
979   /**
980    * Read occupancies from .37 file. Called by readMOs.
981    * @param pt
982    * @throws Exception
983    */
readNBO37Occupancies(int pt)984   private void readNBO37Occupancies(int pt) throws Exception {
985     float[] occupancies = new float[nNOs];
986     fillFloatArray(null, 0, occupancies);
987     for (int i = 0; i < nNOs; i++) {
988       Map<String, Object> mo = orbitals.get(nOrbitals0 + pt - nNOs + i);
989       mo.put("occupancy", Float.valueOf(occupancies[i]));
990     }
991   }
992 
setNboLabels(String[] tokens, int nLabels, Lst<Map<String, Object>> orbitals, int nOrbitals0, String moType)993   public static void setNboLabels(String[] tokens, int nLabels,
994                            Lst<Map<String, Object>> orbitals, int nOrbitals0,
995                            String moType) {
996     boolean alphaBeta = (orbitals.size() == nLabels * 2);
997     boolean addOccupancy = !PT.isOneOf(moType, ";AO;NAO;PNAO;MO;NO;");
998     String ab = (!alphaBeta ? "" : nOrbitals0 == 0 ? " alpha" : " beta");
999     for (int j = 0; j < nLabels; j++) {
1000       Map<String, Object> mo = orbitals.get(j + nOrbitals0);
1001       String type = tokens[j];
1002       mo.put("type", moType + " " + type + ab);
1003       if (addOccupancy)
1004         mo.put(
1005             "occupancy",
1006             Float.valueOf(alphaBeta ? 1 : type.indexOf("*") >= 0
1007                 || type.indexOf("(ry)") >= 0 ? 0 : 2));
1008     }
1009   }
1010 
1011 }