1 /*
2  *  (c) 2004 Iowa State University
3  *      see the LICENSE file in the top level directory
4  */
5 
6 /* Most text file parsing routines
7 
8 	1/1998 - Modified the GAMESS log file parsing code for the new format BMB
9 	10/1998 - GAMESS log files also read in normal mode intensities BMB
10 	11/1998 - Added MDL MolFile input/export code BMB
11 	12/1998 - modified fragment parser routines BMB
12 	8/2000 - Fixed log file parser for new MCSCF orbital header and new basis set format
13 	1/2001 - Moved normal mode parser to Frame::ParseNormalModes BMB
14 	1/2001 - Added exception class UserCancel to more cleanly handle Progress aborts BMB
15 	2/2001 - Added check to allow user to disable the change of the creator type for text files BMB
16 	9/2001 - Fixed initial fragment parser to account for change in GAMESS log file output BMB
17 	11/2001 - ROHF logs now obtain the correct beta orbital occupation BMB
18 	11/2001 - OpenGAMESSDRC updated for the modified header in DRC output BMB
19 	3/2002 - Fixed bug when keywords appear in the Run Title BMB
20 	3/2002 - Redid ReadControlOptions to remove any order dependance among keywords BMB
21 	4/2002 - Modified initial fragment parser and fragment energy search BMB
22 	5/2004 - Modified atomic label parsing to fix conflict between Zr/ZN and fragments BMB
23 	10/2007 - Added import support for Molkel (.MKL) files ?/BMB/DMR
24 	6/2008 - Added import support for MOPAC input (.MOP) and archive (.ARC) files DMR
25 */
26 
27 #include "Files.h"
28 #include "Globals.h"
29 #include "GlobalExceptions.h"
30 #include "Progress.h"
31 #include "MoleculeData.h"
32 #include "Frame.h"
33 #include "Gradient.h"
34 #include "Internals.h"
35 #include "BasisSet.h"
36 #include "SurfaceTypes.h"
37 #include "BFiles.h"
38 #include "myFiles.h"
39 #ifndef __wxBuild__
40 #include "MyWindowClasses.h"
41 #include "MolDisplay.h"
42 #include "UtilWin.h"
43 #include "StdPrefsLib.h"
44 #else
45 #include "MolDisplayWin.h"
46 #endif
47 #include <iostream>
48 
49 //#include "mat2quat.h"
50 #include "InputData.h"
51 #include "Prefs.h"
52 #include <string.h>
53 #include <string>
54 #include <stdio.h>
55 #include <cctype>
56 #include <fstream>
57 #include <iostream>
58 //using namespace std;
59 #include <new>
60 
61 #if defined(WIN32)
62 #undef AddAtom
63 #endif
64 
65 extern WinPrefs * gPreferences;
66 
67 	//Local function definitions
68 bool ReadGVBOccupancy(BufferFile * Buffer, long NumPairOrbs, long MaxOrbs, float * Occupancy);
69 
WriteError(void)70 void FileError::WriteError(void) {
71 	if (Error == eofErr)
72 		wxLogMessage(_("Unexpected End Of File. Please check to make sure the file is complete."));
73 	else {
74 		wxString err;
75 		err.Printf(_("File System related error. Please report error number %d."), (int) Error);
76 		wxLogMessage(err);
77 	}
78 }
79 /**
80   * Adds support for opening GAMESS Input (.INP) files.
81   * @param Buffer A BufferFileObject that the .INP or .inp file is buffered
82   * into to make parsing the file easier.  See the BufferFile object for
83   * valid BufferFile operations.
84 */
OpenGAMESSInput(BufferFile * Buffer)85 long MolDisplayWin::OpenGAMESSInput(BufferFile * Buffer) {
86 	char	Line[kMaxLineLength], token[kMaxLineLength], DFTTYP[kMaxLineLength]="";
87 	int	scanerr;
88 	long	nAtoms;
89 	wxFileOffset StartPos, EndPos;
90 	bool	BasisFound=false, BoolTest, EndOfGroup;
91 
92 	ProgressInd->ChangeText("Reading GAMESS input file...");
93 
94 	MainData->InputOptions = new InputData;
95 
96 	EndOfGroup = false;
97 	if (Buffer->FindGroup("CONTRL")) {
98 		do {
99 			Buffer->GetLine(Line);
100 			if (ReadStringKeyword(Line, "SCFTYP", token))
101 				MainData->InputOptions->Control->SetSCFType(token);
102 			if (ReadStringKeyword(Line, "RUNTYP", token))
103 				MainData->InputOptions->Control->SetRunType(token);
104 			if (ReadLongKeyword(Line, "MPLEVL", &nAtoms))
105 				MainData->InputOptions->Control->SetMPLevel(nAtoms);
106 			if (ReadStringKeyword(Line, "CITYP", token))
107 				MainData->InputOptions->Control->SetCIType(token);
108 			if (ReadStringKeyword(Line, "COORD", token))
109 				MainData->InputOptions->Data->SetCoordType(token);
110 			if (ReadStringKeyword(Line, "UNITS", token))
111 				MainData->InputOptions->Data->SetUnits(token);
112 			if (ReadLongKeyword(Line, "ICHARG", &nAtoms))
113 				MainData->InputOptions->Control->SetCharge(nAtoms);
114 			if (ReadStringKeyword(Line, "LOCAL", token))
115 				MainData->InputOptions->Control->SetLocal(token);
116 			if (ReadLongKeyword(Line, "MULT", &nAtoms))
117 				MainData->InputOptions->Control->SetMultiplicity(nAtoms);
118 			if (ReadLongKeyword(Line, "MAXIT", &nAtoms))
119 				MainData->InputOptions->Control->SetMaxIt(nAtoms);
120 			if (ReadStringKeyword(Line, "ECP", token))
121 				MainData->InputOptions->Basis->SetECPPotential(token);
122 			if (ReadStringKeyword(Line, "PP", token))
123 				MainData->InputOptions->Basis->SetECPPotential(token);
124 			//look for the DFTTYP keyword, but we must allow for reading the DFT group
125 			//later before setting the functional since it depends on the method
126 			ReadStringKeyword(Line, "DFTTYP", DFTTYP);
127 			if (ReadLongKeyword(Line, "ISPHER", &nAtoms)) {
128 				if (nAtoms == 1)
129 					MainData->InputOptions->Control->UseSphericalHarmonics(true);
130 			}
131 			if (ReadLongKeyword(Line, "NOSYM", &nAtoms)) {
132 				MainData->InputOptions->Data->SetUseSym((nAtoms==0));
133 			}
134 
135 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
136 					//scan for multiple occurances of this group
137 				if (!Buffer->FindGroup("CONTRL")) EndOfGroup = true;
138 			}
139 		} while (!EndOfGroup);
140 	}
141 	Buffer->SetFilePos(0);	//restart search from beginning of file
142 	EndOfGroup = false;
143 	if (Buffer->FindGroup("BASIS")) {
144 		BasisFound = true;
145 		do {
146 			Buffer->GetLine(Line);
147 			if (ReadStringKeyword(Line, "GBASIS", token))
148 				MainData->InputOptions->Basis->SetBasis(token);
149 			if (ReadLongKeyword(Line, "NGAUSS", &nAtoms))
150 				MainData->InputOptions->Basis->SetNumGauss(nAtoms);
151 			if (ReadLongKeyword(Line, "NDFUNC", &nAtoms))
152 				MainData->InputOptions->Basis->SetNumDFuncs(nAtoms);
153 			if (ReadLongKeyword(Line, "NPFUNC", &nAtoms))
154 				MainData->InputOptions->Basis->SetNumPFuncs(nAtoms);
155 			if (ReadLongKeyword(Line, "NFFUNC", &nAtoms))
156 				MainData->InputOptions->Basis->SetNumFFuncs(nAtoms);
157 			if (ReadBooleanKeyword(Line, "DIFFS", &BoolTest))
158 				MainData->InputOptions->Basis->SetDiffuseS(BoolTest);
159 			if (ReadBooleanKeyword(Line, "DIFFSP", &BoolTest))
160 				MainData->InputOptions->Basis->SetDiffuseSP(BoolTest);
161 			if (ReadStringKeyword(Line, "POLAR", token))
162 				MainData->InputOptions->Basis->SetPolar(token);
163 
164 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
165 					//scan for multiple occurances of this group
166 				if (!Buffer->FindGroup("BASIS")) EndOfGroup = true;
167 			}
168 		} while (!EndOfGroup);
169 	}
170 	Buffer->SetFilePos(0);	//restart search from beginning of file
171 	EndOfGroup = false;
172 	if (Buffer->FindGroup("SYSTEM")) {
173 		do {
174 			Buffer->GetLine(Line);
175 			if (ReadLongKeyword(Line, "TIMLIM", &nAtoms))
176 				MainData->InputOptions->System->SetTimeLimit(nAtoms);
177 			if (ReadLongKeyword(Line, "MEMORY", &nAtoms))
178 				MainData->InputOptions->System->SetMemory(nAtoms);
179 			if (ReadLongKeyword(Line, "MEMDDI", &nAtoms))
180 				MainData->InputOptions->System->SetMemDDI(nAtoms);
181 			if (ReadBooleanKeyword(Line, "PARALL", &BoolTest))
182 				MainData->InputOptions->System->SetParallel(BoolTest);
183 			if (ReadLongKeyword(Line, "KDIAG", &nAtoms))
184 				MainData->InputOptions->System->SetDiag(nAtoms);
185 			if (ReadBooleanKeyword(Line, "COREFL", &BoolTest))
186 				MainData->InputOptions->System->SetCoreFlag(BoolTest);
187 			if (ReadStringKeyword(Line, "BALTYP", token)) {
188 				nAtoms = FindKeyWord(token, "NXTVAL", 6);
189 				if (nAtoms > -1)
190 					MainData->InputOptions->System->SetBalanceType(true);
191 			}
192 			if (ReadBooleanKeyword(Line, "XDR", &BoolTest))
193 				MainData->InputOptions->System->SetXDR(BoolTest);
194 
195 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
196 					//scan for multiple occurances of this group
197 				if (!Buffer->FindGroup("SYSTEM")) EndOfGroup = true;
198 			}
199 		} while (!EndOfGroup);
200 	}
201 	Buffer->SetFilePos(0);	//restart search from beginning of file
202 	EndOfGroup = false;
203 	if (Buffer->FindGroup("GUESS")) {
204 		if (!MainData->InputOptions->Guess) MainData->InputOptions->Guess = new GuessGroup;
205 		do {
206 			Buffer->GetLine(Line);
207 			if (ReadStringKeyword(Line, "GUESS", token))
208 				MainData->InputOptions->Guess->SetGuess(token);
209 			if (ReadLongKeyword(Line, "NORB", &nAtoms))
210 				MainData->InputOptions->Guess->SetNumOrbs(nAtoms);
211 			if (ReadBooleanKeyword(Line, "PRTMO", &BoolTest))
212 				MainData->InputOptions->Guess->SetPrintMO(BoolTest);
213 			if (ReadBooleanKeyword(Line, "MIX", &BoolTest))
214 				MainData->InputOptions->Guess->SetMix(BoolTest);
215 
216 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
217 														//scan for multiple occurances of this group
218 				if (!Buffer->FindGroup("GUESS")) EndOfGroup = true;
219 			}
220 		} while (!EndOfGroup);
221 	}
222 	Buffer->SetFilePos(0);	//restart search from beginning of file
223 	EndOfGroup = false;
224 	if (Buffer->FindGroup("SCF")) {
225 		if (!MainData->InputOptions->SCF) MainData->InputOptions->SCF = new SCFGroup;
226 		do {
227 			Buffer->GetLine(Line);
228 			if (ReadBooleanKeyword(Line, "DIRSCF", &BoolTest))
229 				MainData->InputOptions->SCF->SetDirectSCF(BoolTest);
230 			if (ReadBooleanKeyword(Line, "FDIFF", &BoolTest))
231 				MainData->InputOptions->SCF->SetFockDiff(BoolTest);
232 			if (ReadLongKeyword(Line, "NCONV", &nAtoms))
233 				MainData->InputOptions->SCF->SetConvergance(nAtoms);
234 			if (ReadBooleanKeyword(Line, "UHFNOS", &BoolTest))
235 				MainData->InputOptions->SCF->SetUHFNO(BoolTest);
236 			if (ReadLongKeyword(Line, "NCO", &nAtoms))
237 				MainData->InputOptions->SCF->SetGVBNumCoreOrbs(nAtoms);
238 			if (ReadLongKeyword(Line, "NPAIR", &nAtoms))
239 				MainData->InputOptions->SCF->SetGVBNumPairs(nAtoms);
240 			if (ReadLongKeyword(Line, "NSETO", &nAtoms))
241 				MainData->InputOptions->SCF->SetGVBNumOpenShells(nAtoms);
242 			if (ReadStringKeyword(Line, "NO(1)", token)) {
243 				int nchar = 0;
244 				int tlen = strlen(token);
245 				MainData->InputOptions->SCF->ClearGVBOpenShellDeg();
246 				while (nchar < tlen) {
247 					int nchar2=0;
248 					long shellDeg;
249 					if (sscanf(&(token[nchar]), "%ld%n", &shellDeg, &nchar2) == 1) {
250 						nchar += nchar2+1;
251 						MainData->InputOptions->SCF->AddGVBOpenShellDeg(shellDeg);
252 					} else
253 						break;
254 				}
255 			}
256 			if (ReadStringKeyword(Line, "NPREO(1)", token)) { //npreo should have 2 or 4 integer elements
257 				int nchar = 0;
258 				int tlen = strlen(token);
259 				int npreoValues=0;
260 				MainData->InputOptions->SCF->ClearNPREOArray();
261 				while (nchar < tlen) {
262 					int nchar2=0;
263 					long npreoVal;
264 					if (sscanf(&(token[nchar]), "%ld%n", &npreoVal, &nchar2) == 1) {
265 						nchar += nchar2+1;
266 						MainData->InputOptions->SCF->AddNPREOValue(npreoVal);
267 						npreoValues++;
268 					} else
269 						break;
270 				}
271 				if ((npreoValues!=2)&&(npreoValues!=4)) {
272 					wxLogMessage(_T("Unexpected number of NPREO values encountered!"));
273 				}
274 			}
275 
276 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
277 														//scan for multiple occurances of this group
278 				if (!Buffer->FindGroup("SCF")) EndOfGroup = true;
279 			}
280 		} while (!EndOfGroup);
281 	}
282 	Buffer->SetFilePos(0);	//restart search from beginning of file
283 	EndOfGroup = false;
284 	if (Buffer->FindGroup("MP2")) {
285 		if (!MainData->InputOptions->MP2) MainData->InputOptions->MP2 = new MP2Group;
286 		do {
287 			float tempf;
288 			Buffer->GetLine(Line);
289 			if (ReadLongKeyword(Line, "NACORE", &nAtoms))
290 				MainData->InputOptions->MP2->SetNumCoreElectrons(nAtoms);
291 			if (ReadBooleanKeyword(Line, "MP2PRP", &BoolTest))
292 				MainData->InputOptions->MP2->SetMP2Prop(BoolTest);
293 			if (ReadBooleanKeyword(Line, "LMOMP2", &BoolTest))
294 				MainData->InputOptions->MP2->SetLMOMP2(BoolTest);
295 			if (ReadLongKeyword(Line, "NWORD", &nAtoms))
296 				MainData->InputOptions->MP2->SetMemory(nAtoms);
297 			if (ReadLongKeyword(Line, "METHOD", &nAtoms))
298 				MainData->InputOptions->MP2->SetMethod(nAtoms);
299 			if (ReadStringKeyword(Line, "AOINTS", token))
300 				MainData->InputOptions->MP2->SetAOIntMethod(token);
301 			if (ReadFloatKeyword(Line, "CUTOFF", &tempf))
302 				MainData->InputOptions->MP2->SetIntCutoff(tempf);
303 
304 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
305 														//scan for multiple occurances of this group
306 				if (!Buffer->FindGroup("MP2")) EndOfGroup = true;
307 			}
308 		} while (!EndOfGroup);
309 	}
310 	Buffer->SetFilePos(0);	//restart search from beginning of file
311 	EndOfGroup = false;
312 	if (Buffer->FindGroup("FORCE")) {
313 		if (!MainData->InputOptions->Hessian) MainData->InputOptions->Hessian = new HessianGroup;
314 		do {
315 			float tempf;
316 			Buffer->GetLine(Line);
317 			if (ReadStringKeyword(Line, "METHOD", token))
318 				MainData->InputOptions->Hessian->SetAnalyticMethod(
319 						strncasecmp(token, "ANALYTIC", 8) == 0);
320 			if (ReadLongKeyword(Line, "NVIB", &nAtoms))
321 				MainData->InputOptions->Hessian->SetDoubleDiff(nAtoms==2);
322 			if (ReadFloatKeyword(Line, "VIBSIZ", &tempf))
323 				MainData->InputOptions->Hessian->SetDisplacementSize(tempf);
324 			if (ReadBooleanKeyword(Line, "PURIFY", &BoolTest))
325 				MainData->InputOptions->Hessian->SetPurify(BoolTest);
326 			if (ReadBooleanKeyword(Line, "PRTIFC", &BoolTest))
327 				MainData->InputOptions->Hessian->SetPrintFC(BoolTest);
328 			if (ReadBooleanKeyword(Line, "VIBANL", &BoolTest))
329 				MainData->InputOptions->Hessian->SetVibAnalysis(BoolTest);
330 			if (ReadFloatKeyword(Line, "SCLFAC", &tempf))
331 				MainData->InputOptions->Hessian->SetFreqScale(tempf);
332 
333 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
334 														//scan for multiple occurances of this group
335 				if (!Buffer->FindGroup("FORCE")) EndOfGroup = true;
336 			}
337 		} while (!EndOfGroup);
338 	}
339 	Buffer->SetFilePos(0);	//restart search from beginning of file
340 	EndOfGroup = false;
341 	if (Buffer->FindGroup("STATPT")) {
342 		if (!MainData->InputOptions->StatPt) MainData->InputOptions->StatPt = new StatPtGroup;
343 		do {
344 			float tempf;
345 			Buffer->GetLine(Line);
346 			if (ReadFloatKeyword(Line, "OPTTOL", &tempf))
347 				MainData->InputOptions->StatPt->SetOptConvergance(tempf);
348 			if (ReadLongKeyword(Line, "NSTEP", &nAtoms))
349 				MainData->InputOptions->StatPt->SetMaxSteps(nAtoms);
350 			if (ReadStringKeyword(Line, "METHOD", token))
351 				MainData->InputOptions->StatPt->SetMethod(token);
352 			if (ReadFloatKeyword(Line, "DXMAX", &tempf))
353 				MainData->InputOptions->StatPt->SetInitRadius(tempf);
354 			if (ReadFloatKeyword(Line, "TRMAX", &tempf))
355 				MainData->InputOptions->StatPt->SetMaxRadius(tempf);
356 			if (ReadFloatKeyword(Line, "TRMIN", &tempf))
357 				MainData->InputOptions->StatPt->SetMinRadius(tempf);
358 			if (ReadLongKeyword(Line, "IFOLOW", &nAtoms))
359 				MainData->InputOptions->StatPt->SetModeFollow(nAtoms);
360 			if (ReadBooleanKeyword(Line, "STPT", &BoolTest))
361 				MainData->InputOptions->StatPt->SetStatPoint(BoolTest);
362 			if (ReadFloatKeyword(Line, "STSTEP", &tempf))
363 				MainData->InputOptions->StatPt->SetStatJump(tempf);
364 			if (ReadLongKeyword(Line, "IHREP", &nAtoms))
365 				MainData->InputOptions->StatPt->SetHessRecalcInterval(nAtoms);
366 			if (ReadLongKeyword(Line, "NPRT", &nAtoms))
367 				MainData->InputOptions->StatPt->SetAlwaysPrintOrbs(nAtoms==1);
368 			if (ReadStringKeyword(Line, "HESS", token))
369 				MainData->InputOptions->StatPt->SetHessMethod(token);
370 
371 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
372 														//scan for multiple occurances of this group
373 				if (!Buffer->FindGroup("STATPT")) EndOfGroup = true;
374 			}
375 		} while (!EndOfGroup);
376 	}
377 	Buffer->SetFilePos(0);	//restart search from beginning of file
378 	EndOfGroup = false;
379 	if (Buffer->FindGroup("DFT")) {
380 		do {
381 			Buffer->GetLine(Line);
382 			if (ReadStringKeyword(Line, "METHOD", token))
383 				MainData->InputOptions->DFT.SetMethodGrid(
384 					   strncasecmp(token, "GRIDFREE", 8) != 0);
385 
386 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
387 														//scan for multiple occurances of this group
388 				if (!Buffer->FindGroup("DFT")) EndOfGroup = true;
389 			}
390 		} while (!EndOfGroup);
391 	}
392 	//Now can save the functional that is read from the contrl group
393 	if (strlen(DFTTYP) > 0) {
394 		MainData->InputOptions->DFT.SetFunctional(DFTTYP);
395 		if (MainData->InputOptions->DFT.GetFunctional() > 0)
396 			MainData->InputOptions->Control->UseDFT(true);
397 		else
398 			wxLogMessage(_("Unknown DFTTYP detected, ignored."));
399 	}
400 
401 	Buffer->SetFilePos(0);	//restart search from beginning of file
402 	EndOfGroup = false;
403 	if (Buffer->FindGroup("FMO")) {
404 		MainData->InputOptions->FMO.FMOActive(true);
405 		do {
406 			Buffer->GetLine(Line);
407 			if (ReadLongKeyword(Line, "NFRAG", &nAtoms))
408 				MainData->InputOptions->FMO.SetNumberFragments(nAtoms);
409 			//The rest of the items in this group depend on the # of atoms so parse them after the coordinates
410 
411 			if (-1 < FindKeyWord(Line, "$END", 4)) {	//End of this group
412 				//scan for multiple occurances of this group
413 				if (!Buffer->FindGroup("FMO")) EndOfGroup = true;
414 			}
415 		} while (!EndOfGroup);
416 	}
417 	float unitConversion = 1.0f;
418 	if (MainData->InputOptions->Data->GetUnits()) unitConversion = kBohr2AngConversion;
419 	Buffer->SetFilePos(0);	//restart search from beginning of file
420 	Frame * lFrame = MainData->GetCurrentFramePtr();
421 	if (Buffer->FindGroup("DATA")) {
422 		Buffer->SkipnLines(1);
423 		Buffer->GetLine(Line);	//1st line is a title line
424 		MainData->InputOptions->Data->SetTitle(Line, strlen(Line));
425 		Buffer->GetLine(Line);	//2nd line contains the point group
426 		if (FindKeyWord(Line, "$END", 4) < 0) {	// Make sure we're not at $END
427 			scanerr = sscanf(Line, "%s %ld", token, &nAtoms);
428 			MainData->InputOptions->Data->SetPointGroup(token);
429 			if (scanerr == 2)	//if a number was read in set the order
430 				MainData->InputOptions->Data->SetPointGroupOrder(nAtoms);
431 				//If !C1 then skip the blank line well I guess rarely it isn't blank...
432 			if (-1 == FindKeyWord(token, "C1", 2)) Buffer->SkipnLines(1);
433 			StartPos = Buffer->GetFilePos();
434 			if (!Buffer->LocateKeyWord("$END", 4)) throw DataError();
435 			EndPos = Buffer->GetFilePos() - 1;
436 			Buffer->SetFilePos(StartPos);
437 			nAtoms = Buffer->GetNumLines(EndPos - StartPos);
438 			if (MainData->InputOptions->FMO.IsFMOActive()) nAtoms=0;	//FMO coordinates are in $FMOXYZ
439 			if (nAtoms > 0) {
440 				if (MainData->InputOptions->Data->GetCoordType() <= CartesianCoordType) {
441 					if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
442 					while (Buffer->GetFilePos() < EndPos) {
443 							CPoint3D	pos;
444 							float		AtomType=-1;
445 						Buffer->GetLine(Line);
446 						if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
447 						{ throw UserCancel();}
448 						pos.x = pos.y = pos.z = 0.0f;
449 						int linecount = sscanf(Line, "%s %f %f %f %f", token, &AtomType, &pos.x, &pos.y, &pos.z);
450 						pos *= unitConversion;
451 						if ((linecount!=5)||(AtomType<1)) {
452 							wxString msg;
453 							msg.Printf(_("Warning: Parsing issue with the line: %s"), Line);
454 							wxLogMessage(msg);
455 						}
456 						lFrame->AddAtom((long) AtomType, pos);
457 						StartPos = Buffer->FindBlankLine();
458 						if ((StartPos <= EndPos)&&(StartPos>-1)) {	//basis set is inlined in $DATA
459 							Buffer->SetFilePos(StartPos);	//just skip over it
460 							Buffer->SkipnLines(1);
461 						}
462 					}
463 					if (((MainData->InputOptions->Data->GetCoordType() == UniqueCoordType)||
464 						 (MainData->InputOptions->Data->GetCoordType() == 0))&&
465 						(MainData->InputOptions->Data->GetPointGroup()>GAMESS_C1)&&
466 						(lFrame->GetNumAtoms() > 0)) {
467 						//Generate symmetry dependant atoms
468 						for (int i=0; i<lFrame->GetNumAtoms(); ++i)
469 							lFrame->Atoms[i].IsSymmetryUnique(true);
470 						MainData->GenerateSymmetryDependentAtoms();
471 					}
472 				} else if (MainData->InputOptions->Data->GetCoordType() <= ZMTCoordType) {
473 					wxFileOffset bPos = Buffer->FindBlankLine();
474 					if ((bPos > 0)&&(bPos < EndPos)) {
475 						nAtoms = Buffer->GetNumLines(bPos - StartPos);
476 					}
477 					if (nAtoms > 0) {
478 						if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
479 					} else {
480 						wxLogMessage(_("No atoms found in your $DATA group!"));
481 						throw DataError();
482 					}
483 					MainData->ParseZMatrix(Buffer, nAtoms, Prefs);
484 				} else if (MainData->InputOptions->Data->GetCoordType() <= ZMTMPCCoordType) {
485 					if (nAtoms > 0) {
486 						if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
487 					} else {
488 						wxLogMessage(_("No atoms found in your $DATA group!"));
489 						throw DataError();
490 					}
491 					MainData->ParseMOPACZMatrix(Buffer, nAtoms, Prefs);
492 				}
493 				if (Prefs->GetAutoBond())	//setup bonds, if needed
494 					lFrame->SetBonds(Prefs, false, ProgressInd);
495 			}
496 		}
497 	}
498 	Buffer->SetFilePos(0);	//restart search from beginning of file
499 	if (MainData->InputOptions->FMO.IsFMOActive() && Buffer->FindGroup("FMOXYZ")) {
500 		Buffer->SkipnLines(1);
501 		StartPos = Buffer->GetFilePos();
502 		if (!Buffer->LocateKeyWord("$END", 4)) throw DataError();
503 		EndPos = Buffer->GetFilePos() - 1;
504 		Buffer->SetFilePos(StartPos);
505 		nAtoms = Buffer->GetNumLines(EndPos - StartPos);
506 		if (nAtoms > 0) {
507 			ProgressInd->ChangeText("Reading FMO Coordinates...");
508 			if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
509 			while (Buffer->GetFilePos() < EndPos) {
510 				CPoint3D	pos;
511 				float		AtomType=-1;
512 				char		token2[kMaxLineLength];
513 				Buffer->GetLine(Line);
514 				if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
515 				{ throw UserCancel();}
516 				pos.x = pos.y = pos.z = 0.0f;
517 				//The form is token (skip) atomic charge or symbol, x y z coords
518 				int linecount = sscanf(Line, "%s %s %f %f %f", token, token2, &pos.x, &pos.y, &pos.z);
519 				int inum = 1;
520 				if (isdigit(token2[0])) inum = sscanf(token2, "%f", &AtomType);
521 				else AtomType = SetAtomType((unsigned char *) token2);
522 				if ((linecount!=5)||(AtomType<1)) {
523 					wxString msg;
524 					msg.Printf(_("Warning: Parsing issue with the line: %s"), Line);
525 					wxLogMessage(msg);
526 				}
527 				pos *= unitConversion;
528 				lFrame->AddAtom((long) AtomType, pos);
529 			}
530 			if (Prefs->GetAutoBond()) {	//setup bonds, if needed
531 				lFrame->SetBonds(Prefs, false, ProgressInd);
532 			}
533 		}
534 	}
535 	Buffer->SetFilePos(0);	//restart search from beginning of file
536 	if (Buffer->FindGroup("EFRAG")) {
537 		Buffer->SkipnLines(1);
538 		Buffer->GetLine(Line);	//1st line has all of the options
539 		if (ReadStringKeyword(Line, "METHOD", token)) {
540 			MainData->InputOptions->EFP.SetCoordinatesType(token);
541 		}
542 		if (ReadStringKeyword(Line, "POLMETHD", token)) {
543 			MainData->InputOptions->EFP.SetPolMethod(token);
544 		}
545 		if (ReadStringKeyword(Line, "POSITION", token)) {
546 			MainData->InputOptions->EFP.SetPositionType(token);
547 		}
548 		long tag;
549 		if (ReadLongKeyword(Line, "COORD", &tag))
550 			MainData->InputOptions->EFP.SetMaxMOs(tag);
551 		if (ReadLongKeyword(Line, "MXBF", &tag))
552 			MainData->InputOptions->EFP.SetMaxBasisFunctions(tag);
553 		if (ReadLongKeyword(Line, "NBUFFMO", &tag))
554 			MainData->InputOptions->EFP.SetNumBufferMOs(tag);
555 
556 		wxFileOffset former_pos, start_pos, found_it;
557 		//Now tackle the individual fragment definitions
558 		//These should consist of 4 line blocks of Fragname=xxx followed by three atom lines
559 		//For now I am only going to deal with cartesian coordinates
560 		if (MainData->InputOptions->EFP.UseCartesianCoordinates()) {
561 			mpAtom *atm;
562 			CPoint3D dst_locs[3];
563 			CPoint3D pos;
564 			int fstart;
565 			int match[3] = {0, 0, 0};
566 			CPoint3D src_locs[3];
567 			std::string labels[3];
568 			long fragNum;
569 			int i;
570 			CPoint3D new_pos;
571 			CPoint3D rot_pos;
572 			CPoint3D curr_pos;
573 			CPoint3D orig;
574 			Matrix4D vec2vec;
575 			CPoint3D src_vec;
576 			CPoint3D dst_vec;
577 			CPoint3D dst_vec2;
578 			CPoint3D dst_norm;
579 			CPoint3D mid_norm;
580 			CPoint3D mid_vec1, mid_vec2;
581 			float dot;
582 
583 			Buffer->GetLine(Line);
584 			while (ReadStringKeyword(Line, "FRAGNAME", token)) {
585 				if (!strcasecmp(token, "H2ORHF") || !strcasecmp(token, "H2ODFT")) {	//builtin EFP1 style is limited to H2O with known labels
586 					MainData->FragmentNames.push_back(std::string(token));
587 					long fragNum = MainData->FragmentNames.size();
588 					CPoint3D	pos;
589 					int		AtomType;
590 					for (int i=0; i<3; ++i) {
591 						AtomType = -1;
592 						Buffer->GetLine(Line);
593 						//lines have format "label x, y, z"
594 						sscanf(Line, "%s %f %f %f", token, &pos.x, &pos.y, &pos.z);
595 						pos *= unitConversion;
596 						if (!strcasecmp(token, "O1")) AtomType = 8;
597 						else if (!strcasecmp(token, "H2")||!strcasecmp(token, "H3")) AtomType = 1;
598 						if (AtomType > 0) {
599 							mpAtom * atm = lFrame->AddAtom(AtomType, pos);
600 							atm->SetFragmentNumber(fragNum);
601 						}
602 					}
603 				}
604 
605 				// Custom fragment type.
606 				else {
607 
608 					// Read the three atoms that setup the fragment.  These
609 					// should be in angstroms.
610 					MainData->FragmentNames.push_back(std::string(token));
611 					fragNum = MainData->FragmentNames.size();
612 					char label[kMaxLineLength];
613 					for (i = 0; i < 3; ++i) {
614 						Buffer->GetLine(Line);
615 						sscanf(Line, "%s %f %f %f", label,
616 							   &(dst_locs[i].x), &(dst_locs[i].y),
617 							   &(dst_locs[i].z));
618 						dst_locs[i] *= unitConversion;
619 						labels[i] = label;
620 						/* std::cout << "Line: " << Line << std::endl; */
621 						/* atm = lFrame->AddAtom(1, dst_locs[i]); */
622 						/* atm->SetFragmentNumber(fragNum); */
623 					}
624 
625 					// See if the fragment template has been loaded in already.
626 					// If so, go ahead and parse it.
627 					std::map<std::string, EFrag>::iterator frag;
628 					frag = MainData->efrags.find(token);
629 					if (frag == MainData->efrags.end()) {
630 						// save current position
631 						former_pos = Buffer->GetFilePos();
632 
633 						// look for fragment definition
634 						found_it = Buffer->FindGroup(token);
635 						if (!found_it) {
636 							std::cout << "didn't find group " << token << std::endl;
637 							wxString msg;
638 							msg.Printf(_("Unable to locate correct EFP2 fragment definition group named %s"), token);
639 							wxLogMessage(msg);
640 							throw DataError();
641 						}
642 						start_pos = Buffer->GetFilePos();
643 
644 						// get definition text
645 						std::string running_text;
646 						Buffer->GetLine(Line);
647 						while (FindKeyWord(Line, "$END", 4) < 0) {
648 							running_text += Line;
649 							running_text += "\n";
650 							Buffer->GetLine(Line);
651 						}
652 						running_text += Line;
653 
654 						// restore file position
655 						Buffer->SetFilePos(former_pos);
656 
657 						// get text
658 						MainData->efrags.insert(std::pair<std::string, EFrag>(token, EFrag(running_text)));
659 						frag = MainData->efrags.find(token);
660 					}
661 
662 					fstart = lFrame->NumAtoms;
663 					const std::vector<EFragAtom>& labeled_atoms = frag->second.GetAtoms();
664 					std::vector<EFragAtom>::const_iterator efrag_atom;
665 
666 					for (efrag_atom = labeled_atoms.begin();
667 						 efrag_atom != labeled_atoms.end();
668 						 ++efrag_atom) {
669 
670 						if (efrag_atom->GetLabel().compare(labels[0]) == 0) {
671 							match[0] = lFrame->NumAtoms;
672 							src_locs[0] = efrag_atom->GetCoords();
673 						} else if (efrag_atom->GetLabel().compare(labels[1]) == 0) {
674 							match[1] = lFrame->NumAtoms;
675 							src_locs[1] = efrag_atom->GetCoords();
676 						} else if (efrag_atom->GetLabel().compare(labels[2]) == 0) {
677 							match[2] = lFrame->NumAtoms;
678 							src_locs[2] = efrag_atom->GetCoords();
679 						}
680 
681 						atm = lFrame->AddAtom(efrag_atom->GetAtomicNumber(),
682 											  efrag_atom->GetCoords());
683 						atm->SetFragmentNumber(fragNum);
684 					}
685 
686 					// We first find a rotation that one will align a vector
687 					// in the fragment template to the corresponding vector in
688 					// the destination space.
689 					dst_vec = dst_locs[1] - dst_locs[0];
690 					Normalize3D(&dst_vec);
691 
692 					src_vec = src_locs[1] - src_locs[0];
693 					Normalize3D(&src_vec);
694 
695 					SetRotationMatrix(vec2vec, &src_vec, &dst_vec);
696 
697 					// The common vector now serves as an axis of rotation.  We
698 					// need to rotate the fragment template plane so that it
699 					// coincides with the destination plane.  The angle of rotation
700 					// can be determined by the angle between the two planes'
701 					// normals.
702 					lFrame->GetAtomPosition(match[0], orig);
703 					Rotate3DOffset(vec2vec, src_locs[1] - orig, &mid_vec1);
704 					Rotate3DOffset(vec2vec, src_locs[2] - orig, &mid_vec2);
705 					UnitCrossProduct3D(&mid_vec1, &mid_vec2, &mid_norm);
706 
707 					dst_vec2 = dst_locs[2] - dst_locs[0];
708 					UnitCrossProduct3D(&dst_vec, &dst_vec2, &dst_norm);
709 
710 					Matrix4D tri2tri;
711 					dot = DotProduct3D(&mid_norm, &dst_norm);
712 
713 					// Technically, the axis of rotation (the aligned vector)
714 					// might be facing a different direction than we think it
715 					// is. To be consistent, we instead use the axis that is
716 					// normal to both planes' normals. It points in the same
717 					// or opposite direction as dst_vec.
718 					CPoint3D axis;
719 					UnitCrossProduct3D(&mid_norm, &dst_norm, &axis);
720 					RotateAroundAxis(tri2tri, axis, acos(dot) * 180.0 / kPi);
721 
722 					// We concatenate the two rotation matrices.
723 					Matrix4D transform;
724 					MultiplyMatrix(vec2vec, tri2tri, transform);
725 
726 					// Okay, for each atom we added for this fragment instance,
727 					// we move all fragment atoms into destination space. We
728 					// translate to make the base fragment atom the origin and
729 					// then rotate to align the fragment with the destination
730 					// plane, and then translate by the base destination atom.
731 					for (long i = fstart; i < lFrame->NumAtoms; ++i) {
732 						lFrame->GetAtomPosition(i, curr_pos);
733 						new_pos = curr_pos - orig;
734 						Rotate3DOffset(transform, new_pos, &rot_pos);
735 						new_pos = rot_pos + dst_locs[0];
736 						lFrame->SetAtomPosition(i, new_pos);
737 					}
738 				}
739 
740 				Buffer->GetLine(Line);
741 					//At some point GAMESS started printing out all fragment atoms instead of the first three,
742 					//since the code above has already properly obtained the full fixed fragment geometry just
743 					//skip the user provided set which could be incorrect.
744 				while (((0>FindKeyWord(Line, "FRAGNAME", 8))&&(0>FindKeyWord(Line, "$END", 4)))) {
745 					Buffer->GetLine(Line);
746 				}
747 			}
748 		}
749 
750 		lFrame->SetBonds(Prefs, true, NULL, false);
751 
752 	}
753 	if (MainData->InputOptions->FMO.IsFMOActive()) {
754 		Buffer->SetFilePos(0);	//restart search from beginning of file
755 		if (Buffer->FindGroup("FMO")) {
756 			wxFileOffset startFMO = Buffer->GetFilePos();
757 			wxFileOffset EndOfGroup;
758 			if (Buffer->LocateKeyWord("$END", 4)) {
759 				EndOfGroup = Buffer->GetFilePos();
760 			} else {
761 				EndOfGroup = -1;
762 				wxLogMessage(_("The FMO group does not have proper termination."));
763 			}
764 			Buffer->SetFilePos(startFMO);
765 			//Parse the items that depend on the # of atoms
766 			//The rest of the items in this group depend on the # of atoms so parse them after the coordinates
767 
768 			if (Buffer->LocateKeyWord("INDAT", 5, EndOfGroup)) {
769 				MainData->ParseFMOIds(Buffer, lFrame->GetNumAtoms(), EndOfGroup);
770 			}
771 		}
772 	}
773 	return 1;
774 }
775 /**
776  * Parses the MDL Mol Format (just atoms).
777  * @param Buffer A BufferFileObject which the MDL mol file is buffered into
778  * @return Returns 1 upon open success or 0 on error or failure to open
779  */
OpenMDLMolFile(BufferFile * Buffer)780 long MolDisplayWin::OpenMDLMolFile(BufferFile * Buffer) {
781 	char Line[kMaxLineLength], partA[16], partB[16], partC[16];
782 	long	nAtoms, nBonds;
783 	short	scanerr;
784 // parts of this are a bit gross since the MDL format is fixed format without
785 // whitespace in between the fields.
786 
787 	ProgressInd->ChangeText("Reading MDL MolFile...");
788 	Frame * lFrame = MainData->cFrame;
789 
790 	Buffer->GetLine(Line);	//The first Line is a comment/compound name line
791 	MainData->SetDescription(Line);
792 	Buffer->GetLine(Line);	//The second line can (optionally) contain program and energy data
793 	long LineLength = strlen(Line);
794 	if (LineLength > 34) {
795 		double	energy;
796 		if (1==sscanf(&(Line[34]), "%lf", &energy))
797 			lFrame->Energy = energy;
798 	}
799 	Buffer->SkipnLines(1);	//third line for comments (unused here)
800 	Buffer->GetLine(Line);	//atom/bond counts
801 	partA[0] = Line[0]; partA[1] = Line[1]; partA[2]=Line[2]; partA[3]='\0';
802 	partB[0] = Line[3]; partB[1] = Line[4]; partB[2]=Line[5]; partB[3]='\0';
803 	scanerr = sscanf(partA, "%3ld", &nAtoms);
804 	scanerr += sscanf(partB, "%3ld", &nBonds);
805 	if (scanerr!=2 || nAtoms <= 0) {
806 		wxLogMessage(_("Error parsing MDL MolFile."));
807 		throw DataError();
808 	}
809 	MainData->SetupFrameMemory(nAtoms, nBonds);
810 		long i;
811 	for (i=0; i<nAtoms; ++i) {
812 			CPoint3D tPt;
813 			char	token[5];
814 				//Atom line format:  "%10f%10f%10f %3s"
815 		Buffer->GetLine(Line);
816 		for (int i=0; i<10; ++i) partA[i] = Line[i];
817 		partA[10] = '\0';
818 		scanerr = sscanf(partA, "%10f", &tPt.x);
819 		for (int i=0; i<10; ++i) partB[i] = Line[i+10];
820 		partB[10] = '\0';
821 		scanerr += sscanf(partB, "%10f", &tPt.y);
822 		for (int i=0; i<10; ++i) partC[i] = Line[i+20];
823 		partC[10] = '\0';
824 		scanerr += sscanf(partC, "%10f", &tPt.z);
825 		scanerr += sscanf(&(Line[31]), "%3s", token);
826 		if (scanerr == 4) {
827 				long AtomType;
828 			AtomType = SetAtomType((unsigned char *) token);
829 			lFrame->AddAtom(AtomType, tPt);
830 		} else break;
831 	}
832 	if (i==nAtoms && nBonds > 0) {	//Read in bonds if all atom were read successfully
833 		for (i=0; i<nBonds; ++i) {
834 			long type, a1, a2;
835 			Buffer->GetLine(Line);	//Bonds format: "%3ld%3ld%3ld"
836 			partA[0] = Line[0]; partA[1] = Line[1]; partA[2]=Line[2]; partA[3]='\0';
837 			partB[0] = Line[3]; partB[1] = Line[4]; partB[2]=Line[5]; partB[3]='\0';
838 			partC[0] = Line[6]; partC[1] = Line[7]; partC[2]=Line[8]; partC[3]='\0';
839 			scanerr = sscanf(partA, "%3ld", &a1);
840 			scanerr += sscanf(partB, "%3ld", &a2);
841 			scanerr += sscanf(partC, "%3ld", &type);
842 			if (scanerr == 3 && a1>0 && a2>0 && a1<=nAtoms && a2<=nAtoms && a1!=a2) {
843 				lFrame->AddBond(a1-1, a2-1);
844 				if (type>3) type = 1;
845 				if (type<1) type = 1;
846 				lFrame->SetBondOrder(lFrame->GetNumBonds()-1, (BondOrder) type);
847 			} else break;
848 		}
849 	}
850 
851 	return 1;
852 }
853 /**
854  * Parses the Protein Databank Format (just atoms).
855  * @param Buffer A BufferFileObject which the PDB file is buffered into
856  * @return Returns 1 upon open success or 0 on error or failure to open
857  */
OpenPDBFile(BufferFile * Buffer)858 long MolDisplayWin::OpenPDBFile(BufferFile * Buffer) {
859 	char Line[kMaxLineLength];
860 	long	nAtoms, nModels = 0;
861 	short	scanerr;
862 
863 	ProgressInd->ChangeText("Reading PDB file...");
864 	Frame * lFrame = MainData->cFrame;
865 		//First scan the file to determine the atoms
866 	nAtoms = 0;
867 	while (Buffer->GetFilePos() < Buffer->GetFileLength()) {
868 		Buffer->GetLine(Line);
869 		if (0==FindKeyWord(Line, "MODEL", 5)) ++nModels;
870 		if (0==FindKeyWord(Line, "ATOM", 4)) ++nAtoms;
871 		if (0==FindKeyWord(Line, "HETATM", 4)) ++nAtoms;
872 	}
873 	Buffer->SetFilePos(0);
874 	if (nAtoms>0) {
875 			//allocate memory for the atoms
876 		if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
877 
878 			CPoint3D Pos;
879 			long AtomType, LinePos;
880 		nAtoms = 0;
881 			//Scan for Atom or hetAtm lines
882 			//Format is: a6,i5,2x,a4,a3,2x,i4,4x,3F8.3,2f6.2
883 			//1 -  6        Record name   "ATOM  "
884 			//7 - 11        Integer       serial       Atom  serial number.
885 			//13 - 16        Atom          name         Atom name.
886 			//17             Character     altLoc       Alternate location indicator.
887 			//18 - 20        Residue name  resName      Residue name.
888 			//22             Character     chainID      Chain identifier.
889 			//23 - 26        Integer       resSeq       Residue sequence number.
890 			//27             AChar         iCode        Code for insertion of residues.
891 			//31 - 38        Real(8.3)     x            Orthogonal coordinates for X in Angstroms.
892 			//39 - 46        Real(8.3)     y            Orthogonal coordinates for Y in Angstroms.
893 			//47 - 54        Real(8.3)     z            Orthogonal coordinates for Z in Angstroms.
894 			//55 - 60        Real(6.2)     occupancy    Occupancy.
895 			//61 - 66        Real(6.2)     tempFactor   Temperature  factor.
896 			//77 - 78        LString(2)    element      Element symbol, right-justified.
897 			//79 - 80        LString(2)    charge       Charge  on the atom.
898 			//This routine only parses simple pdb files. It probably gets many files atom types wrong
899 			//and it always reads in all atoms including duplicates
900 		while (Buffer->GetFilePos() < Buffer->GetFileLength()) {
901 			Buffer->GetLine(Line);
902 			int LineLength = strlen(Line);
903 				//Only read in the first model in a file
904 			if (0==FindKeyWord(Line, "ENDMDL", 6)) {
905 				bool modelFound=false;
906 				while (Buffer->GetFilePos() < Buffer->GetFileLength()) {
907 					Buffer->GetLine(Line);
908 					if (0==FindKeyWord(Line, "MODEL", 5)) {
909 						modelFound = true;
910 						break;
911 					}
912 				}
913 				if (!modelFound) break;
914 				if (Prefs->GetAutoBond())	//setup bonds, if needed
915 					lFrame->SetBonds(Prefs, false, ProgressInd);
916 				lFrame = MainData->AddFrame(lFrame->GetNumAtoms(), lFrame->GetNumBonds());
917 			}
918 			long atomTest = FindKeyWord(Line, "ATOM", 4);
919 			long HetTest = FindKeyWord(Line, "HETATM", 4);
920 			if ((0==atomTest)||(0==HetTest)) {
921 				AtomType = -1;
922 				if (LineLength >= 78) {	//Use the element symbol if present
923 					unsigned char label[4];
924 					bool test=false;
925 					if (isalpha(Line[76])) {
926 						label[0] = Line[76];
927 						label[1] = Line[77];
928 						label[2] = '\0';
929 						test = true;
930 					} else if (isalpha(Line[77])) {
931 						label[0] = Line[77];
932 						label[1] = '\0';
933 						test = true;
934 					}
935 					if (test)
936 						AtomType = SetAtomType(label);
937 				}
938 				if (AtomType <= 0)	{//If no symbol attempt to use the "name"
939 					LinePos = 13;
940 					if (atomTest==0) Line[14] = ' ';
941 					else if (Line[12] != ' ') LinePos = 12;
942 					AtomType = SetAtomType((unsigned char *) &(Line[LinePos]));
943 				}
944 				if (AtomType > 0) {
945 					scanerr = sscanf(&(Line[30]), "%8e%8e%8e", &(Pos.x), &(Pos.y), &(Pos.z));
946 					if (scanerr == 3) {
947 						lFrame->AddAtom(AtomType, Pos);
948 						MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.x));
949 						MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.y));
950 						MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.z));
951 						++nAtoms;
952 					}
953 				}
954 			}
955 		}
956 		if (Prefs->GetAutoBond())	//setup bonds, if needed
957 			lFrame->SetBonds(Prefs, false, ProgressInd);
958 	}
959 	return 1;
960 }
961 
962 /**
963   * Adds support for opening the MKL file extension.
964   * @param Buffer A BufferFileObject which the .MKL file is buffered into
965   * to make parsing the file easier.  See the BufferFile object for valid
966   * BufferFile operations.
967   * @return Returns 1 upon open success or 0 on error or failure to open
968 */
OpenMKLFile(BufferFile * Buffer)969 long MolDisplayWin::OpenMKLFile(BufferFile * Buffer){
970 	// buffer line for text to be scanned while parsing
971 	char Line[kMaxLineLength];
972 	// number of atomes in the structure described by this file
973 	long nAtoms = 0;
974 	// Placeholders for traversing file sections in Buffer
975 	wxFileOffset startOfSection = 0;
976 	wxFileOffset endOfSection = -1;
977 	// counters for line-by-line text input:
978 	// # of tokens sucessfully read in a sscanf call, # bytes total in line,
979 	// current position in line, and the # of bytes read through one sscanf call
980 	int scanCount, lineBytes, bytesRead, bytesConsumed;
981 	// flags to indicate $KEYWORD section completion and order-of-dependency
982 	// following.  Also used to enforce data parsing in-order (doesn't guarantee
983 	// that the file's data was in-order, only that it is parsed in-order)
984 	bool BasisDone = false, CoefAlphaDone = false, CoefBetaDone = false;
985 	bool OccAlphaDone = false, OccBetaDone = false;
986 
987 	ProgressInd->ChangeText("Reading MKL file...");
988 	Frame * lFrame = MainData->cFrame;
989 	// first scan the file to determine the number of atoms
990 	//look throughout the file for the $COORD or the last $$
991 	//and count the number of lines between the two keywords
992 	//(each line is another atom in the molecule)
993 	while (Buffer->GetFilePos() < Buffer->GetFileLength()
994 			&& Buffer->LocateKeyWord("$COORD", 6)) {
995 		Buffer->SkipnLines(1); // skip $COORD line
996 		startOfSection = Buffer->GetFilePos();
997 		if (Buffer->LocateKeyWord("$END", 4)) {
998 			endOfSection = Buffer->GetFilePos();
999 			Buffer->SetFilePos(startOfSection);
1000 		} else endOfSection = Buffer->GetFileSize();
1001 		while (Buffer->GetFilePos() < endOfSection) {
1002 			wxFileOffset startOfFramePos = Buffer->GetFilePos();
1003 			wxFileOffset endOfFramePos = endOfSection;
1004 			//individual geometries are separated by the "$$" line
1005 			if (Buffer->LocateKeyWord("$$", 2, endOfSection)) {
1006 				endOfFramePos = Buffer->GetFilePos();
1007 				Buffer->SetFilePos(startOfFramePos);
1008 			}
1009 			nAtoms = (long) Buffer->GetNumLines(endOfFramePos);
1010 			if (lFrame->GetNumAtoms()>0)
1011 				lFrame = MainData->AddFrame(nAtoms, 0);
1012 			for (long i=0; i<nAtoms; ++i) {
1013 				CPoint3D Pos;
1014 				long AtomType;
1015 				if (Buffer->GetFilePos() >= endOfFramePos) {
1016 					nAtoms = i;
1017 					break;
1018 				}
1019 				Buffer->GetLine(Line);
1020 				//parse line for atom type and x,y,z positions
1021 				scanCount = sscanf(Line,"%ld %f %f %f",&AtomType,&Pos.x,&Pos.y,&Pos.z);
1022 				if (scanCount == 0) {
1023 					nAtoms = i;
1024 					break;
1025 				}
1026 				if (scanCount != 4) {
1027 					MessageAlert("Error while reading coordinates.");
1028 					return 0;
1029 				}
1030 				//add atom to the molecule
1031 				lFrame->AddAtom(AtomType, Pos);
1032 			}
1033 			if (Buffer->GetFilePos() < endOfSection) Buffer->SkipnLines(1);
1034 			//setup bonds, if needed
1035 			if (Prefs->GetAutoBond() && (nAtoms > 0))
1036 				lFrame->SetBonds(Prefs, false, ProgressInd);
1037 		}
1038 	} // Coords done
1039 
1040 	// now look for Basis data
1041 	if ((0<lFrame->GetNumAtoms())&&(Buffer->LocateKeyWord("$BASIS", 6))) {
1042 		bool error = false;
1043 		// totals counters
1044 		unsigned long nShells = 0, linesInBasis = 0;
1045 		// other counters; may be set to -1 as a reset to offset an increment
1046 		// thus placing back at 0 for a subsequent iteration
1047 		long iShell = 0, iAtom = 0, shellsPeriAtom = 0;
1048 		// temp vars for line-at-a-time read
1049 		long nFunc;
1050 		char IType[5];
1051 		float Sc;
1052 		Buffer->SkipnLines(1);
1053 		startOfSection = Buffer->GetFilePos();
1054 
1055 		// count total number of shells in Basis section by counting
1056 		// the number of lines formatted according to the sscanf below
1057 		while ((Buffer->GetFilePos()<Buffer->GetFileSize())) {
1058 			Buffer->GetLine(Line);
1059 			++linesInBasis;
1060 			// continue until we find the end of the group / start of next
1061 			if (FindKeyWord(Line, "$END", 4)<0 && FindKeyWord(Line, "$COEFF", 6)<0
1062 				&& FindKeyWord(Line, "$OCC", 4)<0) {
1063 				lineBytes = strlen(Line);
1064 				bytesRead = 0;
1065 				while (bytesRead < lineBytes) {
1066 					scanCount = sscanf(&(Line[bytesRead]), 	"%ld %4[lLsSpPdDfF] %f%n",
1067 								&nFunc, IType, &Sc, &bytesConsumed);
1068 					if (scanCount == 3) {
1069 						bytesRead+=bytesConsumed;
1070 						++nShells;
1071 					} else
1072 						break;
1073 				}
1074 			}
1075 			else // end of group has been determined
1076 				break;
1077 		}
1078 
1079 		// Now that shells are counted, we can create the BasisSet and parse data
1080 		MainData->Basis = new BasisSet(nAtoms, nShells);
1081 		if (MainData->Basis == NULL) error = true;
1082 
1083 		// go back to the line right after $BASIS so we can parse the data
1084 		Buffer->SetFilePos(startOfSection);
1085 		// reiterate through Basis section to get and save BasisSet data
1086 		while (iShell < nShells && iAtom < nAtoms && !error) {
1087 			Buffer->GetLine(Line);
1088 
1089 			// we only use IType read; nFunc is redundant; Sc(ale Factor) we don't use
1090 			scanCount = sscanf(Line, "%ld %4[lLsSpPdDfF] %f%n",
1091 								&nFunc, IType, &Sc, &bytesConsumed);
1092 			if (3==scanCount) {
1093 				// create this BasisShell in the BasisSet
1094 				MainData->Basis->Shells.push_back(BasisShell());
1095 				// increment the shell count in the BasisSet (how many shells parsed)
1096 				MainData->Basis->NumShells++;
1097 				// cast "SP" to L for simplicity
1098 				if ('S'==toupper(IType[0]) && 'P'==toupper(IType[1])) {
1099 					IType[0] = 'L';
1100 					IType[1] = '\0';
1101 				}
1102 				// save the type of this BasisShell
1103 				switch (toupper(IType[0])) {
1104 					case 'L':
1105 						MainData->Basis->Shells[iShell].ShellType = LShell;
1106 						break;
1107 					case 'S':
1108 						MainData->Basis->Shells[iShell].ShellType = SShell;
1109 						break;
1110 					case 'P':
1111 						MainData->Basis->Shells[iShell].ShellType = PShell;
1112 						break;
1113 					case 'D':
1114 						MainData->Basis->Shells[iShell].ShellType = DShell;
1115 						break;
1116 					case 'F':
1117 						MainData->Basis->Shells[iShell].ShellType = FShell;
1118 						break;
1119 				}
1120 				// add first shell of this atom to BasisMap and save NuclearCharge
1121 				if (0==shellsPeriAtom) {
1122 					MainData->Basis->BasisMap[2*iAtom]=iShell;
1123 					MainData->Basis->NuclearCharge[iAtom] = (long)(lFrame->GetAtomType(iAtom));
1124 				}
1125 				MainData->Basis->NumFuncs += MainData->Basis->Shells[iShell].GetNumFuncs(false);
1126 				// read in functions for this shell (kinda dumb: grab rows of floats if
1127 				// the line isn't formatted like the lines we grab ITypes from)
1128 				char tmpStr[5];
1129 				float tmpFloat[3];
1130 				bool stopReadingShell = false;
1131 				while ( !stopReadingShell ) {
1132 					Buffer->GetLine(Line);
1133 					if (3==sscanf(Line, "%ld %4[lLsSpPdDfF] %f", &nFunc, IType, &Sc)) {
1134 						Buffer->BackupnLines(1);
1135 						break;
1136 					}
1137 					scanCount = sscanf(Line, "%f %f %f", &tmpFloat[0], &tmpFloat[1], &tmpFloat[2]);
1138 					// non-SP (L) case: one exponent, one coef per line
1139 					if (2==scanCount && LShell!=MainData->Basis->Shells[iShell].ShellType) {
1140 						MainData->Basis->Shells[iShell].NumPrims++;
1141 						MainData->Basis->Shells[iShell].Exponent.push_back(tmpFloat[0]);
1142 						MainData->Basis->Shells[iShell].NormCoef.push_back(tmpFloat[1]);
1143 					}
1144 					// SP (L) case: one exp, two coeff's per line
1145 					else if (3==scanCount && LShell==MainData->Basis->Shells[iShell].ShellType) {
1146 						MainData->Basis->Shells[iShell].NumPrims++;
1147 						MainData->Basis->Shells[iShell].Exponent.push_back(tmpFloat[0]);
1148 						MainData->Basis->Shells[iShell].NormCoef.push_back(tmpFloat[1]);
1149 						MainData->Basis->Shells[iShell].NormCoef.push_back(tmpFloat[2]);
1150 					}
1151 					// We've found the end of this Atom's Basis Set, end of the $BASIS section
1152 					// or else we've hit an error
1153 					else if (1==sscanf(Line, "%4s%n", tmpStr, &bytesConsumed)) {
1154 						if (2==bytesConsumed && 0==strncmp(tmpStr, "$$", 3)) {
1155 							// add ending shell of this atom to BasisMap
1156 							MainData->Basis->BasisMap[2*iAtom+1]=iShell;
1157 							// we'll move on to next atom (or be done with Basis)
1158 							++iAtom;
1159 							shellsPeriAtom = -1;	// reset for next atom;
1160 							stopReadingShell = true;
1161 							break;
1162 						}
1163 						else if (4==bytesConsumed && 0==strncmp(tmpStr, "$END", 5)) {
1164 							// same as above, but need to break out of basis parsing
1165 							MainData->Basis->BasisMap[2*iAtom+1]=iShell;
1166 							++iAtom;
1167 							stopReadingShell = true;
1168 							// BasisDone = true;
1169 							// possibly needed when trying to make parser more intelligent when the
1170 							// file isn't formatted perfectly; eg, there is a blank line after $END
1171 							break;
1172 						}
1173 						else {
1174 							error = true;
1175 						}
1176 					} else { // likely hit a blank line
1177 						MainData->Basis->BasisMap[2*iAtom+1]=iShell;
1178 						++iAtom;
1179 						stopReadingShell = true;
1180 					}
1181 				}
1182 				// move on to next shell in next iteration
1183 				++iShell;
1184 				++shellsPeriAtom;
1185 			}
1186 			else if (FindKeyWord(Line, "$END", 4) >-1) {
1187 				BasisDone = true;
1188 				break;
1189 			}
1190 			else {
1191 				error = true;
1192 				break;
1193 			}
1194 
1195 		} // creating BasisSet
1196 		if (error && !BasisDone) {
1197 			// Free what we have and set it NULL so dependent functions won't crash
1198 			if (MainData->Basis != NULL) delete MainData->Basis;
1199 			MainData->Basis = NULL;
1200 			MessageAlert("Error while reading. No basis set created.");
1201 		} else {
1202 			BasisDone = true;
1203 			MainData->Basis->NuclearChargesAreValid(true);
1204 		}
1205 	}
1206 	// now look for Alpha Coefficients (Orbitals; depends on BasisSet)
1207 	if (BasisDone&&(MainData->Basis != NULL)&&(Buffer->LocateKeyWord("$COEFF_ALPHA", 12))) {
1208 		Buffer->GetLine(Line); // skip $COEFF_ALPHA line
1209 		bool error = false;
1210 		char tmpStr[5];
1211 		// counters for within iterations and overall in this section
1212 		unsigned long iSymCount, symCount = 0, eigenvecCount = 0;
1213 
1214 		// we assume that the number of Basis Functions is the number
1215 		// coefficients.  Otherwise we should throw an error
1216 		long nOrbs = MainData->Basis->GetNumBasisFuncs(false);
1217 		// create the OrbitalRec and save it if successful
1218 		OrbitalRec *OrbSet = new OrbitalRec(nOrbs, nOrbs, nOrbs);
1219 		if (OrbSet != NULL) lFrame->Orbs.push_back(OrbSet);
1220 
1221 		// read the section until we hit the end.  should be modified to halt on EOF
1222 		while ((Buffer->GetFilePos()<Buffer->GetFileSize())&&!error) {
1223 			Buffer->GetLine(Line);
1224 			// continue until we find the end of the group
1225 			if (FindKeyWord(Line, "$", 1)<0 && 0!=strncmp(Line, "\0", kMaxLineLength)) {
1226 				lineBytes = strlen(Line);
1227 				bytesRead = 0;
1228 				iSymCount = 0;
1229 
1230 				// get the Alpha symmetry symbols a line at a time (should be 5 per line,
1231 				// except possibly the last block may have fewer per line)
1232 				while (bytesRead < lineBytes) {
1233 					scanCount = sscanf(&Line[bytesRead], "%s%n", tmpStr, &bytesConsumed);
1234 					if (1==scanCount) {
1235 						tmpStr[4] = '\0'; // SymType is 5 chars wide and must be null-terminated
1236 						strncpy(&OrbSet->SymType[5*symCount], tmpStr, 4);
1237 						bytesRead+=bytesConsumed;
1238 						++iSymCount;
1239 						++symCount;
1240 					} else
1241 						break;
1242 				} // got sym line
1243 
1244 				// next come Alpha eigenvectors (Energy; first row of data after syms)
1245 				Buffer->GetLine(Line);
1246 				lineBytes = strlen(Line);
1247 				bytesRead = 0;
1248 				float tmpEigenvec;
1249 				// get a line of the values at a time (should be 5 per line, except possibly
1250 				// the last block may have fewer per line)
1251 				while (bytesRead < lineBytes) {
1252 					scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpEigenvec, &bytesConsumed);
1253 					if (scanCount == 1) {
1254 						lFrame->Orbs[0]->Energy[eigenvecCount] = tmpEigenvec;
1255 						bytesRead += bytesConsumed;
1256 						++eigenvecCount;
1257 					} else
1258 						break;
1259 				} //got eigenvector line
1260 
1261 				// now get the Alpha coefficients
1262 				for (long iLine=0; iLine < nOrbs; ++iLine) {
1263 					Buffer->GetLine(Line);
1264 					// each line should contain up to 5 orbitals
1265 					lineBytes = strlen(Line);
1266 					bytesRead = 0;
1267 					long iCoef = 0;
1268 					float tmpCoef;
1269 					// get coefficients line at a time, "symCount" times
1270 					while (bytesRead < lineBytes && iCoef < symCount) {
1271 						scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpCoef, &bytesConsumed);
1272 						if (scanCount == 1) {
1273 							OrbSet->Vectors[(symCount-iSymCount)*nOrbs+iCoef*nOrbs+iLine] = tmpCoef;
1274 							bytesRead += bytesConsumed;
1275 							++iCoef;
1276 						} else
1277 							break;
1278 					}
1279 					if (iCoef < iSymCount) error = true;
1280 					if (error) break;
1281 				} // got coefs block
1282 				if (error) break;
1283 			}
1284 			else
1285 				break; // found $END of $COEFF_ALPHA
1286 		}
1287 		if (error) {
1288 			// free what we have and set NULL so dependent functions won't crash
1289 			if (OrbSet != NULL) delete OrbSet;
1290 			lFrame->Orbs[0] = NULL;
1291 			MessageAlert("Error while reading. No orbital set created.");
1292 		}
1293 		else
1294 			CoefAlphaDone = true;
1295 	} // Alpha Coefficients (Orbitals) done
1296 
1297 	// now look for Beta Coefficients (Orbitals; optional; depends on Alpha Coefficients)
1298 	if (CoefAlphaDone&&(Buffer->LocateKeyWord("$COEFF_BETA", 11))) {
1299 		Buffer->GetLine(Line); // skip $COEFF_BETA line
1300 		bool error = false;
1301 		char tmpStr[5];
1302 		// counters for within iterations and overall in this section
1303 		unsigned long iSymCount, symCount = 0, eigenvecCount = 0;
1304 		// we assume that the number of Basis Functions is the number
1305 		// coefficients.  Otherwise wei should throw an error
1306 		long nOrbs = MainData->Basis->GetNumBasisFuncs(false);
1307 
1308 		while ((Buffer->GetFilePos()<Buffer->GetFileSize())&&!error) {
1309 			Buffer->GetLine(Line);
1310 			// continue until we find the end of the group
1311 			if (FindKeyWord(Line, "$", 1)<0 && 0!=strncmp(Line, "\0", kMaxLineLength)) {
1312 				lineBytes = strlen(Line);
1313 				bytesRead = 0;
1314 				iSymCount = 0;
1315 
1316 				// get the Beta symmetry symbols a line at a time (should be 5 per line,
1317 				// except possibly the last block may have fewer per line)
1318 				while (bytesRead < lineBytes) {
1319 					scanCount = sscanf(&Line[bytesRead], "%s%n", tmpStr, &bytesConsumed);
1320 					if (1==scanCount) {
1321 						tmpStr[4] = '\0'; // SymType is 5 chars wide and must be null-terminated
1322 						strncpy(&lFrame->Orbs[0]->SymTypeB[5*symCount], tmpStr, 4);
1323 						bytesRead+=bytesConsumed;
1324 						++iSymCount;
1325 						++symCount;
1326 					} else
1327 						break;
1328 				} // get sym line
1329 
1330 				// next come Beta eigenvectors (Energy; first row of data after syms)
1331 				Buffer->GetLine(Line);
1332 				lineBytes = strlen(Line);
1333 				bytesRead = 0;
1334 				float tmpEigenvec;
1335 				// get a line of the values at a time (should be 5 per line, except possibly
1336 				// the last block may have fewer per line)
1337 				while (bytesRead < lineBytes) {
1338 					scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpEigenvec, &bytesConsumed);
1339 					if (scanCount == 1) {
1340 						lFrame->Orbs[0]->EnergyB[eigenvecCount] = tmpEigenvec;
1341 						bytesRead += bytesConsumed;
1342 						++eigenvecCount;
1343 					} else
1344 						break;
1345 				} //get eigenvector line
1346 
1347 				// now get the Beta coefficients
1348 				for (long iLine=0; iLine < nOrbs; ++iLine) {
1349 					Buffer->GetLine(Line);
1350 					// each line will contain up to 5 orbitals
1351 					lineBytes = strlen(Line);
1352 					bytesRead = 0;
1353 					long iCoef = 0;
1354 					float tmpCoef;
1355 					// get coefficients line at a time, "symCount" times
1356 					while (bytesRead < lineBytes && iCoef < symCount) {
1357 						scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpCoef, &bytesConsumed);
1358 						if (scanCount == 1) {
1359 							lFrame->Orbs[0]->VectorsB[(symCount-iSymCount)*nOrbs+iCoef*nOrbs+iLine] = tmpCoef;
1360 							bytesRead += bytesConsumed;
1361 							++iCoef;
1362 						} else
1363 							break;
1364 					}
1365 					if (iCoef < iSymCount) error = true;
1366 					if (error) break;
1367 				} // get coef block
1368 				if (error) break;
1369 			}
1370 			else
1371 				// if not found $END??
1372 				break; // found $END of $COEFF_BETA
1373 		}
1374 		if (error) {
1375 			// If we got to this point, Alpha was done correctly, so we don't delete the
1376 			// OrbitalRec -just resize it to exclude Beta (check for NULL to be safe)
1377 			if (lFrame->Orbs[0] != NULL)
1378 				lFrame->Orbs[0]->ReSize(MainData->Basis->GetNumBasisFuncs(false), 0);
1379 			MessageAlert("Error while reading. No beta orbital set added.");
1380 		}
1381 		else
1382 			CoefBetaDone = true;
1383 	} // Beta Coefficients (orbitals) done
1384 	else if (BasisDone && CoefAlphaDone) // no Beta Coeffs
1385 		lFrame->Orbs[0]->ReSize(MainData->Basis->GetNumBasisFuncs(false), 0);
1386 
1387 	// now look for Alpha Orbital Occupations (optional; depends on COEFF_ALPHA)
1388 	if (CoefAlphaDone&&(Buffer->LocateKeyWord("$OCC_ALPHA", 10))) {
1389 		Buffer->SkipnLines(1); // skip $OCC_ALPHA line
1390 		bool error = false;
1391 		// the number of orbital occupations should be the number of basis functions
1392 		long nOrbs = MainData->Basis->GetNumBasisFuncs(false);
1393 		lFrame->Orbs[0]->OrbOccupation = new float[nOrbs];
1394 		// if the array was allocated fine, we can continue
1395 		if (lFrame->Orbs[0]->OrbOccupation != NULL) {
1396 			// counters and a temporary slot for data read one item at a time
1397 			long occCount = 0, lineOccs;
1398 			float tmpOcc;
1399 			// read the occupation numbers end $END; should have a case for EOF read
1400 			while ((Buffer->GetFilePos()<Buffer->GetFileSize())&&!error) {
1401 				Buffer->GetLine(Line);
1402 				// continue until we find the end of the group
1403 				if (FindKeyWord(Line, "$", 1)<0 && 0!=strncmp(Line, "\0", kMaxLineLength)) {
1404 					lineBytes = strlen(Line);
1405 					bytesRead = 0;
1406 					lineOccs = 0;
1407 					//read line at a time, up to 5, and within number of orb's defined above
1408 					while (bytesRead < lineBytes && lineOccs < 5 && occCount < nOrbs) {
1409 						scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpOcc, &bytesConsumed);
1410 						if (scanCount == 1) {
1411 							bytesRead+=bytesConsumed;
1412 							lFrame->Orbs[0]->OrbOccupation[occCount] = tmpOcc;
1413 							++lineOccs;
1414 							++occCount;
1415 						}
1416 						else
1417 							break;
1418 					}
1419 					if (error) break;
1420 				}
1421 				else
1422 					break;
1423 			}
1424 			// insufficient data
1425 			if (occCount < nOrbs)
1426 				error = true;
1427 			// else set the number occupied to what we read.
1428 			else
1429 				lFrame->Orbs[0]->NumOccupiedAlphaOrbs = occCount;
1430 		}
1431 		if (error) {
1432 			// free what we have and set NULL so dependent functions won't crash
1433 			if (lFrame->Orbs[0]->OrbOccupation != NULL)
1434 				delete lFrame->Orbs[0]->OrbOccupation;
1435 			lFrame->Orbs[0]->OrbOccupation = NULL;
1436 			MessageAlert("Error while reading. No Alpha Occupations added.");
1437 		}
1438 		else
1439 			OccAlphaDone = true;
1440 	}// Occ_Alpha done
1441 
1442 	// now look for Beta Orbital Occupations (optional; depends on COEFF_BETA)
1443 	if (CoefBetaDone&&OccAlphaDone&&(Buffer->LocateKeyWord("$OCC_BETA", 9))) {
1444 		Buffer->SkipnLines(1); // skip $OCC_BETA line
1445 		bool error = false;
1446 
1447 		lFrame->Orbs[0]->setOrbitalWavefunctionType(UHF);
1448 		long nOrbs = MainData->Basis->GetNumBasisFuncs(false);
1449 		lFrame->Orbs[0]->OrbOccupationB = new float[nOrbs];
1450 		if (lFrame->Orbs[0]->OrbOccupationB != NULL) {
1451 			// counters and a temporary slot for data read one item at a time
1452 			long occCount = 0, lineOccs;
1453 			float tmpOcc;
1454 
1455 			while ((Buffer->GetFilePos()<Buffer->GetFileSize())&&!error) {
1456 				Buffer->GetLine(Line);
1457 				// continue until we find the end of the group
1458 				if (FindKeyWord(Line, "$", 1)<0 && 0!=strncmp(Line, "\0", kMaxLineLength)) {
1459 					lineBytes = strlen(Line);
1460 					bytesRead = 0;
1461 					lineOccs = 0;
1462 					//read line at a time, up to 5, and within number of orb's defined above
1463 					while (bytesRead < lineBytes && lineOccs < 5 && occCount < nOrbs) {
1464 						scanCount = sscanf(&Line[bytesRead], "%f%n", &tmpOcc, &bytesConsumed);
1465 						if (scanCount == 1) {
1466 							bytesRead+=bytesConsumed;
1467 							lFrame->Orbs[0]->OrbOccupationB[occCount] = tmpOcc;
1468 							++lineOccs;
1469 							++occCount;
1470 						}
1471 						else
1472 							break;
1473 					}
1474 					if (error) break;
1475 				}
1476 				else
1477 					break;
1478 			}
1479 			// insufficient data
1480 			if (occCount < nOrbs)
1481 				error = true;
1482 			// else set the number occupied to what we read.
1483 			else
1484 				lFrame->Orbs[0]->NumOccupiedBetaOrbs = occCount;
1485 		}
1486 		if (error) {
1487 			// free what we have and set NULL so dependent functions won't crash
1488 			if (lFrame->Orbs[0]->OrbOccupationB != NULL)
1489 				delete lFrame->Orbs[0]->OrbOccupationB;
1490 			lFrame->Orbs[0]->OrbOccupationB = NULL;
1491 			MessageAlert("Error while reading. No Beta Occupations added.");
1492 		}
1493 		else
1494 			OccBetaDone = true;
1495 	}// Occ_Beta Done
1496 
1497 	// now look for vibrational frequencies for the last frame (independent)
1498 	if ((0<lFrame->GetNumAtoms())&&(Buffer->LocateKeyWord("$FREQ", 5))) {
1499 		Buffer->SkipnLines(1);	// skip $FREQ line
1500 		// create the VibRec
1501 		lFrame->Vibs = new VibRec(3*lFrame->NumAtoms, lFrame->NumAtoms);
1502 		//continue only if we're successful
1503 		if (lFrame->Vibs != NULL) {
1504 			long nModes=0;
1505 			char freq[kMaxLineLength];
1506 			bool error = false;	//Use the error flag to bail out once we hit an error
1507 			while ((Buffer->GetFilePos())<(Buffer->GetFileSize())&&!error) {
1508 				Buffer->GetLine(Line);
1509 				//continue until we find the end of the group
1510 				if (FindKeyWord(Line, "$", 1)<0 && 0!=strncmp(Line, "\0", kMaxLineLength)) {
1511 					//the first line is the symmetry symbolis which we ignore
1512 					// (we should've gotten those from the Alpha/Beta Coefficients)
1513 					Buffer->GetLine(Line);	//next line is the frequencies
1514 					long lineModes=0;
1515 					lineBytes = strlen(Line);
1516 					bytesRead = 0;
1517 					// read Frequencies as strings one at a time in one line
1518 					while (bytesRead < lineBytes) {
1519 						scanCount = sscanf(&Line[bytesRead], "%s%n", freq, &bytesConsumed);
1520 						if (scanCount == 1) {
1521 							lFrame->Vibs->Frequencies.push_back(freq);
1522 							bytesRead += bytesConsumed;
1523 							++lineModes;
1524 						} else
1525 							break;
1526 					}
1527 					//Next come the vibrational offsets
1528 					for (long iatm=0; iatm<lFrame->NumAtoms; ++iatm) {
1529 						Buffer->GetLine(Line);
1530 						//each line will normally contain x, y, z for one atom for 3 modes
1531 						bytesRead = 0;
1532 						for (long imode=0; imode<lineModes; ++imode) {
1533 							CPoint3D temp;
1534 							int scanCount = sscanf(&Line[bytesRead], "%f %f %f%n",
1535 												   &temp.x, &temp.y, &temp.z, &bytesConsumed);
1536 							if (scanCount == 3) {
1537 								lFrame->Vibs->NormMode[iatm + lFrame->NumAtoms*(nModes+imode)] = temp;
1538 								bytesRead += bytesConsumed;
1539 							} else {
1540 								lineModes = imode;
1541 								error = true;
1542 								break;
1543 							}
1544 						}
1545 						if (error) break;
1546 					}
1547 					nModes += lineModes;
1548 				} else
1549 					break;
1550 			}// end while in file and not error
1551 			lFrame->Vibs->NumModes = nModes;
1552 			lFrame->Vibs->Resize(nModes);
1553 		}
1554 	} // vibrational frequencies done
1555 	// Don't need an else, case, since lFrame->Vibs would be NULL, anyway
1556 	// We don't handle the $DIPOLE section in MKL files
1557 	// OpenMKLFile() can return "success" because we are done parsing the file
1558 	return 1;
1559 }
1560 
1561 /**
1562   * Adds support for opening the MoPac zMatrix MOP and mop file types, and
1563   * MoPac archive output ARC and arc files.
1564   * @param Buffer A BufferFileObject that the .MOP or .mop file is buffereid.
1565   * @param fileType A char indicating whether the file is a MOP or ARC file.
1566   * into to make parsing the file easier.  See the BufferFile object for
1567   * valid BufferFile operations. Parsing code adapted from
1568   * MoleculeData::ParseMOPACZMatrix.
1569   * @return Returns 1 upon open success or 0 on error or failure to open
1570 */
OpenMOPACFile(BufferFile * Buffer,TextFileType fileType)1571 long MolDisplayWin::OpenMOPACFile(BufferFile * Buffer, TextFileType fileType) {
1572 	// buffer line for text to be scanned while parsing
1573 	char		Line[kMaxLineLength];
1574 	// placeholder for traversing file sections in Buffer
1575 	wxFileOffset	startOfAtoms = 1;
1576 	// # of tokens sucessfully read in a sscanf call, # line of atoms read
1577 	int			scanCount = 0, iLine = 0;
1578 	// vars for holding sscanf read, borrowing some from ParseMOPACZMatrix()
1579 	CPoint3D	pos = CPoint3D(0.0f, 0.0f, 0.0f);	// just a placeholder
1580 	char		symbol[4];	// This could probably safely be 2-3 chars long
1581 	float		bondLength = -0.1f, bondAngle = 0.0f, bondDihedral = 0.0f;
1582 	// sane defaults to avoid accessing unassigned variables
1583 	long		AtomType = -1, nAtoms = 0;
1584 	int			j1 = -1, j2 = -1, j3 = -1, con1, con2, con3;
1585 	bool		error = false;
1586 
1587 	ProgressInd->ChangeText("Reading MOPAC file...");
1588 	Frame *lFrame = MainData->cFrame;
1589 	//zero out initial symbol
1590 	memset((void *)symbol, 0, (size_t)(4*sizeof(char)));
1591 
1592 	// file is of type ARC
1593 	if (fileType == MOPACarcFile) {
1594 		// Get to the right part of the file
1595 		Buffer->LocateKeyWord("DATE:", 5);
1596 		Buffer->SkipnLines(1);
1597 		Buffer->LocateKeyWord("DATE:", 5);
1598 		Buffer->SkipnLines(1);
1599 	}
1600 	// file is of type MOP
1601 	else if (fileType == MOPACmopFile)
1602 		// skip descriptions, MoPac parms and goto start of atoms
1603 		Buffer->SkipnLines(3);
1604 	else
1605 		return 0;	// quit 'cause we don't know what kind of file we were passed
1606 
1607 	startOfAtoms = Buffer->GetFilePos();
1608 	// Count the number of Atoms
1609 	while (Buffer->GetFilePos()	< Buffer->GetFileLength()) {
1610 		Buffer->GetLine(Line);
1611 		scanCount = sscanf(Line, "%3s %f %d %f %d %f %d %d %d %d", symbol, &bondLength,
1612 					&j1, &bondAngle, &j2, &bondDihedral, &j3, &con1, &con2, &con3);
1613 		// The last atom in the list may be a duplicate of the
1614 		// first atom in the list and needs to be ignored
1615 		if (scanCount > 2 && nAtoms > 1 && bondLength < 0.00001) break;
1616 		// otherwise, it is [probably] a new atom
1617 		if ( (scanCount > 9 && nAtoms > 2) || (scanCount > 8 && nAtoms == 2) ||
1618 			(scanCount > 6 && nAtoms == 1) || (scanCount > 4 && nAtoms == 0) )
1619 			++nAtoms;
1620 		else
1621 			break;
1622 	}
1623 	// atoms are now counted; go back to atoms' start for actual parsing
1624 	Buffer->SetFilePos(startOfAtoms);
1625 
1626 	// data in this file will be treated as a zMatrix
1627 	// cartesian mop files exist, but usually have a different extension
1628 	if (!(MainData->IntCoords))
1629 		MainData->IntCoords = new Internals;
1630 	MOPacInternals * mInts = MainData->IntCoords->GetMOPacStyle();
1631 	if (!mInts) {
1632 		MainData->IntCoords->CreateMOPacInternals(3*nAtoms);
1633 		mInts = MainData->IntCoords->GetMOPacStyle();
1634 	}
1635 	float unitConversion = 1.0f;
1636 	if (MainData->InputOptions && MainData->InputOptions->Data->GetUnits())
1637 		unitConversion = kBohr2AngConversion;
1638 
1639 	// Get and add atoms (parsing) loop
1640 	while (iLine < nAtoms) {
1641 		con1 = -1;	// Default Values
1642 		con2 = -1;
1643 		con3 = -1;
1644 		Buffer->GetLine(Line);
1645 		scanCount = sscanf(Line, "%3s %f %d %f %d %f %d %d %d %d", symbol, &bondLength,
1646 					&j1, &bondAngle, &j2, &bondDihedral, &j3, &con1, &con2, &con3);
1647 		if (scanCount < 1) {
1648 			error = true;
1649 			break;	//failed to get anything
1650 		}
1651 		// Get type of atom by atomic symbol and add it to fram (dummy position 0,0,0)
1652 		AtomType = SetAtomType((unsigned char *)symbol);
1653 		lFrame->AddAtom(AtomType, pos);
1654 		if (iLine > 0) {
1655 			if (scanCount < 2) {
1656 				error = true;
1657 				break;
1658 			}
1659 			if (iLine == 1)	//the second atom will specify only the bond length
1660 				con1 = 1;
1661 			// 3rd Line and beyond (iLine == 2 and up)
1662 			else {
1663 				if (iLine == 2) {	//For the third atom the connectivity is optional
1664 					if ((scanCount >= 5)&&(scanCount <= 7)) {
1665 						con1 = 2;
1666 						con2 = 1;	//The default allows the connections to be assumed
1667 						if (scanCount >= 6) {
1668 							con1 = (int) bondDihedral;
1669 							con2 = j3;
1670 						}
1671 					}
1672 					else if (scanCount < 5) break;	// in this case the line is invalid
1673 				}
1674 			}
1675 			if (bondLength < 0.00001)
1676 				break; // bad value or dupe of first atom
1677 			// reduce values by 1 because our indexing starts at 0 not 1
1678 			con1--;
1679 			con2--;
1680 			con3--;
1681 			if (con1 >= iLine)
1682 				break;
1683 			// store connections and coordinates
1684 			mInts->AddInternalCoordinate(iLine, con1, 0, bondLength*unitConversion);
1685 			if (iLine > 1) {
1686 				mInts->AddInternalCoordinate(iLine, con2, 1, bondAngle);
1687 				if (iLine > 2)
1688 					mInts->AddInternalCoordinate(iLine, con3, 2, bondDihedral);
1689 			}
1690 		}
1691 		++iLine;
1692 	} // end parsing loop
1693 	if (error)
1694 		return 0; // failure due to an error: quit!
1695 	// if we punted after the AddAtom call delete off the
1696 	// atom without internal coordinate information
1697 	if (iLine > lFrame->NumAtoms)
1698 		lFrame->DeleteAtom(iLine-1);
1699 	// now convert the set of internals into cartesians
1700 	// this caused some segfaults in testing, but probably due to bad files
1701 	mInts->InternalsToCartesians(MainData, Prefs, 0);
1702 	// Setup bonds, if needed
1703 	if (Prefs->GetAutoBond())
1704 		lFrame->SetBonds(Prefs, true, ProgressInd);
1705 	return 1;	// OpenMOPACFile success
1706 }
1707 
OpenXYZFile(BufferFile * Buffer)1708 long MolDisplayWin::OpenXYZFile(BufferFile * Buffer) {
1709 	char	Line[kMaxLineLength];
1710 	long	nAtoms,i;
1711 	short	scanerr;
1712 
1713 	ProgressInd->ChangeText("Reading XYZ file...");
1714 	Frame * lFrame = MainData->cFrame;
1715 		//1st line contains the number of atoms
1716 	Buffer->GetLine(Line);
1717 	scanerr = sscanf(Line, "%ld", &nAtoms);
1718 	if ((scanerr!=1)||(nAtoms<=0)) {
1719 		wxLogMessage(_("XYZ files must have an integer representing the number of atoms on the first line of the file."));
1720 		throw DataError();
1721 	}
1722 		//allocate memory for the atoms
1723 	if (lFrame->NumAtoms > 0) {	//If there are already atoms treat as an append
1724 		lFrame = MainData->AddFrame(nAtoms,0);
1725 	} else {
1726 		if (!MainData->SetupFrameMemory(nAtoms, 0)) throw MemoryError();
1727 		Buffer->GetLine(Line);
1728 		MainData->SetDescription(Line);
1729 	}
1730 	long DRCnSkip = Prefs->GetDRCSkip(), nSkip=0;
1731 		bool Done=false;
1732 		bool RdPoint = true;
1733 	try {
1734 		while (!Done) {
1735 			Done = true;
1736 			if (RdPoint) {
1737 				VibRec * lVibs = NULL;
1738 				for (i=0; i<nAtoms; ++i) {
1739 						long AtomType, test;
1740 						CPoint3D Pos, Vector;
1741 
1742 					Buffer->GetLine(Line);
1743 					test = ParseCartLine(Line, &AtomType, &Pos, &Vector, -1);
1744 
1745 					if (test==-1) {	//invalid atom type
1746 						wxLogMessage(_("Error: An invalid Atom Type was encountered in the atom list."));
1747 						throw DataError();
1748 					} else if (test<0) {//other invalid data was encountered
1749 						wxLogMessage(_("An error occured while reading the file. Open File Aborted!"));
1750 						throw DataError();
1751 					}
1752 					if (AtomType > 115) {
1753 						if (AtomType > 255) {
1754 							if (((AtomType - 255) < 1)||((AtomType - 255) > nAtoms)) {
1755 								wxLogMessage(_("Invalid atom number detected in special atom list."));
1756 								throw DataError();
1757 							}
1758 						}
1759 						if (!lFrame->AddSpecialAtom(Vector, i)) {
1760 							throw MemoryError();
1761 						}
1762 					} else if (test == 7) {	//mass weight the normal mode
1763 						if (i==0) {
1764 							lVibs = new VibRec(1, nAtoms);
1765 							if (!lVibs) throw MemoryError();
1766 						}
1767 						if (lVibs) {
1768 							lVibs->NormMode[i].x = Vector.x*Prefs->GetSqrtAtomMass(AtomType-1);
1769 							lVibs->NormMode[i].y = Vector.y*Prefs->GetSqrtAtomMass(AtomType-1);
1770 							lVibs->NormMode[i].z = Vector.z*Prefs->GetSqrtAtomMass(AtomType-1);
1771 						}
1772 					}
1773 					lFrame->AddAtom(AtomType, Pos);
1774 					MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.x));
1775 					MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.y));
1776 					MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.z));
1777 				}
1778 				if (lVibs) lFrame->Vibs = lVibs;
1779 				if (Prefs->GetAutoBond())	//setup bonds, if needed
1780 					lFrame->SetBonds(Prefs, false, ProgressInd);
1781 			}
1782 			wxFileOffset cPos = Buffer->GetFilePos();
1783 			wxFileOffset fileLength = Buffer->GetFileLength();
1784 			if (cPos < fileLength) {	//If we haven't reached the end of the file
1785 				Buffer->GetLine(Line);	//check to see if another frame is available
1786 				scanerr = sscanf(Line, "%ld", &nAtoms);
1787 				if ((scanerr==1)&&(nAtoms>0)) {
1788 					if (nSkip >= DRCnSkip) {
1789 						nSkip = 0;
1790 						RdPoint = true;
1791 						lFrame = MainData->AddFrame(nAtoms,0);
1792 						if (!lFrame) throw MemoryError();
1793 						Buffer->GetLine(Line);
1794 						if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
1795 							{ throw UserCancel();}
1796 					} else {
1797 						++nSkip;
1798 						Buffer->SkipnLines(nAtoms+1);
1799 						RdPoint = false;
1800 					}
1801 					Done = false;
1802 				}
1803 			}
1804 		}
1805 	}
1806 	catch (DataError /*Error*/) {
1807 		//attempt to save part of file
1808 		if (MainData->GetNumFrames() > 1) {
1809 			MainData->DeleteFrame();
1810 		}
1811 		wxLogMessage(_("Error while parsing file. Partial file may be valid."));
1812 	}
1813 	return 1;
1814 }
1815 
OpenMolPltFile(BufferFile * Buffer)1816 long MolDisplayWin::OpenMolPltFile(BufferFile *Buffer) {
1817 	long				j,ii, nkinds=0, catm, iscanerr=0, LineLength, LinePos=0, fileAtoms=0,
1818 						fileBonds=0;
1819 	int					nchar;
1820 	long				test=0, Mode=0;
1821 	float				BondLength=0.0f;
1822 	char				LineText[kMaxLineLength+1], KeyWord[kMaxLineLength+1], token[5];
1823 
1824 	ProgressInd->ChangeText("Reading MolPlt format file...");
1825 	Frame * lFrame = MainData->cFrame;
1826 /*Now interpert the file data */
1827 		// Grab the first line (containing all keywords)
1828 	Buffer->GetLine(LineText);
1829 	LineLength = strlen(LineText);
1830 
1831 	LinePos = FindKeyWord(LineText, "NATOMS", 6);
1832 	if (LinePos >= 0) {
1833 		LinePos += 6;
1834 		iscanerr = sscanf(&LineText[LinePos], "%1s%ld", token, &fileAtoms);
1835 		if (iscanerr != 2) return 0;
1836 	} else return 0;	// NATOMS keyword not found!
1837 	LinePos = FindKeyWord(LineText, "NKINDS", 6);
1838 	if (LinePos >= 0) {
1839 		LinePos += 6;
1840 		sscanf(&LineText[LinePos], "%1s%ld", token, &nkinds);
1841 	}
1842 	LinePos = FindKeyWord(LineText, "NBONDS", 6);
1843 	if (LinePos >= 0) {
1844 		LinePos += 6;
1845 		sscanf(&LineText[LinePos], "%1s%ld", token, &fileBonds);
1846 	}
1847 	LinePos = FindKeyWord(LineText, "MODE", 4);
1848 	if (LinePos >= 0) {
1849 		LinePos += 4;
1850 		sscanf(&LineText[LinePos], "%1s%ld", token, &Mode);
1851 	}
1852 	LinePos = FindKeyWord(LineText, "BNDLENGTH", 9);
1853 	if (LinePos >= 0) {
1854 		LinePos += 9;
1855 		sscanf(&LineText[LinePos], "%1s%f", token, &BondLength);
1856 	}
1857 	LinePos = FindKeyWord(LineText, "BONDLENGTH", 10);
1858 	if (LinePos >= 0) {
1859 		LinePos += 10;
1860 		sscanf(&LineText[LinePos], "%1s%f", token, &BondLength);
1861 	}
1862 
1863 	if (fileAtoms <= 0) {			/* There don't appear to be any atoms to read in ???*/
1864 		AbortOpen("NATOMS keyword missing. Are you sure this is a Molplt file\? Open file aborted.");
1865 		return 0;
1866 	}
1867 		//Allocate frame memory
1868 	if (!MainData->SetupFrameMemory(fileAtoms, fileBonds)) throw MemoryError();
1869 			// The second line is just a description so copy it to a string
1870 	Buffer->GetLine(LineText);
1871 	MainData->SetDescription(LineText);
1872 
1873 	//Need to keep the single mode storage separated off as the AddAtom function will delete it
1874 	//from the Frame record otherwise.
1875 	VibRec * Mode1Vibs = NULL;
1876 	if (Mode == -1) {
1877 		Mode1Vibs = new VibRec(1, fileAtoms);
1878 		if (!Mode1Vibs) throw MemoryError();
1879 	}
1880 	Buffer->SkipnLines(nkinds);
1881 
1882 // read in the coords and atomtypes
1883 	for (j=0; j<fileAtoms; ++j) {			// loop over the number of atoms
1884 			long AtomType;
1885 			CPoint3D Pos, Vector;
1886 
1887 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
1888 		{ throw UserCancel();}
1889 		Buffer->GetLine(LineText);
1890 		test = ParseCartLine(LineText, &AtomType, &Pos, &Vector, Mode);
1891 
1892 		if (AtomType==-1) {	//invalid atom type
1893 				//Choices would seem to be to punt and abort or change to some sort of valid type
1894 			wxLogMessage(_("Error: An invalid Atom Type was encountered in the atom list."));
1895 			if (Mode1Vibs) delete Mode1Vibs;
1896 			throw DataError();
1897 		}
1898 		if (test<0) {
1899 			wxLogMessage(_("An error occured while reading the file. Open File Aborted!"));
1900 			if (Mode1Vibs) delete Mode1Vibs;
1901 			throw DataError();
1902 		}
1903 		if (AtomType > 115) {
1904 			if (Mode < 0) {
1905 				wxLogMessage(_("Error: Special Atom types may not be used with Normal Modes!"));
1906 				if (Mode1Vibs) delete Mode1Vibs;
1907 				throw DataError();
1908 			}
1909 			if (AtomType > 255) {
1910 				if (((AtomType - 255) < 1)||((AtomType - 255) > fileAtoms)) {
1911 					wxLogMessage(_("Invalid atom number detected in special atom list."));
1912 					if (Mode1Vibs) delete Mode1Vibs;
1913 					throw DataError();
1914 				}
1915 			}
1916 			if (!lFrame->AddSpecialAtom(Vector, j)) throw MemoryError();
1917 		}
1918 		if (Mode == -1) {	//mass weight the normal mode
1919 			Mode1Vibs->NormMode[j].x = Vector.x*Prefs->GetSqrtAtomMass(AtomType-1);
1920 			Mode1Vibs->NormMode[j].y = Vector.y*Prefs->GetSqrtAtomMass(AtomType-1);
1921 			Mode1Vibs->NormMode[j].z = Vector.z*Prefs->GetSqrtAtomMass(AtomType-1);
1922 		}
1923 		lFrame->AddAtom(AtomType, Pos);
1924 		MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.x));
1925 		MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.y));
1926 		MainData->MaxSize = MAX(MainData->MaxSize, fabs(Pos.z));
1927 	}
1928 	if (Mode1Vibs) lFrame->Vibs = Mode1Vibs;
1929 
1930 	if (fileBonds > 0) {						/* read in the array of bonds */
1931 		long	ibond=-1, temp;
1932 		Buffer->GetLine(LineText);
1933 		LinePos = FindKeyWord(LineText, "BONDATOMS", 9);
1934 		if (LinePos >= 0) {
1935 			LinePos += 9;
1936 			LineLength = strlen(LineText);
1937 			for (j=0; j<(2*fileBonds); ++j) {
1938 				while (LineText[LinePos] && ((LineText[LinePos] < '0')||
1939 						(LineText[LinePos] > '9'))) ++LinePos;
1940 				while (LinePos >= LineLength) {	//EOL reached try getting a new line
1941 					wxFileOffset CurrentPos = Buffer->GetFilePos();
1942 					Buffer->GetLine(LineText);
1943 					if ((-1<FindKeyWord(LineText, "ATOMIC", 6))||
1944 						(-1<FindKeyWord(LineText, "MODE", 4))) {
1945 						Buffer->SetFilePos(CurrentPos);
1946 						break;
1947 					}
1948 					LinePos = 0;
1949 					LineLength = strlen(LineText);
1950 					while (LineText[LinePos] && ((LineText[LinePos] < '0')||
1951 							(LineText[LinePos] > '9'))) ++LinePos;
1952 				}
1953 				if (LinePos < LineLength) {
1954 					iscanerr = sscanf(&LineText[LinePos], "%ld%n", &temp, &nchar);
1955 					if (iscanerr != 1)
1956 						return 1;
1957 					LinePos += nchar;
1958 					if ((temp >= 1)&&(temp <= lFrame->NumAtoms)) {
1959 						temp--;
1960 						if (ibond == -1) ibond = temp;
1961 						else {
1962 							lFrame->AddBond(ibond, temp);
1963 							ibond = -1;		//reset ibond for the next bond pair
1964 						}
1965 					} else	// Bad bonded atom number
1966 						return 1;
1967 				} else break;	//and break since we've run out of bond #'s
1968 			}
1969 		} else {
1970 			return 1;
1971 		}
1972 	}
1973 	if ((BondLength > 0.0)||(Prefs->GetAutoBond())) {
1974 		Prefs->SetMaxBondLength(BondLength);
1975 		lFrame->SetBonds(Prefs, false, ProgressInd);
1976 	}
1977 	if (Mode > 0) {
1978 		nkinds = 3*(lFrame->NumAtoms);		/* In general there will be 3N normal modes */
1979 		VibRec * lVibs = MainData->cFrame->Vibs = new VibRec(nkinds, fileAtoms);
1980 		if (!lVibs) throw MemoryError();
1981 		catm = 0;
1982 		ii=0;
1983 		try {
1984 					/* Now locate the first frequency (skipping the atomic masses) */
1985 			wxFileOffset CurrentPos = Buffer->GetFilePos();
1986 			Buffer->GetLine(LineText);
1987 			while (-1>=FindKeyWord(LineText, "MODE", 4)) {
1988 				CurrentPos = Buffer->GetFilePos();
1989 				Buffer->GetLine(LineText);
1990 			}
1991 			Buffer->SetFilePos(CurrentPos);
1992 
1993 			for (; ii < (3*(lFrame->NumAtoms)); ++ii) {
1994 				/* Allow user cancels */
1995 				if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
1996 					{ throw UserCancel();}
1997 				Buffer->GetLine(LineText);
1998 				for (j=0; LineText[j] && (LineText[j] != '='); ++j) ;
1999 				if (LineText[j] != '=') break;	/* no more frequencies so quit */
2000 				sscanf(&LineText[j+1], "%s", KeyWord);
2001 				LineLength = strlen(KeyWord);
2002 	/*Check to see if the first character is a '-' if so change it to an 'i' since it really is an
2003 	imaginary mode and because the menu manager will think it means create a divider in the menu instead
2004 	of a regular text item */
2005 				if (KeyWord[0] == '-') KeyWord[0] = 'i';
2006 				lVibs->Frequencies.push_back(std::string(KeyWord));
2007 
2008 				for (j=0; j < (lFrame->NumAtoms); ++j) {
2009 					Buffer->GetLine(LineText);
2010 					iscanerr = sscanf(LineText, "%f%f%f", &((lVibs->NormMode[catm]).x),
2011 						&((lVibs->NormMode[catm]).y), &((lVibs->NormMode[catm]).z));
2012 					if (iscanerr != 3) {			/*Uh Ohh looks like there was a problem reading the file*/
2013 						wxLogMessage(_("Error reading the Normal Mode input. Open file aborted."));
2014 						throw DataError();
2015 					}
2016 					(lVibs->NormMode[catm]).x *= (Prefs->GetSqrtAtomMass((lFrame->Atoms[j].Type)-1));
2017 					(lVibs->NormMode[catm]).y *= (Prefs->GetSqrtAtomMass((lFrame->Atoms[j].Type)-1));
2018 					(lVibs->NormMode[catm]).z *= (Prefs->GetSqrtAtomMass((lFrame->Atoms[j].Type)-1));
2019 					++catm;
2020 				}
2021 			}
2022 		}
2023 		catch (FileError) {	//We've hit the end of file so truncate the Mode list
2024 		}
2025 		lVibs->NumModes = ii;
2026 		if (lVibs->NumModes < 3*lFrame->NumAtoms)	/* Downsize the frequency storage to the size actually used */
2027 			lVibs->Resize(lFrame->NumAtoms);
2028 	}
2029 	if (lFrame->Vibs) {
2030 		lFrame->Vibs->CurrentMode = Mode - 1;
2031 		if (lFrame->Vibs->CurrentMode < 0) lFrame->Vibs->CurrentMode = 0;
2032 		MainData->SetDrawMode(true);
2033 	}
2034 	if (lFrame->SpecialAtoms)	MainData->SetSpecialAtomDrawMode(true);
2035 
2036 	return 1;
2037 } /* OpenMolPlt */
OpenMoldenFile(BufferFile * Buffer)2038 long MolDisplayWin::OpenMoldenFile(BufferFile * Buffer) {
2039 	char	LineText[kMaxLineLength];
2040 	Frame * lFrame = MainData->cFrame;
2041 	Buffer->SetFilePos(0);
2042 	if (Buffer->LocateKeyWord("[GEOMETRIES]", 12, -1)) {	//both formats use Angstroms
2043 		Buffer->GetLine(LineText);
2044 		if (FindKeyWord(LineText, "XYZ", 3) >= 0) { //cartesian coordinates
2045 												   // XYZ format looks like
2046 												   //   #_of_atoms
2047 												   //  title often containing "scf done: energy"
2048 												   //  one line for each atom in the form "symbol x y z"
2049 			while (Buffer->GetFilePos() < Buffer->GetFileSize()) {
2050 				Buffer->GetLine(LineText);
2051 				int atmCount=0;
2052 				if (sscanf(LineText, "%d", &atmCount) == 1) {
2053 					if (atmCount <= 0) break;
2054 					Buffer->GetLine(LineText);
2055 					if (lFrame->NumAtoms > 0) {
2056 						float t = lFrame->time;
2057 						lFrame = MainData->AddFrame(atmCount, 0);
2058 						lFrame->time = t+1;
2059 					}
2060 					int epos = FindKeyWord(LineText, "done:", 5);
2061 					if (epos > 0) {
2062 						sscanf(&(LineText[epos+5]), "%lf", &(lFrame->Energy));
2063 					}
2064 					for (int iatm=0; iatm<atmCount; ++iatm) {
2065 						unsigned char token[kMaxLineLength];
2066 						CPoint3D	pos;
2067 						Buffer->GetLine(LineText);
2068 						int rdcount = sscanf(LineText, "%s %f %f %f", token, &(pos.x), &(pos.y), &(pos.z));
2069 						if (rdcount == 4) {
2070 							long atomnum = SetAtomType(token);
2071 							if (atomnum>0)
2072 								lFrame->AddAtom(atomnum, pos);
2073 						}
2074 					}
2075 					if (Prefs->GetAutoBond())
2076 						lFrame->SetBonds(Prefs, false, ProgressInd);
2077 				} else break;
2078 			}
2079 		} else if (FindKeyWord(LineText, "ZMAT", 4) >= 0) {	//GAMESS-UK style z matrix
2080 			while (Buffer->GetFilePos() < Buffer->GetFileSize()) {
2081 				Buffer->GetLine(LineText);
2082 				if (FindKeyWord(LineText, "ZMAT", 4) >= 0) {
2083 					Buffer->BackupnLines(1);
2084 					if (lFrame->NumAtoms > 0) {
2085 						float t = lFrame->time;
2086 						lFrame = MainData->AddFrame(lFrame->NumAtoms, 0);
2087 						lFrame->time = t+1;
2088 					}
2089 					MainData->ParseGAMESSUKZMatrix(Buffer, Prefs);
2090 					if (lFrame->NumAtoms == 0) break;
2091 					if (Prefs->GetAutoBond())
2092 						lFrame->SetBonds(Prefs, false, ProgressInd);
2093 				} else break;
2094 			}
2095 		}	//else there is some undocumented type...
2096 		Buffer->SetFilePos(0);
2097 		if (Buffer->LocateKeyWord("[GEOCONV]", 9, -1)) {
2098 			Buffer->SkipnLines(1);
2099 			bool good = true;
2100 			while (good) {
2101 				good = false;
2102 				Buffer->GetLine(LineText);
2103 				if (FindKeyWord(LineText, "energy", 6) == 0) {
2104 					good = true;
2105 					int iframe = 1;
2106 					MainData->SetCurrentFrame(iframe);
2107 					Buffer->GetLine(LineText);
2108 					while (sscanf(LineText, "%lf", &MainData->cFrame->Energy) == 1) {
2109 						++iframe;
2110 						if (iframe > MainData->GetNumFrames()) break;
2111 						MainData->SetCurrentFrame(iframe);
2112 						Buffer->GetLine(LineText);
2113 					}
2114 					if (iframe <= MainData->GetNumFrames()) Buffer->BackupnLines(1);
2115 				} else if (FindKeyWord(LineText, "max-force", 9) == 0) {
2116 					good = true;
2117 					int iframe = 1;
2118 					MainData->SetCurrentFrame(iframe);
2119 					Buffer->GetLine(LineText);
2120 					float val;
2121 					while (sscanf(LineText, "%f", &val) == 1) {
2122 						MainData->cFrame->SetRMSGradient(val);
2123 						++iframe;
2124 						if (iframe > MainData->GetNumFrames()) break;
2125 						MainData->SetCurrentFrame(iframe);
2126 						Buffer->GetLine(LineText);
2127 					}
2128 					if (iframe <= MainData->GetNumFrames()) Buffer->BackupnLines(1);
2129 				} else if (FindKeyWord(LineText, "rms-force", 9) == 0) {
2130 					good = true;
2131 					int iframe = 1;
2132 					MainData->SetCurrentFrame(iframe);
2133 					Buffer->GetLine(LineText);
2134 					float val;
2135 					while (sscanf(LineText, "%f", &val) == 1) {
2136 						MainData->cFrame->SetMaximumGradient(val);
2137 						++iframe;
2138 						if (iframe > MainData->GetNumFrames()) break;
2139 						MainData->SetCurrentFrame(iframe);
2140 						Buffer->GetLine(LineText);
2141 					}
2142 					if (iframe <= MainData->GetNumFrames()) Buffer->BackupnLines(1);
2143 				}
2144 			}
2145 			MainData->SetCurrentFrame(MainData->GetNumFrames());
2146 		}
2147 	}
2148 	Buffer->SetFilePos(0);
2149 	// Now look for the ATOMS keyword to use as coordinates for any MOs
2150 	if (Buffer->LocateKeyWord("[ATOMS]", 7, -1)) {
2151 		float unitConv = 1.0f;	//default to angstroms
2152 		Buffer->GetLine(LineText);
2153 		if (FindKeyWord(LineText, "AU", 2) > 0) unitConv = kBohr2AngConversion;
2154 		if (lFrame->NumAtoms > 0) lFrame = MainData->AddFrame(lFrame->NumAtoms, 0);
2155 		//ugh why does everybody have to create their own cartesian format...
2156 		Buffer->GetLine(LineText);
2157 		while ((FindKeyWord(LineText, "[", 1) < 0)&&(Buffer->GetFilePos()<Buffer->GetFileSize())) {
2158 			char	token[kMaxLineLength];
2159 			long atomNum, junk;
2160 			CPoint3D pos;
2161 			//name # atomic_# x y z
2162 			int count = sscanf(LineText, "%s %ld %ld %f %f %f", token, &junk, &atomNum,
2163 							   &(pos.x), &(pos.y), &(pos.z));
2164 			pos *= unitConv;
2165 			if ((count == 6)&&((atomNum>0)&&(atomNum<120))) {
2166 				lFrame->AddAtom(atomNum, pos);
2167 			} else {
2168 				throw DataError();
2169 			}
2170 			Buffer->GetLine(LineText);
2171 		}
2172 		Buffer->SetFilePos(0);
2173 		if (Prefs->GetAutoBond())
2174 			lFrame->SetBonds(Prefs, false, ProgressInd);
2175 		//Now look for a basis set
2176 		//MacMolPlt only supports GTOs so we don't even look for the STO keyword
2177 		if (Buffer->LocateKeyWord("[GTO]", 5, -1)) {
2178 				//We really don't know how many shells there will be so this is just
2179 				//a rough estimate.
2180 			BasisSet * lbasis = new BasisSet(lFrame->NumAtoms, 5*lFrame->NumAtoms);
2181 			if (lbasis->ReadMolDenBasisSet(Buffer, lFrame->NumAtoms)) {
2182 				if (MainData->Basis) delete MainData->Basis;
2183 				MainData->Basis = lbasis;
2184 				lbasis->Normalize(false, false);
2185 			} else
2186 				delete lbasis;
2187 		}
2188 		bool sphericalHarmonics=false;
2189 		//Should look for [5D], [5D10F], [5D7F] to catch unsupported spherical harmonics
2190 		if (Buffer->LocateKeyWord("[5D]", 4, -1)||Buffer->LocateKeyWord("[5D7F]", 6, -1)) {
2191 			wxLogMessage(_("Spherical harmonic basis sets are not supported. Molecular orbitals will be skipped."));
2192 			sphericalHarmonics = true;
2193 		}
2194 		if (MainData->Basis && !sphericalHarmonics) {	//look for orbitals if we have a basis set
2195 			if (Buffer->LocateKeyWord("[MO]", 4, -1)) {
2196 				Buffer->SkipnLines(1);
2197 				lFrame->ReadMolDenOrbitals(Buffer, MainData->Basis->GetNumBasisFuncs(false));
2198 			}
2199 		}
2200 	}
2201 	Buffer->SetFilePos(0);
2202 	if (Buffer->LocateKeyWord("[FR-COORD]", 10, -1)) {	//FR-COORD section is coordinates for frequencies
2203 														//The units are bohr throughout
2204 		if (lFrame->NumAtoms > 0) lFrame = MainData->AddFrame(lFrame->NumAtoms, 0);
2205 		Buffer->SkipnLines(1);
2206 		Buffer->GetLine(LineText);
2207 		while ((LineText[0] != '[')&&(Buffer->GetFilePos()<Buffer->GetFileSize())) {
2208 			unsigned char	token[kMaxLineLength];
2209 			CPoint3D pos;
2210 			//name x y z
2211 			int rdcount = sscanf(LineText, "%s %f %f %f", token, &(pos.x), &(pos.y), &(pos.z));
2212 			pos *= kBohr2AngConversion;
2213 			if (rdcount == 4) {
2214 				long atomnum = SetAtomType(token);
2215 				if (atomnum>0)
2216 					lFrame->AddAtom(atomnum, pos);
2217 			}
2218 			Buffer->GetLine(LineText);
2219 		}
2220 		Buffer->SetFilePos(0);
2221 		if (lFrame->NumAtoms > 0) {
2222 			if (Prefs->GetAutoBond())
2223 				lFrame->SetBonds(Prefs, false, ProgressInd);
2224 			if (Buffer->LocateKeyWord("[FREQ]", 6, -1)) {
2225 				lFrame->ParseMolDenFrequencies(Buffer, Prefs);
2226 			}
2227 		}
2228 	}
2229 
2230 	return 1;
2231 }
2232 
ParseECPotentials(BufferFile * Buffer)2233 long MoleculeData::ParseECPotentials(BufferFile * Buffer) {
2234 	long	ElectronsRemoved = 0, ProtonsRemoved=0, LinePos, atom;
2235 	char	LineText[kMaxLineLength];
2236 	if (cFrame->NumAtoms <= 0) {
2237 		Buffer->SkipnLines(1);
2238 		return 0;
2239 	}
2240 	long *	zcore = new long[cFrame->NumAtoms];
2241 	if (!zcore) throw MemoryError();
2242 	for (atom=0; atom<cFrame->NumAtoms; ++atom) zcore[atom]=0;
2243 
2244 	wxFileOffset StartPos = Buffer->GetFilePos();
2245 	//This works for both ECPs and MCPs
2246 	if (!Buffer->LocateKeyWord("CP RUN REMOVES", 14, -1)) {
2247 		delete [] zcore;
2248 		return 0;
2249 	}
2250 	wxFileOffset EndPos = Buffer->GetFilePos();
2251 	Buffer->GetLine(LineText);	//read in the number of electrons removed
2252 	sscanf(&(LineText[15]),"%ld", &ElectronsRemoved);
2253 
2254 		//Now read in the number of protons removed from each atom
2255 	Buffer->SetFilePos(StartPos);
2256 	if (Buffer->LocateKeyWord("MODEL-POTENTIALS", 16, EndPos)) {
2257 		while (Buffer->LocateKeyWord("THE MCP PLACED ON ATOM", 22, EndPos)) {
2258 			Buffer->GetLine(LineText);
2259 			LinePos = FindKeyWord(LineText, "ON ATOM", 7)+7;
2260 			sscanf(&(LineText[LinePos]), "%ld", &atom);
2261 			atom--;
2262 			if (atom>=0 && atom<cFrame->NumAtoms) {
2263 				LinePos = FindKeyWord(LineText, "REMOVES ZCORE=", 14)+14;
2264 				if (LinePos>=14) {
2265 					sscanf(&(LineText[LinePos]), "%ld", &(zcore[atom]));
2266 					if (zcore[atom]>0 && zcore[atom] <= cFrame->Atoms[atom].GetNuclearCharge()) {
2267 						Basis->NuclearCharge[atom] -= zcore[atom];
2268 						ProtonsRemoved += zcore[atom];
2269 					}
2270 				}
2271 			}
2272 		}
2273 	} else {
2274 		while (Buffer->LocateKeyWord("PARAMETERS FOR", 14, EndPos)) {
2275 			Buffer->GetLine(LineText);
2276 			LinePos = FindKeyWord(LineText, "ON ATOM", 7)+7;
2277 			sscanf(&(LineText[LinePos]), "%ld", &atom);
2278 			atom--;
2279 			if (atom>=0 && atom<cFrame->NumAtoms) {
2280 				LinePos = FindKeyWord(LineText, "WITH ZCORE", 10)+10;
2281 				if (LinePos>=10) {
2282 					sscanf(&(LineText[LinePos]), "%ld", &(zcore[atom]));
2283 					if (zcore[atom]>0 && zcore[atom] <= cFrame->Atoms[atom].GetNuclearCharge()) {
2284 						Basis->NuclearCharge[atom] -= zcore[atom];
2285 						ProtonsRemoved += zcore[atom];
2286 					}
2287 				} else {
2288 					LinePos = FindKeyWord(LineText, "ARE THE SAME AS ATOM", 20)+20;
2289 					if (LinePos>=20) {
2290 						long OtherAtom;
2291 						sscanf(&(LineText[LinePos]), "%ld", &OtherAtom);
2292 						OtherAtom --;
2293 						if (OtherAtom>=0 && OtherAtom<atom) {
2294 							zcore[atom] = zcore[OtherAtom];
2295 							Basis->NuclearCharge[atom] -= zcore[atom];
2296 							ProtonsRemoved += zcore[atom];
2297 						}
2298 					}
2299 				}
2300 			}
2301 		}
2302 	}
2303 	delete [] zcore;
2304 	if (ProtonsRemoved != ElectronsRemoved) {
2305 		Basis->NuclearChargesAreValid(false);
2306 //		MessageAlert("Parse Error while reading ECP Potential Data. Use with caution!");
2307 	}
2308 	return ElectronsRemoved;
2309 }
ParseTinkerCoordinates(BufferFile * Buffer)2310 long MoleculeData::ParseTinkerCoordinates(BufferFile *Buffer) {
2311 	char		LineText[kMaxLineLength];
2312 
2313 	Frame * lFrame = cFrame;
2314 	if (!Buffer->LocateKeyWord("Cartesian Coordinates of Atoms in Bulk Model", 44)) {
2315 		return 0;
2316 	}
2317 	//Grab the tinker coordinate output
2318 
2319 	Buffer->SkipnLines(3);
2320 	wxFileOffset StartPos = Buffer->GetFilePos();
2321 	if (!(Buffer->LocateKeyWord("-----------", 11, -1))) throw DataError();
2322 	wxFileOffset test = Buffer->GetFilePos() - StartPos;
2323 	Buffer->SetFilePos(StartPos);
2324 	long numlines = Buffer->GetNumLines(test) - 1;
2325 	if (numlines > 0) {
2326 		if (!SetupFrameMemory(numlines, 0)) throw std::bad_alloc();
2327 	} else {
2328 		wxLogMessage(_("Unable to locate Tinker coordinates in file."));
2329 		throw DataError();
2330 	}
2331 	for (long i=0; i<numlines; ++i) {
2332 		long linenum;
2333 		CPoint3D	position;
2334 		unsigned char	Label[kMaxLineLength];
2335 
2336 		Buffer->GetLine(LineText);
2337 		int scannum = sscanf(LineText, "%ld %s %f %f %f", &linenum, Label, &(position.x),
2338 							 &(position.y), &(position.z));
2339 		if (scannum != 5) {
2340 			wxLogMessage(_("Error encountered while parsing coordinates."));
2341 			throw DataError();
2342 		}
2343 		long atomtype = SetAtomType(Label);
2344 		mpAtom * newAtom = lFrame->AddAtom(atomtype, position);
2345 		if (newAtom) newAtom->IsSIMOMMAtom(true);
2346 	}
2347 	return 1;
2348 }
ParseSIMMOMLogFile(BufferFile * Buffer,long EnergyPos)2349 long MolDisplayWin::ParseSIMMOMLogFile(BufferFile *Buffer, long EnergyPos) {
2350 		char		LineText[kMaxLineLength];
2351 
2352 	Frame * lFrame = MainData->cFrame;
2353 	if (!Buffer->LocateKeyWord("Cartesian Coordinates of Atoms in Bulk Model", 44, EnergyPos)) {
2354 		return 0;
2355 	}
2356 		//Grab the tinker coordinate output from the top of the file
2357 	ProgressInd->ChangeText("Reading Tinker Coordinates");
2358 	if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2359 		{throw UserCancel();}
2360 
2361 	Buffer->SkipnLines(3);
2362 	wxFileOffset StartPos = Buffer->GetFilePos();
2363 	if (!(Buffer->LocateKeyWord("-----------", 11, -1))) throw DataError();
2364 	wxFileOffset test = Buffer->GetFilePos() - StartPos;
2365 	Buffer->SetFilePos(StartPos);
2366 	long numlines = Buffer->GetNumLines(test) - 1;
2367 	if (numlines > 0) {
2368 		if (!MainData->SetupFrameMemory(numlines, 0)) throw std::bad_alloc();
2369 	} else {
2370 		wxLogMessage(_("Unable to locate Tinker coordinates in file."));
2371 		throw DataError();
2372 	}
2373 	for (long i=0; i<numlines; ++i) {
2374 			long linenum;
2375 			CPoint3D	position;
2376 			unsigned char	Label[kMaxLineLength];
2377 
2378 		Buffer->GetLine(LineText);
2379 		int scannum = sscanf(LineText, "%ld %s %f %f %f", &linenum, Label, &(position.x),
2380 				&(position.y), &(position.z));
2381 		if (scannum != 5) {
2382 			wxLogMessage(_("Error encountered while parsing coordinates."));
2383 			throw DataError();
2384 		}
2385 		long atomtype = SetAtomType(Label);
2386 		mpAtom * newAtom = lFrame->AddAtom(atomtype, position);
2387 		if (newAtom) newAtom->IsSIMOMMAtom(true);
2388 	}
2389 		//Now add the full ab initio atoms
2390 	if (Buffer->LocateKeyWord("COORDINATES (BOHR)", 16, -1)) {	//first normal (ab initio) atoms
2391 		ProgressInd->ChangeText("Reading Coordinates");
2392 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2393 			{ AbortOpen("File open canceled by user"); return 0;}
2394 
2395 		Buffer->SkipnLines(2);
2396 		StartPos = Buffer->GetFilePos();
2397 		test = Buffer->FindBlankLine() - StartPos;
2398 		numlines = Buffer->GetNumLines(test);
2399 		if (numlines > 0) {
2400 			if (!MainData->SetupFrameMemory(numlines+lFrame->NumAtoms, 0)) throw MemoryError();
2401 		} else {
2402 			wxLogMessage(_("Unable to locate coordinates in the file."));
2403 			throw DataError();
2404 		}
2405 		if (!ParseGLogLine(Buffer, lFrame, numlines, 0, &(MainData->MaxSize))) {
2406 			wxLogMessage(_("Unable to interpret coordinates."));
2407 			throw DataError();
2408 		}
2409 		lFrame->toggleAbInitioVisibility();
2410 	}
2411 	if (Prefs->GetAutoBond())
2412 		lFrame->SetBonds(Prefs, false, ProgressInd);
2413 	//attempt to read in the atomic basis set
2414 	if (Buffer->LocateKeyWord("ATOMIC BASIS SET", 16)) {
2415 		ProgressInd->ChangeText("Reading atomic basis set");
2416 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2417 		{ throw UserCancel();}
2418 		try {
2419 			MainData->ParseGAMESSBasisSet(Buffer);
2420 			BasisSet * Basis = MainData->Basis;
2421 			if (Basis) {	//generate the nuclear charge array
2422 				if (Basis->NuclearCharge[0] == -1) {
2423 					if (MainData->cFrame->NumAtoms == Basis->MapLength) {
2424 						//for the purpose of the basis set, set the charge of mm atoms to 0
2425 						for (long iatom=0; iatom<MainData->cFrame->NumAtoms; ++iatom) {
2426 							if (! MainData->cFrame->Atoms[iatom].IsSIMOMMAtom() )
2427 								Basis->NuclearCharge[iatom] = MainData->cFrame->Atoms[iatom].GetNuclearCharge();
2428 							else
2429 								Basis->NuclearCharge[iatom] = 0;
2430 						}
2431 					}
2432 				}
2433 			}
2434 		}
2435 		catch (MemoryError) {
2436 			if (MainData->Basis) delete MainData->Basis;
2437 			MainData->Basis = NULL;
2438 			MessageAlert("Insufficient Memory to read the Basis Set.");
2439 		}
2440 		catch (std::bad_alloc) {
2441 			if (MainData->Basis) delete MainData->Basis;
2442 			MainData->Basis = NULL;
2443 			MessageAlert("Insufficient Memory to read the Basis Set.");
2444 		}
2445 		catch (DataError) {
2446 			MessageAlert("An error occured while reading the basis set, basis set skipped.");
2447 			if (MainData->Basis) delete MainData->Basis;
2448 			MainData->Basis = NULL;
2449 		}
2450 	}
2451 
2452 	if (Buffer->LocateKeyWord("QM+MM Energy (Hartree):", 23)) {
2453 		Buffer->GetLine(LineText);
2454 			double FrameEnergy;
2455 		sscanf(&(LineText[24]), "%lf", &FrameEnergy);
2456 		lFrame->Energy = FrameEnergy;
2457 	}
2458 
2459 		//Read in normal modes, if present
2460 	MainData->cFrame->ParseNormalModes(Buffer, ProgressInd, Prefs);
2461 
2462 	return 1;
2463 }
OpenGAMESSlog(BufferFile * Buffer,bool Append,long flip,float offset)2464 long MolDisplayWin::OpenGAMESSlog(BufferFile *Buffer, bool Append, long flip, float offset) {
2465 	Frame *			lpFrame;
2466 	long			test=0, numlines=0, OccupiedOrbCount=0, NumFragmentAtoms=0,
2467 					NumOccAlpha=0, NumOccBeta=0, NumBetaUHFOrbs=0, LinePos,
2468 					NumCoreOrbs, NumOpenOrbs, NumGVBPairs,
2469 					ReadMP2Orbitals=1;
2470 	wxFileOffset	EnergyPos, NextFinalPos, SavedPos, StartPos;
2471 	float			*Occupancy = NULL;
2472 	bool			KeyWordFound, SIMOMM=false;
2473 	char			LineText[kMaxLineLength], token[kMaxLineLength];
2474 	BufferFile *	DatBuffer=NULL;
2475 
2476 	ProgressInd->ChangeText("Reading GAMESS log file...");
2477 	Frame * lFrame = MainData->cFrame;
2478 
2479 	EnergyPos = -1;
2480 	NextFinalPos = -1;
2481 		//First Skip over all of the input card lines, the lines are near the beginning of the file and one after another
2482 	while (Buffer->LocateKeyWord("INPUT CARD>", 11, (Buffer->GetFilePos()+50000)))
2483 		Buffer->SkipnLines(1);
2484 	wxFileOffset HeaderEndPos = Buffer->GetFilePos();	//We don't care about anything earlier than this pos.
2485 //	Buffer->LocateKeyWord("RUN TITLE", 9);	//find and skip over run title since
2486 //	Buffer->SkipnLines(3);					//it can contain any arbitrary text
2487 //	if (Buffer->LocateKeyWord("FINAL", 5)) {//locate initial energy since all options are before it
2488 //		EnergyPos = Buffer->GetFilePos();
2489 //		Buffer->SetFilePos(HeaderEndPos);
2490 //	}
2491 	std::vector<std::pair <std::string, int> > OptKeywords; //search tokens for optimizations
2492 	OptKeywords.push_back(make_pair (std::string("BEGINNING GEOMETRY SEARCH POINT"), 0));
2493 	OptKeywords.push_back(make_pair (std::string("1NSERCH"), 1));
2494 
2495 	if (Append) {
2496 		Buffer->LocateKeyWord("RUN TITLE", 9);	//find and skip over run title since
2497 		Buffer->SkipnLines(3);					//it can contain any arbitrary text
2498 		if (Buffer->LocateFinalEnergy()) {//locate initial energy since all options are before it
2499 			EnergyPos = Buffer->GetFilePos();
2500 			Buffer->SetFilePos(HeaderEndPos);
2501 		}
2502 		if (!MainData->InputOptions) throw MemoryError();
2503 			//Determine the number of occupied alpha and beta orbitals
2504 		if (Buffer->LocateKeyWord("NUMBER OF OCCUPIED ORBITALS (ALPHA)", 35, EnergyPos)) {
2505 			Buffer->GetLine(LineText);
2506 			LinePos = FindKeyWord(LineText, "=", 1) + 1;
2507 			sscanf(&(LineText[LinePos]),"%ld", &NumOccAlpha);
2508 		}
2509 		if (Buffer->LocateKeyWord("NUMBER OF OCCUPIED ORBITALS (BETA )", 35, EnergyPos)) {
2510 			Buffer->GetLine(LineText);
2511 			LinePos = FindKeyWord(LineText, "=", 1) + 1;
2512 			sscanf(&(LineText[LinePos]),"%ld", &NumOccBeta);
2513 		}
2514 		SavedPos = Buffer->GetFilePos();
2515 			//Check for ECP/MCP type run which reduces the number of occupied orbitals
2516 		if (Buffer->LocateKeyWord("CP RUN REMOVES", 14, EnergyPos)) {
2517 			Buffer->GetLine(LineText);	//read in the number of electrons removed
2518 			sscanf(&(LineText[15]),"%ld", &test);
2519 			test /= 2;
2520 			NumOccAlpha -= test;
2521 			if (NumOccAlpha < 0) NumOccAlpha = 0;	//Oops!
2522 			if (NumOccBeta) NumOccBeta -= test;
2523 			if (NumOccBeta<0) NumOccBeta = 0;
2524 			Buffer->SetFilePos(SavedPos);
2525 		}
2526 		if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {	//Calculate the # of occupied MOs by parsing the DRT info
2527 			if (Buffer->LocateKeyWord("GUGA DISTINCT ROW TABLE", 23, EnergyPos)) {
2528 					long nfzc=0, ndoc=0, nmcc=0, naos=0, nbos=0, nalp=0, nval=0;
2529 				if (Buffer->LocateKeyWord("NFZC=",5, EnergyPos)) {
2530 					Buffer->GetLine(LineText);
2531 					sscanf(&(LineText[6]), "%ld NDOC= %ld", &nfzc, &ndoc);
2532 					Buffer->GetLine(LineText);
2533 					sscanf(LineText, " NMCC= %ld NAOS= %ld", &nmcc, &naos);
2534 					Buffer->GetLine(LineText);
2535 					sscanf(LineText, " NBOS= %ld", &nbos);
2536 					Buffer->GetLine(LineText);
2537 					sscanf(LineText, " NALP= %ld", &nalp);
2538 					Buffer->GetLine(LineText);
2539 					sscanf(LineText, " NVAL= %ld", &nval);
2540 					OccupiedOrbCount = nfzc + ndoc + nmcc + naos + nbos + nalp + nval;
2541 				}
2542 			}//GAMESS wasn't nice enough to punch out the # of occupied MO's
2543 			if (!OccupiedOrbCount) OccupiedOrbCount = MainData->GetNumBasisFunctions();
2544 			NumOccAlpha = OccupiedOrbCount;	//setup for localized orbs
2545 		}
2546 	//	test = MainData->InputOptions->Control->SetSCFType(&(LineText[LinePos]));
2547 		if (MainData->InputOptions->Control->GetSCFType()==GAMESS_UHF)
2548 			NumBetaUHFOrbs = NumOccBeta;	//Only seperate Beta spin orbs for UHF wavefunctions
2549 		else NumOccBeta = 0;
2550 		if (IRCRun==MainData->InputOptions->Control->GetRunType())
2551 			return this->OpenGAMESSIRCLog(Buffer, flip, offset, NumOccAlpha, NumOccBeta, NumFragmentAtoms);
2552 		if (DRCRun==MainData->InputOptions->Control->GetRunType())
2553 			return this->OpenGAMESSDRC(Buffer, true, Append, flip,offset);
2554 		else
2555 			while (lFrame->NextFrame) lFrame = lFrame->NextFrame;
2556 		if (MainData->InputOptions->Control->GetRunType() == GLOBOPRun)
2557 			return OpenGAMESSGlobOpLog(Buffer, NumOccAlpha, NumOccBeta, NumFragmentAtoms);
2558 	} else {
2559 		MainData->InputOptions = new InputData;
2560 		if (!MainData->InputOptions) throw MemoryError();
2561 		enum {
2562 			final=0,
2563 			headerEnd,
2564 			basisOptions,
2565 			runTitle,
2566 			pointGroup,
2567 			QMMM,
2568 			coords,
2569 			EFRAG,
2570 			basisSet,
2571 			molCharge,
2572 			multiplicity,
2573 			occAlphaOrbs,
2574 			occBetaOrbs,
2575 			ECPoptions,
2576 			gridDFT,
2577 			gridFreeDFT,
2578 			controlOptions,
2579 			systemOptions,
2580 			GVBOptions,
2581 			abnormalTerm
2582 		};
2583 		std::vector<std::pair <std::string, int> > HeaderKeywords;
2584 //		HeaderKeywords.push_back(make_pair (std::string("FINAL"), (int) final));
2585 		HeaderKeywords.push_back(make_pair (std::string("DONE SETTING UP THE RUN"), (int) headerEnd));
2586 		HeaderKeywords.push_back(make_pair (std::string("BASIS OPTIONS"), (int) basisOptions));
2587 		HeaderKeywords.push_back(make_pair (std::string("RUN TITLE"), (int) runTitle));
2588 		HeaderKeywords.push_back(make_pair (std::string("POINT GROUP"), (int) pointGroup));
2589 		HeaderKeywords.push_back(make_pair (std::string("QMMM PROCEDURE IS ON"), (int) QMMM));
2590 		HeaderKeywords.push_back(make_pair (std::string("COORDINATES (BOHR)"), (int) coords));
2591 		HeaderKeywords.push_back(make_pair (std::string("READING $EFRAG GROUP"), (int) EFRAG));
2592 		HeaderKeywords.push_back(make_pair (std::string("ATOMIC BASIS SET"), (int) basisSet));
2593 		HeaderKeywords.push_back(make_pair (std::string("CHARGE OF MOLECULE"), (int) molCharge));
2594 		HeaderKeywords.push_back(make_pair (std::string("MULTIPLICITY"), (int) multiplicity));
2595 		HeaderKeywords.push_back(make_pair (std::string("NUMBER OF OCCUPIED ORBITALS (ALPHA)"), (int) occAlphaOrbs));
2596 		HeaderKeywords.push_back(make_pair (std::string("NUMBER OF OCCUPIED ORBITALS (BETA )"), (int) occBetaOrbs));
2597 		HeaderKeywords.push_back(make_pair (std::string("ECP POTENTIALS"), (int) ECPoptions));
2598 		HeaderKeywords.push_back(make_pair (std::string("MODEL-POTENTIALS"), (int) ECPoptions));
2599 		HeaderKeywords.push_back(make_pair (std::string("GRID-BASED DFT"), (int) gridDFT));
2600 		HeaderKeywords.push_back(make_pair (std::string("MODEL-POTENTIALS"), (int) gridFreeDFT));
2601 		HeaderKeywords.push_back(make_pair (std::string("CONTRL OPTIONS"), (int) controlOptions));
2602 		HeaderKeywords.push_back(make_pair (std::string("JOB OPTIONS"), (int) controlOptions));
2603 		HeaderKeywords.push_back(make_pair (std::string("SYSTEM OPTIONS"), (int) systemOptions));
2604 		HeaderKeywords.push_back(make_pair (std::string("EXECUTION OF GAMESS TERMINATED -ABNORMALLY- AT"), (int) abnormalTerm));
2605 
2606 		bool headerDone=false;
2607 		bool controlOptionsFound = false;
2608 		while (! Buffer->Eof() && ! headerDone) {
2609 			if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2610 			{ throw UserCancel();}
2611 			int kw;
2612 			if (-1 < (kw = Buffer->LocateKeyWord(HeaderKeywords))) {
2613 				wxFileOffset keywordPosition = Buffer->GetFilePos();
2614 				switch (kw) {
2615 					case final:
2616 						headerDone = true;
2617 						EnergyPos = Buffer->GetFilePos();
2618 						break;
2619 					case headerEnd:
2620 						//Until recently this was printed out at the beginning of the header output - useless!
2621 						//To account for that only consider this done if we've found the coordinates
2622 						if (lFrame->NumAtoms > 0) headerDone = true;
2623 						Buffer->SkipnLines(1);
2624 						break;
2625 					case basisOptions:
2626 	//					KeyWordFound = Buffer->LocateKeyWord("BASIS OPTIONS", 13, EnergyPos);
2627 	//					if (KeyWordFound) {	//Read in the basis set information (for user reference)
2628 							ProgressInd->ChangeText("Reading Basis information");
2629 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2630 							{ throw UserCancel();}
2631 							MainData->ReadBasisOptions(Buffer);
2632 	//					}
2633 						break;
2634 					case runTitle:
2635 		//				if (Buffer->LocateKeyWord("RUN TITLE", 9, EnergyPos)) {	//Read the 1 line run label
2636 							Buffer->SkipnLines(2);
2637 							Buffer->GetLine(LineText);
2638 							MainData->InputOptions->Data->SetTitle(LineText, strlen(LineText));
2639 		//				}
2640 						break;
2641 					case pointGroup:
2642 //						if (Buffer->LocateKeyWord("POINT GROUP", 11, EnergyPos)) {	//Setup molecular point group
2643 							Buffer->GetLine(LineText);
2644 							LinePos = FindKeyWord(LineText, "MOLECULE IS", 11);
2645 							if (LinePos > -1) {
2646 								sscanf(&(LineText[LinePos+12]), "%s", token);
2647 								MainData->InputOptions->Data->SetPointGroup(token);
2648 							}
2649 
2650 							Buffer->GetLine(LineText);
2651 							LinePos = FindKeyWord(LineText, "AXIS IS", 7);
2652 							if (LinePos > -1) {
2653 								sscanf(&(LineText[LinePos+8]),"%ld", &test);
2654 								MainData->InputOptions->Data->SetPointGroupOrder(test);
2655 							}
2656 //						}
2657 						break;
2658 					case QMMM:
2659 //						Buffer->SetFilePos(HeaderEndPos);
2660 //						if (Buffer->LocateKeyWord("QMMM PROCEDURE IS ON", 20, EnergyPos)) {
2661 							//If this is a simmom type run then switch to that routine since the format is
2662 							//significantly different
2663 							//			return (ParseSIMMOMLogFile(Buffer, EnergyPos));
2664 							SIMOMM=true;
2665 							ProgressInd->ChangeText("Reading Tinker Coordinates");
2666 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2667 							{throw UserCancel();}
2668 							MainData->ParseTinkerCoordinates(Buffer);
2669 							//The ab initio atoms will be added below
2670 //						}
2671 						break;
2672 					case coords:
2673 						//locate the input set of coordinates (present in every file)
2674 	//					if (Buffer->LocateKeyWord("COORDINATES (BOHR)", 16, EnergyPos)) {	//first normal (ab initio) atoms
2675 							ProgressInd->ChangeText("Reading Coordinates");
2676 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2677 							{ AbortOpen("File open canceled by user"); return 0;}
2678 
2679 							Buffer->SkipnLines(2);
2680 							StartPos = Buffer->GetFilePos();
2681 							test = Buffer->FindBlankLine() - StartPos;
2682 							numlines = Buffer->GetNumLines(test);
2683 							if (numlines > 0) {
2684 								if (!MainData->SetupFrameMemory(numlines+lFrame->NumAtoms, 0)) throw MemoryError();
2685 							} else {
2686 								wxLogMessage(_("Unable to locate coordinates in the file."));
2687 								throw DataError();
2688 							}
2689 							if (!ParseGLogLine(Buffer, lFrame, numlines, 0, &(MainData->MaxSize))) {
2690 								wxLogMessage(_("Unable to interpret coordinates."));
2691 								throw DataError();
2692 							}
2693 	//					}
2694 						break;
2695 					case EFRAG:
2696 //						StartPos = Buffer->GetFilePos();		//next look for fragments
2697 //						if (Buffer->LocateKeyWord("READING $EFRAG GROUP", 20, EnergyPos)) {	//ughh fragments!
2698 							NumFragmentAtoms = MainData->ReadInitialFragmentCoords(Buffer);
2699 //							Buffer->SetFilePos(StartPos);
2700 //						}
2701 						break;
2702 					case basisSet:
2703 						//Read in the atomic basis set (if present) and keep it in case we find MO vectors later
2704 						//if it is not located and read in correctly MO vectors will also be skipped
2705 	//					if (Buffer->LocateKeyWord("ATOMIC BASIS SET", 16, EnergyPos)) {
2706 					{
2707 							ProgressInd->ChangeText("Reading atomic basis set");
2708 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
2709 							{ throw UserCancel();}
2710 							try {
2711 								MainData->ParseGAMESSBasisSet(Buffer);
2712 								BasisSet * Basis = MainData->Basis;
2713 								if (Basis && SIMOMM) {	//generate the nuclear charge array
2714 									if (Basis->NuclearCharge[0] == -1) {
2715 										if (MainData->cFrame->NumAtoms == Basis->MapLength) {
2716 											//for the purpose of the basis set, set the charge of mm atoms to 0
2717 											for (long iatom=0; iatom<MainData->cFrame->NumAtoms; ++iatom) {
2718 												if (! MainData->cFrame->Atoms[iatom].IsSIMOMMAtom() )
2719 													Basis->NuclearCharge[iatom] = MainData->cFrame->Atoms[iatom].GetNuclearCharge();
2720 												else
2721 													Basis->NuclearCharge[iatom] = 0;
2722 											}
2723 										}
2724 									}
2725 								}
2726 							}
2727 							catch (MemoryError) {
2728 								if (MainData->Basis) delete MainData->Basis;
2729 								MainData->Basis = NULL;
2730 								MessageAlert("Insufficient Memory to read the Basis Set.");
2731 							}
2732 							catch (std::bad_alloc) {
2733 								if (MainData->Basis) delete MainData->Basis;
2734 								MainData->Basis = NULL;
2735 								MessageAlert("Insufficient Memory to read the Basis Set.");
2736 							}
2737 							catch (DataError) {
2738 								MessageAlert("An error occured while reading the basis set, basis set skipped.");
2739 								if (MainData->Basis) delete MainData->Basis;
2740 								MainData->Basis = NULL;
2741 							}
2742 						}
2743 						break;
2744 					case molCharge:
2745 						//Read in charge and multiplicity
2746 //						if (Buffer->LocateKeyWord("CHARGE OF MOLECULE", 18, EnergyPos)) {
2747 							Buffer->GetLine(LineText);
2748 							LinePos = FindKeyWord(LineText, "=", 1) + 1;
2749 							long charge;
2750 							sscanf(&(LineText[LinePos]),"%ld", &charge);
2751 							MainData->InputOptions->Control->SetCharge(charge);
2752 //						}
2753 						break;
2754 					case multiplicity:
2755 						//There are now two forms of this, "SPIN MULTIPLICITY" and "STATE MULTIPLICITY"
2756 						//however, either should appear soon after the CHARGE.
2757 //						if (Buffer->LocateKeyWord("MULTIPLICITY", 12, Buffer->GetFilePos()+100)) {
2758 							Buffer->GetLine(LineText);
2759 							LinePos = FindKeyWord(LineText, "=", 1) + 1;
2760 							long Multiplicity;
2761 							sscanf(&(LineText[LinePos]),"%ld", &Multiplicity);
2762 							MainData->InputOptions->Control->SetMultiplicity(Multiplicity);
2763 //						}
2764 						break;
2765 					case occAlphaOrbs:
2766 						//Determine the number of occupied alpha and beta orbitals
2767 //						if (Buffer->LocateKeyWord("NUMBER OF OCCUPIED ORBITALS (ALPHA)", 35, EnergyPos)) {
2768 							Buffer->GetLine(LineText);
2769 							LinePos = FindKeyWord(LineText, "=", 1) + 1;
2770 							sscanf(&(LineText[LinePos]),"%ld", &NumOccAlpha);
2771 //						}
2772 						break;
2773 					case occBetaOrbs:
2774 //						if (Buffer->LocateKeyWord("NUMBER OF OCCUPIED ORBITALS (BETA )", 35, EnergyPos)) {
2775 							Buffer->GetLine(LineText);
2776 							LinePos = FindKeyWord(LineText, "=", 1) + 1;
2777 							sscanf(&(LineText[LinePos]),"%ld", &NumOccBeta);
2778 //						}
2779 						break;
2780 					case ECPoptions:
2781 //						SavedPos = Buffer->GetFilePos();
2782 						//Check for ECP type run which reduces the number of occupied orbitals
2783 //						if (Buffer->LocateKeyWord("ECP POTENTIALS", 14, EnergyPos)||
2784 //							Buffer->LocateKeyWord("MODEL-POTENTIALS", 16, EnergyPos)) {
2785 							test = MainData->ParseECPotentials(Buffer);
2786 							test /= 2;
2787 							NumOccAlpha -= test;
2788 							if (NumOccAlpha < 0) NumOccAlpha = 0;	//Oops!
2789 							if (NumOccBeta) NumOccBeta -= test;
2790 							if (NumOccBeta<0) NumOccBeta = 0;
2791 //							Buffer->SetFilePos(SavedPos);
2792 //						}
2793 						break;
2794 					case gridDFT:
2795 						//DFT options
2796 	//					if (Buffer->LocateKeyWord("GRID-BASED DFT", 14, EnergyPos))
2797 					{
2798 							Buffer->SkipnLines(2);
2799 							Buffer->GetLine(LineText);
2800 							char DFTTYP[kMaxLineLength];
2801 							if (ReadStringKeyword(LineText, "DFTTYP", DFTTYP)) {
2802 								MainData->InputOptions->DFT.SetFunctional(DFTTYP);
2803 								if (MainData->InputOptions->DFT.GetFunctional() > 0)
2804 									MainData->InputOptions->Control->UseDFT(true);
2805 								else
2806 									wxLogMessage(_("Unknown DFTTYP detected, ignored."));
2807 							}
2808 					}
2809 							break;
2810 					case gridFreeDFT:
2811 					//	 else if (Buffer->LocateKeyWord("GRID-FREE DFT", 13, EnergyPos))
2812 					{
2813 							Buffer->SkipnLines(2);
2814 							Buffer->GetLine(LineText);
2815 							char DFTTYP[kMaxLineLength];
2816 							MainData->InputOptions->DFT.SetMethodGrid(false);
2817 							if (ReadStringKeyword(LineText, "DFTTYP", DFTTYP)) {
2818 								MainData->InputOptions->DFT.SetFunctional(DFTTYP);
2819 								if (MainData->InputOptions->DFT.GetFunctional() > 0)
2820 									MainData->InputOptions->Control->UseDFT(true);
2821 								else
2822 									wxLogMessage(_("Unknown DFTTYP detected, ignored."));
2823 							}
2824 						}
2825 						break;
2826 					case controlOptions:
2827 						//Now read other Control options
2828 //						if (!Buffer->LocateKeyWord("CONTRL OPTIONS", 14, EnergyPos)) {
2829 //							// $CONTRL OPTIONS used to be JOB OPTIONS so check for it too
2830 //							if (!Buffer->LocateKeyWord("JOB OPTIONS", 11, EnergyPos)) {
2831 //								//Unable to locate the job options, perhaps the run terminated abnormally?
2832 //								if (Buffer->LocateKeyWord("EXECUTION OF GAMESS TERMINATED -ABNORMALLY- AT", 46))
2833 //									wxLogMessage(_("GAMESS terminated abnormally. Please check the log file for details."));
2834 //								wxLogMessage(_("Unable to locate run options."));
2835 //								return 0;
2836 //							}
2837 //						}
2838 						MainData->ReadControlOptions(Buffer);
2839 						controlOptionsFound = true;
2840 						if (MainData->InputOptions->Control->GetSCFType()==GAMESS_GVB)
2841 							HeaderKeywords.push_back(make_pair (std::string("ROHF-GVB INPUT PARAMETERS"), (int) GVBOptions));
2842 						break;
2843 					case systemOptions:
2844 						//System group is immediately after the control group
2845 			//			if (Buffer->LocateKeyWord("SYSTEM OPTIONS", 14, EnergyPos)) {
2846 							MainData->InputOptions->System->ReadSystemOptions(Buffer);
2847 			//			}
2848 						break;
2849 					case GVBOptions:
2850 						Buffer->SkipnLines(3);
2851 						Buffer->GetLine(LineText);
2852 						sscanf(LineText, " NORB   =%ld NCO    =%ld", &test, &NumCoreOrbs);
2853 						MainData->InputOptions->SCF->SetGVBNumCoreOrbs(NumCoreOrbs);
2854 						NumOccAlpha = test;
2855 						Buffer->GetLine(LineText);
2856 						sscanf(LineText, " NPAIR  =%ld NSETO  =%ld", &NumGVBPairs, &NumOpenOrbs);
2857 						MainData->InputOptions->SCF->SetGVBNumPairs(NumGVBPairs);
2858 						if (NumOpenOrbs>0) {
2859 							//If there are Open Shells we need to parse the degeneracy of each shell
2860 							//This is a space separated list starting with NO =
2861 							//In theory it could be more than a line, but that is highly unlikely
2862 							Buffer->GetLine(LineText);
2863 							int nchar = 0;
2864 							if (sscanf(LineText, " NO   =%n", &nchar) == 0) {
2865 								for (int ishell=0; ishell<NumOpenOrbs; ishell++) {
2866 									int nchar2=0;
2867 									long shellDeg;
2868 									if (sscanf(&(LineText[nchar]), "%ld%n", &shellDeg, &nchar2) == 1) {
2869 										nchar += nchar2;
2870 										MainData->InputOptions->SCF->AddGVBOpenShellDeg(shellDeg);
2871 									} else
2872 										break;
2873 								}
2874 							}
2875 							//Set this after reading in NO so no need to clear the NO array
2876 							MainData->InputOptions->SCF->SetGVBNumOpenShells(NumOpenOrbs);
2877 						}
2878 							Occupancy = new float[MainData->GetNumBasisFunctions()];
2879 							if (!Occupancy) throw MemoryError();
2880 							for (test=0; test<MainData->GetNumBasisFunctions(); ++test) Occupancy[test] = 0.0f;
2881 							for (test=0; test<NumCoreOrbs; ++test) Occupancy[test] = 2.0f;
2882 							if (NumOpenOrbs > 0) {	//Parse the occupancies of the open shells
2883 								if (Buffer->LocateKeyWord("F VECTOR (OCCUPANCIES)", 23)) {
2884 									//Next find the first row indicating the doubly occupied orbitals
2885 									Buffer->SkipnLines(1);
2886 									bool foundPos=false;
2887 									int lineCount=0;
2888 									while (!foundPos) {
2889 										int test;
2890 										Buffer->GetLine(LineText);
2891 										sscanf(LineText, "%d", &test);
2892 										if (test == 1) {	//If there are no cores then the first line is needed below.
2893 											if (NumCoreOrbs<=0) {
2894 												Buffer->BackupnLines(1);
2895 											}
2896 											foundPos = true;
2897 										}
2898 										lineCount++;
2899 										if (lineCount > 10) {
2900 											wxLogMessage(_("Warning: Unable to parse GVB F Vector Occupancies."));
2901 											break;
2902 										}
2903 									}
2904 									if (foundPos) {
2905 										int iorb = NumCoreOrbs;
2906 										for (int nShell=0; nShell<NumOpenOrbs; ++nShell) {
2907 											Buffer->GetLine(LineText);
2908 											float occTemp;
2909 											sscanf(LineText, "%ld %f", &test, &occTemp);
2910 											for (int jj=0; jj<MainData->InputOptions->SCF->GetGVBOpenShellDeg(nShell); jj++) {
2911 												Occupancy[iorb] = occTemp * 2;	//occupancies are listed as % of orbital filled
2912 												iorb++;
2913 											}
2914 										}
2915 									}
2916 								}
2917 							}
2918 	//					}
2919 						break;
2920 					case abnormalTerm:
2921 					//		if (Buffer->LocateKeyWord("EXECUTION OF GAMESS TERMINATED -ABNORMALLY- AT", 46))
2922 						wxLogMessage(_("GAMESS terminated abnormally. Please check the log file for details."));
2923 						return 0;
2924 						break;
2925 				}
2926 					//If still positioned at the keyword, must advance or there will be a loop.
2927 				if (keywordPosition == Buffer->GetFilePos()) Buffer->SkipnLines(1);
2928 			} else break;
2929 		}
2930 		if (lFrame->NumAtoms <= 0) {	//initial coordinates not found! Abort!
2931 			wxLogMessage(_("Unable to locate coordinates in the file."));
2932 			throw DataError();
2933 		}
2934 		if (Prefs->GetAutoBond())
2935 			lFrame->SetBonds(Prefs, false, ProgressInd);
2936 
2937 		if (!controlOptionsFound) wxLogMessage(_("Unable to locate run options. Attempting to continue"));
2938 
2939 			//Now that the $control options are read in normalize the basis set (normf and normp are needed)
2940 		if (MainData->Basis) MainData->Basis->Normalize(MainData->InputOptions->Control->GetNormP(),
2941 			MainData->InputOptions->Control->GetNormF());
2942 			//plot the rms gradient by default for run types: gradient, optimize, and sadpoint
2943 		if ((MainData->InputOptions->Control->GetRunType()==4)||
2944 	//		(MainData->InputOptions->Control->GetRunType()==2)|| could add gradient, but output is different
2945 			(MainData->InputOptions->Control->GetRunType()==6)) {
2946 			GraphOptions * lPOpts = Prefs->GetGraphOptions();
2947 			EnergyOptions * lEOpts = Prefs->GetEnergyOptions();
2948 			lEOpts->SetPlotOther(true);
2949 			lPOpts->SetPlotRMSGradient(true);
2950 		}
2951 		if (MainData->InputOptions->Control->GetSCFType()==GAMESS_UHF)
2952 				//Only seperate Beta spin orbs for UHF wavefunctions
2953 			NumBetaUHFOrbs = MainData->GetNumBasisFunctions();
2954 		else if (MainData->InputOptions->Control->GetSCFType()!=GAMESS_ROHF)
2955 			NumOccBeta = 0;
2956 
2957 		if (MainData->InputOptions->Control->GetRunType() == GLOBOPRun)
2958 			return OpenGAMESSGlobOpLog(Buffer, NumOccAlpha, NumOccBeta, NumFragmentAtoms);
2959 
2960 		HeaderEndPos = Buffer->GetFilePos();
2961 		if (Buffer->LocateFinalEnergy()) {//locate initial energy
2962 			EnergyPos = Buffer->GetFilePos();
2963 			Buffer->SetFilePos(HeaderEndPos);
2964 		}
2965 
2966 		if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {	//Calculate the # of occupied MOs by parsing the DRT info
2967 			wxFileOffset filePos = Buffer->GetFilePos();
2968 			if (Buffer->LocateKeyWord("GUGA DISTINCT ROW TABLE", 23, EnergyPos)) {
2969 					long nfzc=0, ndoc=0, nmcc=0, naos=0, nbos=0, nalp=0, nval=0;
2970 				if (Buffer->LocateKeyWord("NFZC=",5)) {
2971 					Buffer->GetLine(LineText);
2972 					sscanf(&(LineText[6]), "%ld NDOC= %ld", &nfzc, &ndoc);
2973 					Buffer->GetLine(LineText);
2974 					sscanf(LineText, " NMCC= %ld NAOS= %ld", &nmcc, &naos);
2975 					Buffer->GetLine(LineText);
2976 					sscanf(LineText, " NBOS= %ld", &nbos);
2977 					Buffer->GetLine(LineText);
2978 					sscanf(LineText, " NALP= %ld", &nalp);
2979 					Buffer->GetLine(LineText);
2980 					sscanf(LineText, " NVAL= %ld", &nval);
2981 					OccupiedOrbCount = nfzc + ndoc + nmcc + naos + nbos + nalp + nval;
2982 				}
2983 			} else if ((Buffer->LocateKeyWord("AMES LABORATORY DETERMINANTAL FULL CI", 37,
2984 					EnergyPos))||(Buffer->LocateKeyWord("DIRECT DETERMINANT ORMAS-CI INPUT SORTER", 40, EnergyPos))) {
2985 				if (Buffer->LocateKeyWord("NUMBER OF OCCUPIED ORBITALS",27,800+Buffer->GetFilePos())) {
2986 					Buffer->GetLine(LineText);
2987 					sscanf(&(LineText[30]), " = %ld", &OccupiedOrbCount);
2988 				}
2989 			}//GAMESS wasn't nice enough to punch out the # of occupied MO's
2990 			if (!OccupiedOrbCount) OccupiedOrbCount = MainData->GetNumBasisFunctions();
2991 			NumOccAlpha = OccupiedOrbCount;	//setup for localized orbs
2992 			Buffer->SetFilePos(filePos);	//reset the file position
2993 		}
2994 		//Could read GUESS options here...
2995 		//Look for the initial guess orbitals in case the user requested them
2996 		if (MainData->GetNumBasisFunctions() > 0) {
2997 			if (Buffer->LocateKeyWord("      INITIAL GUESS ORBITALS", 28, EnergyPos)) {
2998 				lFrame->ParseGAMESSGuessVectors(Buffer, MainData->GetNumBasisFunctions(),
2999 												(TypeOfWavefunction)MainData->InputOptions->Control->GetSCFType(),
3000 												ProgressInd);
3001 			}
3002 		}
3003 
3004 	// Switch to DRC routine if neccessary
3005 		if (MainData->InputOptions->Control->GetRunType() == DRCRun) {
3006 			lFrame->NumAtoms = lFrame->NumBonds = 0;
3007 			return this->OpenGAMESSDRC(Buffer, true, Append, flip,offset);
3008 		} else if (MainData->InputOptions->Control->GetRunType() == IRCRun) {
3009 			//Confirm that the first energy is before the start of the IRC
3010 			if (Buffer->LocateKeyWord("JUMPING OFF SADDLE POINT ALONG THE IMAGINARY NORMAL MODE", 55)) {
3011 				wxFileOffset test = Buffer->GetFilePos();
3012 				if (EnergyPos > test) {
3013 					return OpenGAMESSIRCLog(Buffer, flip, offset, NumOccAlpha, NumOccBeta, NumFragmentAtoms);
3014 				}
3015 			}
3016 		} else if (MainData->InputOptions->Control->GetRunType() == VSCFRun) {
3017 			//Read in normal modes, if present
3018 			if (Buffer->LocateKeyWord("NORMAL COORDINATE ANALYSIS", 25, EnergyPos))
3019 				MainData->cFrame->ParseNormalModes(Buffer, ProgressInd, Prefs);
3020 		}
3021 
3022 		if (EnergyPos > 0) {
3023 			Buffer->SetFilePos(EnergyPos);
3024 			Buffer->GetLine(LineText);
3025 			LinePos = FindKeyWord(LineText, "ENERGY", 6);
3026 			if (LinePos > -1) {
3027 				int k = sscanf(&(LineText[LinePos+10]), "%lf", &(lFrame->Energy));
3028 				if (k == 0) {	//Crappy fragment output is different
3029 					k = FindKeyWord(&(LineText[LinePos]), "=", 1);
3030 					if (LinePos > -1)
3031 						sscanf(&(LineText[LinePos+k+1]), "%lf", &(lFrame->Energy));
3032 				}
3033 				if (MainData->InputOptions->Control->GetMPLevel()) {	//MP2 run so look for MP2 energy
3034 					StartPos = Buffer->GetFilePos();
3035 					if (Buffer->LocateKeyWord("E(MP2)=", 7)) {
3036 						double mpE;
3037 						Buffer->GetLine(LineText);
3038 						sscanf(&(LineText[8]), "%lf", &(mpE));
3039 						lFrame->Energies.push_back(EnergyValue(mpE, PT2Energy));
3040 					}
3041 					Buffer->SetFilePos(StartPos);
3042 				}
3043 			}
3044 				//Attempt to read in orbitals for first geometry
3045 			SavedPos = Buffer->GetFilePos();
3046 			NextFinalPos = -1;
3047 			if (Buffer->LocateFinalEnergy()) NextFinalPos = Buffer->GetFilePos();
3048 			Buffer->SetFilePos(SavedPos);
3049 			if (MainData->Basis) {
3050 				try {
3051 					if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {
3052 							bool ReadOrbs = false;
3053 						if (Buffer->LocateKeyWord("MCSCF NATURAL ORBITALS", 22, NextFinalPos)) {
3054 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3055 								ReadOrbs = true;
3056 							else Buffer->SetFilePos(SavedPos);
3057 						} else if (Buffer->LocateKeyWord("MCSCF OPTIMIZED ORBITALS", 24, NextFinalPos)) {
3058 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3059 								ReadOrbs = true;
3060 							else Buffer->SetFilePos(SavedPos);
3061 						} else if (Buffer->LocateKeyWord("-MCHF- NATURAL ORBITALS", 23, NextFinalPos)) {
3062 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3063 								ReadOrbs = true;
3064 							else Buffer->SetFilePos(SavedPos);
3065 						} else if (Buffer->LocateKeyWord("-MCHF- OPTIMIZED ORBITALS", 25, NextFinalPos)) {
3066 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3067 								ReadOrbs = true;
3068 							else Buffer->SetFilePos(SavedPos);
3069 						} else if (Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos)) {
3070 							Buffer->SetFilePos(Buffer->FindBlankLine());
3071 							Buffer->SkipnLines(1);
3072 							lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
3073 								MainData->GetNumBasisFunctions(), 0, NumOccAlpha, NumOccBeta,
3074 								(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
3075 		//					lFrame->ExchangeEigenVectors();
3076 						}
3077 						if (ReadOrbs)
3078 							lFrame->ParseGAMESSMCSCFVectors(Buffer, MainData->GetNumBasisFunctions(),
3079 								OccupiedOrbCount, ProgressInd);
3080 					} else {
3081 						if (MainData->InputOptions->Control->GetSCFType() == GAMESS_GVB) {
3082 							if (Buffer->LocateKeyWord("PAIR INFORMATION", 16, NextFinalPos)) {
3083 								ReadGVBOccupancy(Buffer, NumGVBPairs, MainData->GetNumBasisFunctions(),
3084 									Occupancy);
3085 							}
3086 						}
3087 //						if (MainData->InputOptions->Control->GetCIType() == CI_CIS) {
3088 //							//CIS output includes the EIGENVECTORS token
3089 //							//I think the regular EIGENVECTORS would be before the CIS line???
3090 //							long bp = Buffer->GetFilePos();
3091 //							KeyWordFound = Buffer->LocateKeyWord("EIGENVECTORS", 12, NextFinalPos);
3092 //							Buffer->BackupnLines(1);
3093 //							if (Buffer->LocateKeyWord("CIS EIGENVALUES", 14, 80+Buffer->GetFilePos())) {
3094 //								Buffer->SkipnLines(1);
3095 //								KeyWordFound = Buffer->LocateKeyWord("EIGENVECTORS", 12, NextFinalPos);
3096 //								if (!KeyWordFound) {
3097 //									Buffer->SetFilePos(bp);
3098 //									KeyWordFound = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3099 //									Buffer->BackupnLines(1);
3100 //									if (Buffer->LocateKeyWord("# MOLECULAR ORBITALS =", 22)) {
3101 //										Buffer->SkipnLines(1);
3102 //										KeyWordFound = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3103 //										if (!KeyWordFound) Buffer->SetFilePos(bp);
3104 //									}
3105 //								}
3106 //							}
3107 //						} else {
3108 							KeyWordFound = Buffer->LocateKeyWord("   EIGENVECTORS", 15, NextFinalPos);
3109 							if (!KeyWordFound)
3110 								KeyWordFound = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3111 //						}
3112 						if (KeyWordFound) {
3113 								//skip over the line to the start of the orbital blocks
3114 								//There is always a blank line before the orbs, but there may a '---' divider line after the key line just found
3115 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos())) {
3116 								Buffer->SetFilePos(Buffer->FindBlankLine());
3117 								Buffer->SkipnLines(1);
3118 								ProgressInd->ChangeText("Reading eigenvectors");
3119 								if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3120 									{ AbortOpen("File open canceled by user"); return 0;}
3121 								OrbitalRec * OrbSet = lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
3122 									MainData->GetNumBasisFunctions(), NumBetaUHFOrbs, NumOccAlpha, NumOccBeta,
3123 									(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
3124 								if ((MainData->InputOptions->Control->GetSCFType() == GAMESS_GVB)&&(OrbSet!=NULL)) {
3125 									//Add the Occupancy vector for GVB wavefunctions
3126 									OrbSet->SetOccupancy(Occupancy, MainData->GetNumBasisFunctions());
3127 								}
3128 							} else Buffer->SetFilePos(SavedPos);
3129 						}
3130 					}
3131 					if (MainData->InputOptions->Control->GetSCFType() == GAMESS_GVB) {
3132 						KeyWordFound = Buffer->LocateKeyWord("GI ORBITALS", 11, NextFinalPos);
3133 						if (KeyWordFound && ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))) {
3134 							Buffer->SkipnLines(4);
3135 							lFrame->ParseGVBGIOrbitals(Buffer, MainData->GetNumBasisFunctions(), NumGVBPairs, ProgressInd);
3136 						}
3137 					} else if (MainData->InputOptions->Control->GetSCFType() == GAMESS_UHF) {
3138 						if (Buffer->LocateKeyWord("UHF NATURAL ORBITALS AND OCCUPATION NUMBERS",
3139 												  43, NextFinalPos)) {
3140 							lFrame->ParseUHFNOs(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3141 						}
3142 					}
3143 					//			if (MainData->InputOptions->Control->GetSCFType() == GAMESS_TDDFT) {
3144 					//I don't have the right control keywords yet. Possibilities are TDDFT=EXCITE in
3145 					//$CONTRL or TDPRP=.t. in $TDDFT
3146 					if (Buffer->LocateKeyWord("TDDFT NATURAL ORBITALS",
3147 											  23, NextFinalPos)) {
3148 						lFrame->ParseTDDFTNOs(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3149 					}
3150 					//			}
3151 					if (MainData->InputOptions->Control->GetMPLevel()) {
3152 						if (Buffer->LocateKeyWord("MP2 NATURAL ORBITAL OCCUPATION NUMBERS",
3153 							38, NextFinalPos) && ReadMP2Orbitals) {
3154 							lFrame->ReadMP2Vectors(Buffer, DatBuffer, MainData->GetNumBasisFunctions(),
3155 								ProgressInd, &ReadMP2Orbitals);
3156 						}
3157 					}
3158 					if (MainData->InputOptions->Control->GetCCType()) {
3159 						if (Buffer->LocateKeyWord("EOM-CC NATURAL ORBITALS",
3160 												  23, NextFinalPos)) {
3161 							lFrame->ParseGAMESSEOM_CC_Vectors(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3162 						}
3163 					}
3164 					if (MainData->InputOptions->Control->GetCIType()) {	//Look for CI Natural orbitals
3165 						//loop to add multiple CI NOs, one set for each eigenstate.
3166 						//This would be the place to read in each eigenstate's energy
3167 						if (MainData->InputOptions->Control->GetCIType() == CI_CIS) {
3168 								//The spaces are important since the phrase appears elsewhere....
3169 							if (Buffer->LocateKeyWord("      CIS NATURAL ORBITALS",
3170 													  26, NextFinalPos)) {
3171 								lFrame->ParseGAMESSCIVectors(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3172 							}
3173 						} else {
3174 							while (Buffer->LocateKeyWord("NATURAL ORBITALS IN ATOMIC ORBITAL BASIS",
3175 													  40, NextFinalPos)) {
3176 								lFrame->ParseGAMESSCIVectors(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3177 							}
3178 						}
3179 					}
3180 				}
3181 				catch (std::bad_alloc) {
3182 					MessageAlert("Insufficient memory to read in eigenvectors.");
3183 				}
3184 				catch (MemoryError) {
3185 					MessageAlert("Insufficient memory to read in eigenvectors.");
3186 				}
3187 				catch (DataError) {
3188 					MessageAlert("Error reading eigenvectors, orbitals skipped.");
3189 				}
3190 			}
3191 			//MRMP2 - Only energy is supported
3192 			if ((MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF)&&
3193 				(MainData->InputOptions->Control->GetMPLevel())) {	//MP2 run so look for MP2 energy
3194 				if (Buffer->LocateKeyWord("TOTAL MRPT2, E(MP2) 0TH + 1ST + 2ND ORDER ENERGY", 48)) {
3195 					double mpE;
3196 					Buffer->GetLine(LineText);
3197 					sscanf(&(LineText[51]), "%lf", &(mpE));
3198 					//This should be changed to MRMP2Energy, but that isn't recognized elsewhere currently
3199 					lFrame->Energies.push_back(EnergyValue(mpE, PT2Energy));
3200 				}
3201 			}
3202 			if (SIMOMM) {	//See if we have MM energies and new coords
3203 				//could also grab the MM energy here
3204 				if (Buffer->LocateKeyWord("QM+MM Energy (Hartree):", 23)) {
3205 					Buffer->GetLine(LineText);
3206 					double FrameEnergy;
3207 					sscanf(&(LineText[24]), "%lf", &FrameEnergy);
3208 					lFrame->Energy = FrameEnergy;
3209 				}
3210 				//now update the coordinates with the new MM list
3211 				Frame * preserve = MainData->cFrame;
3212 				lFrame = MainData->AddFrame(MainData->cFrame->NumAtoms,0);
3213 				MainData->ParseTinkerCoordinates(Buffer);
3214 				if (MainData->cFrame->NumAtoms > 0) {
3215 					//update the coordinates in the first frame
3216 					for (int iatom=0; iatom<MainData->cFrame->NumAtoms; ++iatom) {
3217 						if (MainData->cFrame->Atoms[iatom].IsSIMOMMAtom()) {
3218 							preserve->Atoms[iatom].Position.x = MainData->cFrame->Atoms[iatom].Position.x;
3219 							preserve->Atoms[iatom].Position.y = MainData->cFrame->Atoms[iatom].Position.y;
3220 							preserve->Atoms[iatom].Position.z = MainData->cFrame->Atoms[iatom].Position.z;
3221 						}
3222 					}
3223 				}
3224 				// delete off the temporary frame
3225 				MainData->DeleteFrame();
3226 				lFrame = preserve;
3227 			}
3228 				//look for gradient data
3229 			if (Buffer->LocateKeyWord(OptKeywords) >= 0) {
3230 				KeyWordFound = true;
3231 				NextFinalPos = Buffer->GetFilePos();
3232 				Buffer->SetFilePos(EnergyPos);
3233 			}
3234 			lFrame->ReadGradient(Buffer, NextFinalPos);
3235 		} else if (NumFragmentAtoms > 0) {
3236 			if (Buffer->LocateKeyWord("TOT. INTER. ENERGY", 18, NextFinalPos)) {
3237 				Buffer->GetLine(LineText);
3238 				LinePos = FindKeyWord(LineText, "=", 1);
3239 				if (LinePos > -1) {
3240 					sscanf(&(LineText[LinePos+1]), "%lf", &(lFrame->Energy));
3241 				}
3242 			}
3243 		} else if (MainData->InputOptions->Control->GetCIType()) {
3244 			// If this is just a CI grab CI energy and orbitals
3245 			if (Buffer->LocateKeyWord("CI EIGENSTATE", 13)) {
3246 				Buffer->GetLine(LineText);
3247 				sscanf(&(LineText[35]), "%lf", &(lFrame->Energy));
3248 				while (Buffer->LocateKeyWord("NATURAL ORBITALS IN ATOMIC ORBITAL BASIS",
3249 											 40, NextFinalPos)) {
3250 					lFrame->ParseGAMESSCIVectors(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3251 				}
3252 			}
3253 		}
3254 	// Switch to IRC routine if neccessary
3255 		if (MainData->InputOptions->Control->GetRunType() == IRCRun) {
3256 			//If this is an MP2 run need to copy the MP2 energy to the total energy as the IRC
3257 			//parsing routine only finds the single total energy
3258 			if (MainData->InputOptions->Control->GetMPLevel()) {
3259 				lFrame->SetEnergy(lFrame->GetEnergy(PT2Energy));
3260 			}
3261 			return this->OpenGAMESSIRCLog(Buffer, flip, offset, NumOccAlpha, NumOccBeta, NumFragmentAtoms);
3262 		}
3263 	}
3264 	KeyWordFound = true;
3265 //	if (SIMOMM) KeyWordFound = false;	//only grab a single geometry for SIMOMM
3266 	double	FrameEnergy, MP2FrameEnergy;
3267 //	bool NewStyleGeometryKeyWord=true;
3268 //	char GeoSearchToken[] = "BEGINNING GEOMETRY SEARCH POINT";
3269 //	if (!(Buffer->LocateKeyWord(GeoSearchToken, 31))) {
3270 //		NewStyleGeometryKeyWord = false;
3271 //		strcpy(GeoSearchToken, "1NSERCH");
3272 //	}
3273 	while (KeyWordFound) {
3274 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3275 			{ throw UserCancel();}
3276 		KeyWordFound = false;
3277 			//Advance to the start of the next geometry step BEGINNING GEOMETRY SEARCH POINT
3278 			//If there isn't one then we are done with the geometries
3279 		if (Buffer->LocateKeyWord(OptKeywords) < 0) break;
3280 		StartPos = Buffer->GetFilePos();
3281 		if (Buffer->LocateFinalEnergy()) {	//Search for final and energy on the same line
3282 			Buffer->GetLine(LineText);				//since final also appears in LMO calcs.
3283 			LinePos = FindKeyWord(LineText, "ENERGY", 6);
3284 			if (LinePos > -1) {
3285 				EnergyPos = Buffer->GetFilePos();
3286 				KeyWordFound = true;
3287 				int k = sscanf(&(LineText[LinePos+10]), "%lf", &FrameEnergy);
3288 				if (k == 0) {	//Crappy fragment output is different
3289 					k = FindKeyWord(&(LineText[LinePos]), "=", 1);
3290 					if (LinePos > -1)
3291 						sscanf(&(LineText[LinePos+k+1]), "%lf", &FrameEnergy);
3292 				}
3293 				if (MainData->InputOptions->Control->GetMPLevel()==2) {	//MP2 run so look for MP2 energy
3294 					wxFileOffset temp = Buffer->GetFilePos();
3295 					if (Buffer->LocateKeyWord("E(MP2)=", 7)) {
3296 						Buffer->GetLine(LineText);
3297 						sscanf(&(LineText[8]), "%lf", &MP2FrameEnergy);
3298 					}
3299 					Buffer->SetFilePos(temp);
3300 				} else MP2FrameEnergy = 0.0;
3301 			} else Buffer->SetFilePos(StartPos);
3302 		}
3303 		if (!KeyWordFound && (NumFragmentAtoms > 0)) { //Look for old style fragment output
3304 			if (Buffer->LocateKeyWord("TOT. INTER. ENERGY", 18)) {
3305 				Buffer->GetLine(LineText);
3306 				LinePos = FindKeyWord(LineText, "=", 1);
3307 				if (LinePos > -1) {
3308 					sscanf(&(LineText[LinePos+1]), "%lf", &FrameEnergy);
3309 					KeyWordFound = true;
3310 					EnergyPos = Buffer->GetFilePos();
3311 				}
3312 			}
3313 		}
3314 		if (!KeyWordFound) {	//This is a last resort in case normal GAMESS energies are missing
3315 			if (MainData->InputOptions->Control->GetRunType() == OptimizeRun) {
3316 				if (Buffer->LocateKeyWord("  NSERCH=", 9)) {
3317 					Buffer->GetLine(LineText);
3318 					LinePos = FindKeyWord(LineText, "ENERGY=", 7);
3319 					sscanf(&(LineText[LinePos+7]), "%lf", &FrameEnergy);
3320 					KeyWordFound = true;
3321 					EnergyPos = Buffer->GetFilePos();
3322 				}
3323 			}
3324 		}
3325 
3326 		if (KeyWordFound) {
3327 				//Let the user know we are still making progress
3328 			sprintf(LineText, "Reading Coordinates: frame %ld", MainData->NumFrames);
3329 			ProgressInd->ChangeText(LineText);
3330 			if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3331 				{ throw UserCancel();}
3332 			EnergyPos = Buffer->GetFilePos();
3333 
3334 			Buffer->SkipnLines(1);
3335 			NextFinalPos = -1;
3336 			if (lFrame->NumAtoms - NumFragmentAtoms > 0) {
3337 		//		if (NewStyleGeometryKeyWord&&Buffer->LocateKeyWord("BEGINNING GEOMETRY SEARCH POINT", 31)) {
3338 				if (Buffer->LocateKeyWord(OptKeywords) >= 0) {
3339 		//			KeyWordFound = true;
3340 					NextFinalPos = Buffer->GetFilePos();
3341 					//this doesn't seem to be needed and it messes up the last point in a numerical opt.
3342 	//			} else {
3343 	//				KeyWordFound = Buffer->LocateKeyWord("FINAL", 5);
3344 				}
3345 	//			if (KeyWordFound) NextFinalPos = Buffer->GetFilePos();
3346 				Buffer->SetFilePos(EnergyPos);
3347 			}
3348 		// The output for optimizations was changed in 1/1998 to print all coordinates
3349 		// at the top of an optimization step, but the older style is also still possible
3350 		//Look for ab initio atoms first
3351 			Buffer->SetFilePos(StartPos);	//reset pos to last frame to begin search
3352 			if (Buffer->LocateKeyWord(OptKeywords) >= 0) {
3353 				lpFrame = lFrame;
3354 				lFrame = MainData->AddFrame(lpFrame->NumAtoms,0);
3355 
3356 				if (SIMOMM) {	//copy over the MM atoms so that they will be in the same order
3357 					for (int iatom=0; iatom<lpFrame->NumAtoms; ++iatom) {
3358 						if (lpFrame->Atoms[iatom].IsSIMOMMAtom()) {
3359 							lFrame->AddAtom(lpFrame->Atoms[iatom].Type,
3360 											lpFrame->Atoms[iatom].Position);
3361 							lFrame->Atoms[iatom].IsSIMOMMAtom(true);
3362 						}
3363 					}
3364 				}
3365 
3366 				try {
3367 					if (lpFrame->NumAtoms-NumFragmentAtoms > 0) {
3368 
3369 						//Look for new style with all atoms at top of step first
3370 						if (Buffer->LocateKeyWord("COORDINATES OF ALL ATOMS ARE (ANGS)", 35, EnergyPos)) {
3371 							Buffer->SkipnLines(3);
3372 							test = ParseGLogLine(Buffer, lFrame, lpFrame->NumAtoms-NumFragmentAtoms, 10, &(MainData->MaxSize));
3373 							if (test==-1) {	//Something was wrong with this set of coordinates
3374 								MainData->DeleteFrame();
3375 								break;
3376 							}
3377 						} else if (Buffer->LocateKeyWord(" NSERCH", 7, NextFinalPos)) {
3378 							//Otherwise look for the coordinates at the end of the
3379 							//geometry step (pre 1998 style)
3380 							wxFileOffset npos = Buffer->GetFilePos();
3381 							Buffer->SkipnLines(9);
3382 							test = ParseGLogLine(Buffer, lFrame, lpFrame->NumAtoms-NumFragmentAtoms, 1, &(MainData->MaxSize));
3383 							if (test==-1) {	//Something was wrong with this set of coordinates
3384 								MainData->DeleteFrame();
3385 								break;
3386 							}
3387 							Buffer->SetFilePos(npos);//reset position back to beginning of gradient data
3388 						}
3389 					}
3390 					if (NumFragmentAtoms > 0) {
3391 						wxFileOffset tempPos = Buffer->GetFilePos();
3392 						Buffer->SetFilePos(StartPos);
3393 						if (Buffer->LocateKeyWord(OptKeywords) >= 0) {
3394 							if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 41, NextFinalPos)) {
3395 								Buffer->SkipnLines(3);
3396 								MainData->ReadFragmentCoordinates(Buffer, NumFragmentAtoms);
3397 							}
3398 							Buffer->SetFilePos(tempPos);
3399 						}
3400 					}
3401 					lFrame->ReadGradient(Buffer, NextFinalPos);
3402 				}
3403 				catch (...) {	//Error occured while parsing coordinates, delete this frame
3404 					MainData->DeleteFrame();
3405 					Buffer->SetFilePos(StartPos);
3406 					break;
3407 				}
3408 			} else {
3409 				Buffer->SetFilePos(StartPos);
3410 				break;
3411 			}	//Make sure we actually found the coordinates
3412 			if (lFrame->GetNumAtoms()==0) {Buffer->SetFilePos(StartPos); break;}
3413 			lFrame->Energy = FrameEnergy;
3414 			if (MainData->InputOptions->Control->GetMPLevel()==2)
3415 				lFrame->Energies.push_back(EnergyValue(MP2FrameEnergy, PT2Energy));
3416 			lFrame->IRCPt = lpFrame->IRCPt + flip;
3417 			lFrame->time = lpFrame->time + flip + offset;
3418 
3419 			if (SIMOMM) {
3420 				Buffer->SetFilePos(EnergyPos);
3421 				//could also grab the MM energy here
3422 				if (Buffer->LocateKeyWord("QM+MM Energy (Hartree):", 23)) {
3423 					Buffer->GetLine(LineText);
3424 					double FrameEnergy;
3425 					sscanf(&(LineText[24]), "%lf", &FrameEnergy);
3426 					lFrame->Energy = FrameEnergy;
3427 				}
3428 				//now update the coordinates with the new MM list
3429 				Frame * preserve = MainData->cFrame;
3430 				lFrame = MainData->AddFrame(MainData->cFrame->NumAtoms,0);
3431 				MainData->ParseTinkerCoordinates(Buffer);
3432 				if (MainData->cFrame->NumAtoms > 0) {
3433 					//update the coordinates in the first frame
3434 					for (int iatom=0; iatom<MainData->cFrame->NumAtoms; ++iatom) {
3435 						if (MainData->cFrame->Atoms[iatom].IsSIMOMMAtom()) {
3436 							preserve->Atoms[iatom].Position.x = MainData->cFrame->Atoms[iatom].Position.x;
3437 							preserve->Atoms[iatom].Position.y = MainData->cFrame->Atoms[iatom].Position.y;
3438 							preserve->Atoms[iatom].Position.z = MainData->cFrame->Atoms[iatom].Position.z;
3439 						}
3440 					}
3441 				}
3442 				// delete off the temporary frame
3443 				MainData->DeleteFrame();
3444 				lFrame = preserve;
3445 			}
3446 
3447 			if (Prefs->GetAutoBond())
3448 				lFrame->SetBonds(Prefs, false, ProgressInd);
3449 //			NextFinalPos = -1;
3450 			Buffer->SetFilePos(EnergyPos);
3451 //			long SavedPos = Buffer->GetFilePos();
3452 //			if (lFrame->NumAtoms - NumFragmentAtoms > 0) {
3453 //				KeyWordFound = Buffer->LocateKeyWord("FINAL", 5);
3454 //				if (KeyWordFound) NextFinalPos = Buffer->GetFilePos();
3455 //				Buffer->SetFilePos(SavedPos);
3456 //			}
3457 				//Attempt to read in orbitals for this geometry
3458 			if (MainData->Basis) {
3459 				Buffer->SetFilePos(EnergyPos);
3460 				try {
3461 					if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {
3462 							bool ReadOrbs = false;
3463 						if (Buffer->LocateKeyWord("MCSCF NATURAL ORBITALS", 22, NextFinalPos)) {
3464 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3465 								ReadOrbs = true;
3466 							else Buffer->SetFilePos(SavedPos);
3467 						} else if (Buffer->LocateKeyWord("MCSCF OPTIMIZED ORBITALS", 24, NextFinalPos)) {
3468 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3469 								ReadOrbs = true;
3470 							else Buffer->SetFilePos(SavedPos);
3471 						} else if (Buffer->LocateKeyWord("-MCHF- NATURAL ORBITALS", 23, NextFinalPos)) {
3472 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3473 								ReadOrbs = true;
3474 							else Buffer->SetFilePos(SavedPos);
3475 						} else if (Buffer->LocateKeyWord("-MCHF- OPTIMIZED ORBITALS", 25, NextFinalPos)) {
3476 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos()))
3477 								ReadOrbs = true;
3478 							else Buffer->SetFilePos(SavedPos);
3479 						} else if (Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos)) {
3480 							Buffer->SetFilePos(Buffer->FindBlankLine());
3481 							Buffer->SkipnLines(1);
3482 							lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
3483 								MainData->GetNumBasisFunctions(), 0, NumOccAlpha, NumOccBeta,
3484 								(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
3485 	//						lFrame->ExchangeEigenVectors();
3486 						}
3487 						if (ReadOrbs)
3488 							lFrame->ParseGAMESSMCSCFVectors(Buffer, MainData->GetNumBasisFunctions(),
3489 								OccupiedOrbCount, ProgressInd);
3490 					} else {
3491 						if (MainData->InputOptions->Control->GetSCFType() == GAMESS_GVB) {
3492 							if (Buffer->LocateKeyWord("PAIR INFORMATION", 16, NextFinalPos)) {
3493 								ReadGVBOccupancy(Buffer, NumGVBPairs, MainData->GetNumBasisFunctions(),
3494 									Occupancy);
3495 							}
3496 						}
3497 						bool test = false;
3498 						if (MainData->InputOptions->Control->GetCIType() == 4) {
3499 							//CIS output includes the EIGENVECTORS token
3500 							//I think the regular EIGENVECTORS would be before the CIS line???
3501 							wxFileOffset bp = Buffer->GetFilePos();
3502 							test = Buffer->LocateKeyWord("EIGENVECTORS", 12, NextFinalPos);
3503 							Buffer->BackupnLines(1);
3504 							if (Buffer->LocateKeyWord("CIS EIGENVALUES", 14, 80+Buffer->GetFilePos())) {
3505 								Buffer->SkipnLines(1);
3506 								test = Buffer->LocateKeyWord("EIGENVECTORS", 12, NextFinalPos);
3507 								if (!test) {
3508 									Buffer->SetFilePos(bp);
3509 									test = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3510 									Buffer->BackupnLines(1);
3511 									if (Buffer->LocateKeyWord("# MOLECULAR ORBITALS =", 22)) {
3512 										Buffer->SkipnLines(1);
3513 										test = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3514 										if (!test) Buffer->SetFilePos(bp);
3515 									}
3516 								}
3517 							}
3518 						} else {
3519 							test = Buffer->LocateKeyWord("EIGENVECTORS", 12, NextFinalPos);
3520 							if (!test) {
3521 								test = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3522 								//for a while GAMESS printed out MOLECULAR ORBITALS with the LZ analysis
3523 								//so add a test to avoid that output
3524 								if (test) {
3525 									Buffer->BackupnLines(0);
3526 									Buffer->GetLine(LineText);
3527 									LinePos = FindKeyWord(LineText, "LZ VALUE ANALYSIS", 16);
3528 									if (LinePos > -1) {
3529 										Buffer->SkipnLines(2);
3530 										test = Buffer->LocateKeyWord("MOLECULAR ORBITALS", 18, NextFinalPos);
3531 									}
3532 								}
3533 							}
3534 						}
3535 						if (test) {
3536 								//skip over the line to the start of the orbital blocks
3537 								//There is always a blank line before the orbs, but there may a '---' divider line after the key line just found
3538 							if ((NextFinalPos<0)||(NextFinalPos>Buffer->GetFilePos())) {
3539 								Buffer->SetFilePos(Buffer->FindBlankLine());
3540 								Buffer->SkipnLines(1);
3541 								ProgressInd->ChangeText("Reading eigenvectors");
3542 								if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3543 									{throw UserCancel();}
3544 								OrbitalRec * OrbSet = lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
3545 									MainData->GetNumBasisFunctions(), NumBetaUHFOrbs, NumOccAlpha, NumOccBeta,
3546 									(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
3547 								if ((MainData->InputOptions->Control->GetSCFType() == GAMESS_GVB)&&(OrbSet!=NULL)) {
3548 									//Add the Occupancy vector for GVB wavefunctions
3549 									OrbSet->SetOccupancy(Occupancy, MainData->GetNumBasisFunctions());
3550 								}
3551 							} else Buffer->SetFilePos(SavedPos);
3552 						}
3553 					}
3554 					// It doesn't appear that GVB orbitals are read in after the first set???
3555 					// It appears that GAMESS only prints the GI orbitals on the first iteration
3556 					if (MainData->InputOptions->Control->GetSCFType() == GAMESS_UHF) {
3557 						if (Buffer->LocateKeyWord("UHF NATURAL ORBITALS AND OCCUPATION NUMBERS",
3558 												  43, NextFinalPos)) {
3559 							lFrame->ParseUHFNOs(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3560 						}
3561 					}
3562 		//			if (MainData->InputOptions->Control->GetSCFType() == GAMESS_TDDFT) {
3563 					//I don't have the right control keywords yet. Possibilities are TDDFT=EXCITE in
3564 					//$CONTRL or TDPRP=.t. in $TDDFT
3565 						if (Buffer->LocateKeyWord("TDDFT NATURAL ORBITALS",
3566 												  23, NextFinalPos)) {
3567 							lFrame->ParseTDDFTNOs(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3568 						}
3569 		//			}
3570 					if (MainData->InputOptions->Control->GetMPLevel()) {
3571 						if (Buffer->LocateKeyWord("MP2 NATURAL ORBITAL OCCUPATION NUMBERS",
3572 							38, NextFinalPos) && ReadMP2Orbitals) {
3573 							lFrame->ReadMP2Vectors(Buffer, DatBuffer, MainData->GetNumBasisFunctions(),
3574 								ProgressInd, &ReadMP2Orbitals);
3575 						}
3576 					}
3577 					if (MainData->InputOptions->Control->GetCIType()) {	//Look for CI Natural orbitals
3578 						//loop to add multiple CI NOs, one set for each eigenstate.
3579 						//This would be the place to read in each eigenstate's energy
3580 						while (Buffer->LocateKeyWord("NATURAL ORBITALS IN ATOMIC ORBITAL BASIS",
3581 													 40, NextFinalPos)) {
3582 							lFrame->ParseGAMESSCIVectors(Buffer, MainData->GetNumBasisFunctions(), ProgressInd);
3583 						}
3584 					}
3585 				}
3586 				catch (std::bad_alloc) {
3587 					MessageAlert("Insufficient memory to read in eigenvectors.");
3588 				}
3589 				catch (MemoryError) {
3590 					MessageAlert("Insufficient memory to read in eigenvectors.");
3591 				}
3592 				catch (DataError) {
3593 					MessageAlert("Error reading eigenvectors, orbitals skipped.");
3594 				}
3595 			}
3596 		}
3597 	}
3598 		//Read in normal modes, if present
3599 	MainData->cFrame->ParseNormalModes(Buffer, ProgressInd, Prefs);
3600 
3601 //Look for localized orbitals which appear only at the end of a log file
3602 	if (MainData->Basis) {
3603 		try {
3604 			enum {
3605 				CASSCFDiabatic=0,
3606 				FockLocalized,
3607 				DensityMatrixLocalized,
3608 				OrientedLocOrbs,
3609 				NonorthogLocOrbs,
3610 				PPASVDOrbs,
3611 				LocalizedOrbitals,
3612 				SVDExternalOrbs,
3613 				SplitQALocOrbs,
3614 				OrderedExternalLocOrbs
3615 			};
3616 			std::vector<std::pair <std::string, int> > LocOrbKeywords;
3617 			if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF)
3618 				LocOrbKeywords.push_back(make_pair (std::string("CAS-SCF DIABATIC MOLECULAR ORBITALS"), (int) CASSCFDiabatic));
3619 			LocOrbKeywords.push_back(make_pair (std::string("FOCK OPERATOR FOR THE LOCALIZED ORBITALS"), (int) FockLocalized));
3620 			if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF)
3621 				LocOrbKeywords.push_back(make_pair (std::string("DENSITY MATRIX FOR THE LOCALIZED ORBITALS"), (int) DensityMatrixLocalized));
3622 			LocOrbKeywords.push_back(make_pair (std::string("ORIENTED LOCALIZED ORBITALS"), (int) OrientedLocOrbs));
3623 			LocOrbKeywords.push_back(make_pair (std::string("NONORTHOGONAL PPA SVD LOCALIZED ORBITALS"), (int) NonorthogLocOrbs));
3624 			LocOrbKeywords.push_back(make_pair (std::string("PPA SVD LOCALIZED ORBITALS"), (int) PPASVDOrbs));
3625 //			LocOrbKeywords.push_back(make_pair (std::string("SVD EXTERNAL LOCALIZED ORBITALS"), (int) SVDExternalOrbs));
3626 			LocOrbKeywords.push_back(make_pair (std::string("SPLITQA LOCALIZED ORBITALS"), (int) SplitQALocOrbs));
3627 			LocOrbKeywords.push_back(make_pair (std::string("ORDERED EXTERNAL LOCALIZED ORBITALS"), (int) OrderedExternalLocOrbs));
3628 //Order is important, look for this last since it is a subset of some of the others
3629 			LocOrbKeywords.push_back(make_pair (std::string("LOCALIZED ORBITALS"), (int) LocalizedOrbitals));
3630 
3631 			while (! Buffer->Eof()) {
3632 				int kw;
3633 				if (-1 < (kw = Buffer->LocateKeyWord(LocOrbKeywords))) {
3634 					wxFileOffset keywordPosition = Buffer->GetFilePos();
3635 					OrbitalRec * OrbSet;
3636 					switch (kw) {
3637 						case CASSCFDiabatic:
3638 							//MCSCF runs can potentially have diabatic orbitals at the end.
3639 							if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {
3640 								lFrame->ParseGAMESSMCSCFDiabaticVectors(Buffer, MainData->GetNumBasisFunctions(),
3641 																		OccupiedOrbCount, ProgressInd);
3642 							}
3643 							break;
3644 						case FockLocalized:
3645 							Buffer->SkipnLines(1);
3646 							break;
3647 						case OrientedLocOrbs:
3648 							Buffer->SkipnLines(2);
3649 							ProgressInd->ChangeText("Reading oriented localized orbitals");
3650 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3651 							{ throw UserCancel();}
3652 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3653 															 NumBetaUHFOrbs, ProgressInd, true);
3654 							if (OrbSet != NULL) {
3655 								OrbSet->setOrbitalWavefunctionType((TypeOfWavefunction)MainData->InputOptions->Control->GetSCFType());
3656 								if (MainData->InputOptions->Control->GetSCFType() != GAMESS_MCSCF) {
3657 									OrbSet->SetOrbitalOccupancy(NumOccAlpha, NumOccBeta);
3658 								}
3659 							}
3660 							break;
3661 						case NonorthogLocOrbs:
3662 							Buffer->SetFilePos(Buffer->FindBlankLine());
3663 							Buffer->SkipnLines(1);
3664 							ProgressInd->ChangeText("Reading Nonorthogonal PPA SVD localized orbitals");
3665 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3666 							{ throw UserCancel();}
3667 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3668 															 NumBetaUHFOrbs, ProgressInd, true);
3669 							OrbSet->setOrbitalType(NonOrthogonalSVDLocalizedOrbital);
3670 							break;
3671 						case PPASVDOrbs:
3672 							Buffer->SetFilePos(Buffer->FindBlankLine());
3673 							Buffer->SkipnLines(1);
3674 							ProgressInd->ChangeText("Reading PPA SVD localized orbitals");
3675 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3676 							{ throw UserCancel();}
3677 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3678 															 NumBetaUHFOrbs, ProgressInd, true);
3679 							OrbSet->setOrbitalType(PPASVDLocalizedOrbital);
3680 							break;
3681 						case LocalizedOrbitals:
3682 							Buffer->SkipnLines(2);
3683 							ProgressInd->ChangeText("Reading localized orbitals");
3684 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3685 							{ throw UserCancel();}
3686 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3687 																		  NumBetaUHFOrbs, ProgressInd, false);
3688 							if (OrbSet != NULL) {
3689 								OrbSet->setOrbitalWavefunctionType((TypeOfWavefunction)MainData->InputOptions->Control->GetSCFType());
3690 								if (MainData->InputOptions->Control->GetSCFType() != GAMESS_MCSCF) {
3691 									OrbSet->SetOrbitalOccupancy(NumOccAlpha, NumOccBeta);
3692 								}
3693 							}
3694 							break;
3695 						case SVDExternalOrbs:
3696 							Buffer->SetFilePos(Buffer->FindBlankLine());
3697 							Buffer->SkipnLines(1);
3698 							ProgressInd->ChangeText("Reading SVD External localized orbitals");
3699 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3700 							{ throw UserCancel();}
3701 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3702 															 NumBetaUHFOrbs, ProgressInd, true);
3703 							OrbSet->setOrbitalType(SVDExternalLocalizedOrbital);
3704 							break;
3705 						case SplitQALocOrbs:
3706 							Buffer->SetFilePos(Buffer->FindBlankLine());
3707 							Buffer->SkipnLines(1);
3708 							ProgressInd->ChangeText("Reading SplitQA localized orbitals");
3709 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3710 							{ throw UserCancel();}
3711 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3712 															 NumBetaUHFOrbs, ProgressInd, true);
3713 							OrbSet->setOrbitalType(SplitQAExternalLocalizedOrbital);
3714 							break;
3715 						case OrderedExternalLocOrbs:
3716 							Buffer->SetFilePos(Buffer->FindBlankLine());
3717 							Buffer->SkipnLines(1);
3718 							ProgressInd->ChangeText("Reading Ordered External localized orbitals");
3719 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3720 							{ throw UserCancel();}
3721 							OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3722 															 NumBetaUHFOrbs, ProgressInd, true);
3723 							OrbSet->setOrbitalType(OrderedExternalLocalizedOrbital);
3724 							break;
3725 					}
3726 					//If still positioned at the keyword, must advance or there will be a loop.
3727 					if (keywordPosition == Buffer->GetFilePos()) Buffer->SkipnLines(1);
3728 				} else break;
3729 			}
3730 				//MCSCF runs can potentially have diabatic orbitals at the end.
3731 //			if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {
3732 //				if (Buffer->LocateKeyWord("CAS-SCF DIABATIC MOLECULAR ORBITALS", 34)) {
3733 //					lFrame->ParseGAMESSMCSCFDiabaticVectors(Buffer, MainData->GetNumBasisFunctions(),
3734 //												OccupiedOrbCount, ProgressInd);
3735 //				}
3736 //			}
3737 				//GAMESS now punchs out the Fock operator for ruedenburg type localization
3738 				//which I need to skip if it is present
3739 //			if (Buffer->LocateKeyWord("FOCK OPERATOR FOR THE LOCALIZED ORBITALS",40))
3740 //				Buffer->SkipnLines(1);
3741 //			if (MainData->InputOptions->Control->GetSCFType()==GAMESS_MCSCF) {
3742 					//skip over the density matrix (present in Ruedenburg MCSCF runs)
3743 //				if (Buffer->LocateKeyWord("DENSITY MATRIX FOR THE LOCALIZED ORBITALS",41))
3744 //					Buffer->SkipnLines(1);
3745 //			}
3746 //			KeyWordFound = Buffer->LocateKeyWord("LOCALIZED ORBITALS",18);
3747 //			if (KeyWordFound) {
3748 //				Buffer->SkipnLines(2);
3749 //				ProgressInd->ChangeText("Reading localized orbitals");
3750 //				if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3751 //					{ throw UserCancel();}
3752 //				OrbitalRec * OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3753 //					NumBetaUHFOrbs, ProgressInd, false);
3754 //				if (OrbSet != NULL) {
3755 //					OrbSet->setOrbitalWavefunctionType((TypeOfWavefunction)MainData->InputOptions->Control->GetSCFType());
3756 //					if (MainData->InputOptions->Control->GetSCFType() != GAMESS_MCSCF) {
3757 //						OrbSet->SetOrbitalOccupancy(NumOccAlpha, NumOccBeta);
3758 //					}
3759 //				}
3760 //				// There may also be oriented localized orbitals
3761 //				KeyWordFound = Buffer->LocateKeyWord("ORIENTED LOCALIZED ORBITALS",27);
3762 //				if (KeyWordFound) {
3763 //					Buffer->SkipnLines(2);
3764 //					ProgressInd->ChangeText("Reading oriented localized orbitals");
3765 //					if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
3766 //						{ throw UserCancel();}
3767 //					OrbSet = lFrame->ParseGAMESSLMOs(Buffer, MainData->GetNumBasisFunctions(), MainData->GetNumBasisFunctions(),
3768 //						NumBetaUHFOrbs, ProgressInd, true);
3769 //					if (OrbSet != NULL) {
3770 //						OrbSet->setOrbitalWavefunctionType((TypeOfWavefunction)MainData->InputOptions->Control->GetSCFType());
3771 //						if (MainData->InputOptions->Control->GetSCFType() != GAMESS_MCSCF) {
3772 //							OrbSet->SetOrbitalOccupancy(NumOccAlpha, NumOccBeta);
3773 //						}
3774 //					}
3775 //				}
3776 //			}
3777 		}
3778 		catch (std::bad_alloc) {
3779 			MessageAlert("Insufficient memory to read in the localized orbitals.");
3780 		}
3781 		catch (MemoryError) {
3782 			MessageAlert("Insufficient memory to read in the localized orbitals.");
3783 		}
3784 		catch (DataError) {
3785 			MessageAlert("Error reading localized orbitals, local orbs. skipped.");
3786 		}
3787 	}
3788 	if (DatBuffer) DatBuffer->CloseFile();
3789 	if (Occupancy) delete [] Occupancy;
3790 	MainData->cFrame = MainData->Frames;
3791 	MainData->CurrentFrame = 1;
3792 	if (MainData->InputOptions->Control->GetMPLevel()==2) {
3793 		EnergyOptions * lOpts = Prefs->GetEnergyOptions();
3794 		lOpts->SetPlotMPEnergy(true);
3795 		lOpts->SetPlotEnergy(false);
3796 	}
3797 	if ((MainData->InputOptions->Control->GetRunType()==4)||
3798 		(MainData->InputOptions->Control->GetRunType()==6)) {
3799 		MainData->SetCurrentFrame(MainData->GetNumFrames());
3800 	}
3801 	return 1;
3802 }	/*OpenGAMESSlog*/
ReadGVBOccupancy(BufferFile * Buffer,long NumPairs,long MaxOrbs,float * Occupancy)3803 bool ReadGVBOccupancy(BufferFile * Buffer, long NumPairs, long MaxOrbs, float * Occupancy) {
3804 		char Line[kMaxLineLength];
3805 		long	junk, Orb1, Orb2;
3806 		float	junkf, Occ1, Occ2;
3807 	if ((NumPairs <= 0)||(!Occupancy)) return false;	//no GVB pairs or no memory
3808 	Buffer->SkipnLines(4);
3809 	for (long i=0; i<NumPairs; ++i) {
3810 		Buffer->GetLine(Line);
3811 		sscanf(Line, "%ld %ld %ld %f %f %f %f", &junk, &Orb1, &Orb2, &junkf, &junkf,
3812 			&Occ1, &Occ2);
3813 		if ((Orb1<1)||(Orb1>MaxOrbs)||(Orb2<1)||(Orb2>MaxOrbs)) return false;//invalid orbital number
3814 		Occupancy[Orb1 - 1] = Occ1;
3815 		Occupancy[Orb2 - 1] = Occ2;
3816 	}
3817 	return true;
3818 }
3819 //routine to parse initial fragment coordinates which are in a real ugly
3820 //format with all of the multipole expantion points
ReadInitialFragmentCoords(BufferFile * Buffer)3821 long MoleculeData::ReadInitialFragmentCoords(BufferFile * Buffer) {
3822 	long NumFragmentAtoms = 0, iatom, NumMultipoles=0, FragmentNumber=0;
3823 	char Label[kMaxLineLength], Line[kMaxLineLength];
3824 	Frame * lFrame = GetCurrentFramePtr();
3825 	iatom = lFrame->GetNumAtoms();
3826 
3827 	//First read in the fragment names which are separate from the coordinates
3828 	//I am not sure why I originally pulled it as "FOR", but GAMESS hasn't used it for some time.
3829 	//	"COORDINATES FOR FRAGMENT"
3830 	while (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT", 23, Buffer->GetFilePos()+200)) {
3831 		if (Buffer->LocateKeyWord("NAMED", 5, Buffer->GetFilePos()+80)) {
3832 			Buffer->GetLine(Line);
3833 			sscanf(&(Line[5]), "%s", Label);
3834 			FragmentNames.push_back(std::string(Label));
3835 		} else Buffer->SkipnLines(1);
3836 	}
3837 	while (Buffer->LocateKeyWord("READING POTENTIAL PARAMETERS FOR FRAGMENT", 40, Buffer->GetFilePos()+200)) {
3838 		Buffer->SkipnLines(1);
3839 	}
3840 
3841 	if (Buffer->LocateKeyWord("TOTAL NUMBER OF MULTIPOLE POINTS", 32, Buffer->GetFilePos()+10000)) {
3842 		Buffer->GetLine(Line);
3843 		sscanf(&(Line[32]), " =%ld", &NumMultipoles);
3844 	}
3845 		//Mike finally fixed the spelling of coordinates
3846 	if ((NumMultipoles>0) && (Buffer->LocateKeyWord("MULTIPOLE COORDINATES", 20, Buffer->GetFilePos()+10000) ||
3847 			Buffer->LocateKeyWord("MULTIPOLE CORDINATES", 19, Buffer->GetFilePos()+10000))) {
3848 		Buffer->SkipnLines(3);
3849 		SetupFrameMemory(lFrame->NumAtoms + 10, 0);
3850 		bool workingFragment=false;
3851 		for (int i=0; i<NumMultipoles; ++i) {
3852 				CPoint3D	Pos;
3853 				float		eCharge, nCharge;
3854 			Buffer->GetLine(Line);
3855 			int iscan = sscanf(Line, "%s%f%f%f%f%f", Label, &Pos.x, &Pos.y, &Pos.z,
3856 				&eCharge, &nCharge);
3857 			if (iscan == 6) {
3858 
3859 					//The fragment output at the top of the log file is very bad for reading
3860 					//and parsing. First we test on charge (some types have atom positions with
3861 					//zero nuclear but positive electronic charge). Then strip off the 'Z' which
3862 					//may or may not be present, then try to avoid non-atom positions which most of
3863 					//the time have negative charge and often seem to start with 'B'.
3864 				if (eCharge>0.5 || nCharge > 0.5) {
3865 					long AtomType = -1;
3866 					if (std::toupper(Label[0]) == 'B') {
3867 						//a 'B' almost always not an atom
3868 						if (workingFragment) workingFragment=false;	//flag to indicate end of fragment
3869 						if ((std::isalpha(Label[1]))) {
3870 							if (eCharge<3.5 || nCharge < 3.5) continue;
3871 						}
3872 					}
3873 					if ((Label[0] == 'Z') || (Label[0] == 'z')) {	//z represents an atom pos
3874 						Label[0] = Label[1];
3875 						if (std::isalpha(Label[2])) {
3876 							Label[1] = Label[2];
3877 							Label[2] = 0;
3878 						} else Label[1] = 0;
3879 					}
3880 					AtomType = SetAtomType((unsigned char *) &(Label[0]));
3881 					if ((std::toupper(Label[0]) == 'A')&&(AtomType < 0)) {
3882 						AtomType = nCharge;
3883 					}
3884 					if (lFrame->NumAtoms + 1 > lFrame->AtomAllocation)
3885 						SetupFrameMemory(lFrame->NumAtoms + 10, 0);
3886 					if (AtomType > 0) {
3887 						if (!workingFragment) {
3888 							++FragmentNumber;
3889 							workingFragment = true;
3890 						}
3891 						Pos.x *= kBohr2AngConversion;
3892 						Pos.y *= kBohr2AngConversion;
3893 						Pos.z *= kBohr2AngConversion;
3894 						mpAtom * newAtom = lFrame->AddAtom(AtomType, Pos);
3895 						if (newAtom) newAtom->SetFragmentNumber(FragmentNumber);
3896 						MaxSize = MAX(MaxSize, fabs(Pos.x));
3897 						MaxSize = MAX(MaxSize, fabs(Pos.y));
3898 						MaxSize = MAX(MaxSize, fabs(Pos.z));
3899 						++NumFragmentAtoms;
3900 					}
3901 				} else workingFragment = false;
3902 			}
3903 		}
3904 	}
3905 	return NumFragmentAtoms;
3906 }
ReadFragmentCoordinates(BufferFile * Buffer,long NumFragmentAtoms)3907 void MoleculeData::ReadFragmentCoordinates(BufferFile * Buffer, long NumFragmentAtoms) {
3908 	long		iatom=0, FragmentNumber=0;
3909 	CPoint3D	Pos;
3910 	char		Label[kMaxLineLength], Line[kMaxLineLength];
3911 	Frame *		lFrame = GetCurrentFramePtr();
3912 	Frame *		startFrame = Frames;
3913 	long		referenceFragAtom=0;
3914 
3915 	while (iatom<NumFragmentAtoms) {
3916 		Buffer->GetLine(Line);
3917 		if (-1<LocateKeyWord(Line, "FRAGNAME=",9, strlen(Line))) {++FragmentNumber; continue;}
3918 		int iscan = sscanf(Line, "%s%f%f%f", Label, &Pos.x, &Pos.y, &Pos.z);
3919 		if (iscan == 4) {
3920 			long AtomType = -1;
3921 			if ((Label[0] == 'Z') || (Label[0] == 'z')) {	//z represents an atom pos
3922 				Label[0] = Label[1];
3923 				if (std::isalpha(Label[2])) {
3924 					Label[1] = Label[2];
3925 					Label[2] = 0;
3926 				} else Label[1] = 0;
3927 			}
3928 			AtomType = SetAtomType((unsigned char *) &(Label[0]));
3929 			//In the late-2007 style we get only the useless label (starting with an 'A')
3930 			//and the x, y, and z coords. So in order to determine the atomtype we have
3931 			//to reference the initial frame.
3932 			if ((std::toupper(Label[0]) == 'A')&&(AtomType < 0)) {
3933 				while ((referenceFragAtom < startFrame->GetNumAtoms())&&
3934 					   !startFrame->Atoms[referenceFragAtom].IsEffectiveFragment())
3935 					++referenceFragAtom;
3936 				if (referenceFragAtom < startFrame->GetNumAtoms()) {
3937 					AtomType = startFrame->Atoms[referenceFragAtom].Type;
3938 					++referenceFragAtom;
3939 				}
3940 			}
3941 			if (AtomType > 0) {
3942 				mpAtom * newAtom = lFrame->AddAtom(AtomType, Pos);
3943 				if (newAtom) newAtom->SetFragmentNumber(FragmentNumber);
3944 				MaxSize = MAX(MaxSize, fabs(Pos.x));
3945 				MaxSize = MAX(MaxSize, fabs(Pos.y));
3946 				MaxSize = MAX(MaxSize, fabs(Pos.z));
3947 				++iatom;
3948 			}
3949 		}
3950 	}
3951 }
ReadBasisOptions(BufferFile * Buffer)3952 void MoleculeData::ReadBasisOptions(BufferFile * Buffer) {
3953 		char LineText[kMaxLineLength], token[kMaxLineLength];
3954 		long LinePos, test;
3955 	if (Buffer->LocateKeyWord("GBASIS", 6)) {
3956 		Buffer->GetLine(LineText);
3957 		LinePos = FindKeyWord(LineText, "GBASIS", 6) + 7;
3958 		sscanf(&(LineText[LinePos]),"%s", token);
3959 		InputOptions->Basis->SetBasis(token);
3960 
3961 		LinePos = FindKeyWord(LineText, "IGAUSS", 6);
3962 		if (LinePos > -1) {
3963 			sscanf(&(LineText[LinePos+7]),"%ld", &test);
3964 			InputOptions->Basis->SetNumGauss(test);
3965 		}
3966 
3967 		LinePos = FindKeyWord(LineText, "POLAR", 5);
3968 		if (LinePos > -1) {
3969 			sscanf(&(LineText[LinePos+6]),"%s", token);
3970 			InputOptions->Basis->SetPolar(&(LineText[LinePos+6]));
3971 		}
3972 
3973 		Buffer->GetLine(LineText);
3974 		LinePos = FindKeyWord(LineText, "NDFUNC", 6);
3975 		if (LinePos > -1) {
3976 			sscanf(&(LineText[LinePos+7]),"%ld", &test);
3977 			InputOptions->Basis->SetNumDFuncs(test);
3978 		}
3979 
3980 		LinePos = FindKeyWord(LineText, "DIFFSP", 6);
3981 		if (LinePos > -1) {
3982 			sscanf(&(LineText[LinePos+7]),"%1s", token);
3983 			InputOptions->Basis->SetDiffuseSP(token[0] == 'T');
3984 		}
3985 
3986 		Buffer->GetLine(LineText);
3987 		LinePos = FindKeyWord(LineText, "NPFUNC", 6);
3988 		if (LinePos > -1) {
3989 			sscanf(&(LineText[LinePos+7]),"%ld", &test);
3990 			InputOptions->Basis->SetNumPFuncs(test);
3991 		}
3992 
3993 		LinePos = FindKeyWord(LineText, "DIFFS", 5);
3994 		if (LinePos > -1) {
3995 			sscanf(&(LineText[LinePos+6]),"%1s", token);
3996 			InputOptions->Basis->SetDiffuseS(token[0] == 'T');
3997 		}
3998 	}
3999 }
ReadControlOptions(BufferFile * Buffer)4000 void MoleculeData::ReadControlOptions(BufferFile * Buffer) {
4001 		long	test;
4002 		char	LineText[kMaxLineLength], token[kMaxLineLength];
4003 	wxFileOffset StartPos = Buffer->GetFilePos()+5;	//All keywords should be between these positions
4004 	wxFileOffset EndPos = Buffer->FindBlankLine();
4005 	if (!Buffer->LocateKeyWord("SCFTYP", 6, EndPos)) throw DataError();
4006 	Buffer->GetLine(LineText);
4007 	sscanf(&(LineText[7]), "%s", token);
4008 	test = InputOptions->Control->SetSCFType(token);
4009 	// a -1 return means the SCFTyp was invalid, we'll continue, but there may be problems
4010 	Buffer->SetFilePos(StartPos);
4011 
4012 	if (Buffer->LocateKeyWord("RUNTYP", 6, EndPos)) {
4013 		Buffer->GetLine(LineText);
4014 		sscanf(&(LineText[7]), "%s", token);
4015 		InputOptions->Control->SetRunType(token);
4016 		Buffer->SetFilePos(StartPos);
4017 	}
4018 
4019 	if (Buffer->LocateKeyWord("EXETYP", 6, EndPos)) {
4020 		Buffer->GetLine(LineText);
4021 		sscanf(&(LineText[7]), "%s", token);
4022 		InputOptions->Control->SetExeType(token);
4023 		Buffer->SetFilePos(StartPos);
4024 	}
4025 
4026 	if (Buffer->LocateKeyWord("MPLEVL", 6, EndPos)) {
4027 		Buffer->GetLine(LineText);
4028 		sscanf(&(LineText[7]),"%ld", &test);
4029 		InputOptions->Control->SetMPLevel(test);
4030 		Buffer->SetFilePos(StartPos);
4031 	}
4032 
4033 	if (Buffer->LocateKeyWord("CITYP", 5, EndPos)) {
4034 		Buffer->GetLine(LineText);
4035 		sscanf(&(LineText[7]),"%s", token);
4036 		InputOptions->Control->SetCIType(token);
4037 		Buffer->SetFilePos(StartPos);
4038 	}
4039 
4040 	if (Buffer->LocateKeyWord("CCTYP", 5, EndPos)) {
4041 		Buffer->GetLine(LineText);
4042 		sscanf(&(LineText[7]),"%s", token);
4043 		InputOptions->Control->SetCCType(token);
4044 		Buffer->SetFilePos(StartPos);
4045 	}
4046 
4047 	if (Buffer->LocateKeyWord("LOCAL", 5, EndPos)) {
4048 		Buffer->GetLine(LineText);
4049 		sscanf(&(LineText[7]), "%s", token);
4050 		InputOptions->Control->SetLocal(token);
4051 		Buffer->SetFilePos(StartPos);
4052 	}
4053 
4054 	if (Buffer->LocateKeyWord("MULT", 4, EndPos)) {
4055 		Buffer->GetLine(LineText);
4056 		sscanf(&(LineText[7]),"%ld", &test);
4057 		InputOptions->Control->SetMultiplicity(test);
4058 		Buffer->SetFilePos(StartPos);
4059 	}
4060 
4061 	if (Buffer->LocateKeyWord("ICHARG", 6, EndPos)) {
4062 		Buffer->GetLine(LineText);
4063 		sscanf(&(LineText[7]),"%ld", &test);
4064 		InputOptions->Control->SetCharge(test);
4065 		Buffer->SetFilePos(StartPos);
4066 	}
4067 
4068 	if (Buffer->LocateKeyWord("MAXIT", 5, EndPos)) {
4069 		Buffer->GetLine(LineText);
4070 		sscanf(&(LineText[7]),"%ld", &test);
4071 		InputOptions->Control->SetMaxIt(test);
4072 		Buffer->SetFilePos(StartPos);
4073 	}
4074 
4075 	bool foo = Buffer->LocateKeyWord("ECP", 3, EndPos);
4076 	if (!foo) foo = Buffer->LocateKeyWord("PP  ", 4, EndPos);
4077 	if (foo) {
4078 		Buffer->GetLine(LineText);
4079 		sscanf(&(LineText[7]),"%s", token);
4080 		InputOptions->Basis->SetECPPotential(token);
4081 		Buffer->SetFilePos(StartPos);
4082 	}
4083 
4084 	if (Buffer->LocateKeyWord("ISPHER", 6, EndPos)) {
4085 		Buffer->GetLine(LineText);
4086 		sscanf(&(LineText[7]),"%ld", &test);
4087 		if (test == 1) InputOptions->Control->UseSphericalHarmonics(true);
4088 		Buffer->SetFilePos(StartPos);
4089 	}
4090 	if (Buffer->LocateKeyWord("NOSYM", 5, EndPos)) {
4091 		Buffer->GetLine(LineText);
4092 		sscanf(&(LineText[7]),"%ld", &test);
4093 		InputOptions->Data->SetUseSym((test==0));
4094 		Buffer->SetFilePos(StartPos);
4095 	}
4096 
4097 	if (Buffer->LocateKeyWord("NORMF", 5, EndPos)) {
4098 		Buffer->GetLine(LineText);
4099 		sscanf(&(LineText[7]),"%ld", &test);
4100 		InputOptions->Control->SetNormF((test!=0));
4101 		Buffer->SetFilePos(StartPos);
4102 	}
4103 
4104 	if (Buffer->LocateKeyWord("NORMP", 5, EndPos)) {
4105 		Buffer->GetLine(LineText);
4106 		sscanf(&(LineText[7]),"%ld", &test);
4107 		InputOptions->Control->SetNormP((test!=0));
4108 		Buffer->SetFilePos(StartPos);
4109 	}
4110 }
ReadSystemOptions(BufferFile * Buffer)4111 void SystemGroup::ReadSystemOptions(BufferFile * Buffer) {
4112 	char	LineText[kMaxLineLength], token[kMaxLineLength];
4113 	wxFileOffset StartPos = Buffer->GetFilePos();	//All keywords should be between these positions
4114 	wxFileOffset EndPos = Buffer->FindBlankLine();
4115 
4116 	if (Buffer->LocateKeyWord("MEMORY=", 7, EndPos)) {
4117 		Buffer->GetLine(LineText);
4118 		double temp=0.0;
4119 		sscanf(&(LineText[7]), "%lf", &temp);
4120 		SetMemory(temp);
4121 		Buffer->SetFilePos(StartPos);
4122 	}
4123 	if (Buffer->LocateKeyWord("MEMDDI=", 7, EndPos)) {
4124 		Buffer->GetLine(LineText);
4125 		double temp=0.0;
4126 		sscanf(&(LineText[7]), "%lf", &temp);
4127 		SetMemDDI(temp);
4128 		Buffer->SetFilePos(StartPos);
4129 	}
4130 	if (Buffer->LocateKeyWord("TIMLIM=", 7, EndPos)) {
4131 		Buffer->GetLine(LineText);
4132 		double temp=0.0;
4133 		sscanf(&(LineText[7]), "%lf%s", &temp, token);
4134 		if (FindKeyWord(token, "SECONDS", 7)>=0)
4135 			temp /= 60.0;	//For some odd reason TIMLIM is printed in seconds...
4136 		SetTimeLimit((long) temp);
4137 		Buffer->SetFilePos(StartPos);
4138 	}
4139 	if (Buffer->LocateKeyWord("PARALL=", 7, EndPos)) {
4140 		Buffer->GetLine(LineText);
4141 		sscanf(&(LineText[7]), "%s", token);
4142 		if (token[0]=='F') SetParallel(false);
4143 		else if (token[0]=='T') SetParallel(true);
4144 		Buffer->SetFilePos(StartPos);
4145 	}
4146 	if (Buffer->LocateKeyWord("BALTYP=", 7, EndPos)) {
4147 		Buffer->GetLine(LineText);
4148 		sscanf(&(LineText[7]), "%s", token);
4149 		if (FindKeyWord(token, "LOOP", 4)>=0)
4150 			SetBalanceType(true);
4151 		Buffer->SetFilePos(StartPos);
4152 	}
4153 	if (Buffer->LocateKeyWord("COREFL=", 7, EndPos)) {
4154 		Buffer->GetLine(LineText);
4155 		sscanf(&(LineText[7]), "%s", token);
4156 		if (token[0]=='F') SetCoreFlag(false);
4157 		else if (token[0]=='T') SetCoreFlag(true);
4158 		Buffer->SetFilePos(StartPos);
4159 	}
4160 	if (Buffer->LocateKeyWord("KDIAG=", 6, EndPos)) {
4161 		Buffer->GetLine(LineText);
4162 		int temp;
4163 		sscanf(&(LineText[6]), "%d", &temp);
4164 		SetDiag(temp);
4165 	}
4166 }
OpenGAMESSTRJ(BufferFile * Buffer,bool Append,long flip,float offset)4167 long MolDisplayWin::OpenGAMESSTRJ(BufferFile * Buffer, bool Append, long flip, float offset)
4168 {
4169 	TypeOfRun		runType=InvalidRunType;
4170 	char			LineText[kMaxLineLength+1];
4171 	bool			FirstFrame = true;
4172 	long IRCnSkip = Prefs->GetDRCSkip();
4173 	long nSkip = 0;
4174 
4175 	ProgressInd->ChangeText("Reading GAMESS trajectory file...");
4176 	Frame * lFrame = MainData->cFrame;
4177 
4178 	long NumAIAtoms=0, NumFragments=0, NumMDAtoms=0;
4179 	//Determine the specific run type
4180 	//the 1024 is arbitrary, but if it's not found in the first 1024 bytes it probably isn't there
4181 	if (Buffer->LocateKeyWord("===== IRC DATA PACKET", 21, 1024)) {
4182 		runType	= IRCRun;
4183 	} else if (Buffer->LocateKeyWord("===== DRC DATA PACKET", 21, 1024)) {
4184 		runType = DRCRun;
4185 	} else if (Buffer->LocateKeyWord("===== MD DATA PACKET", 20, 1024)) {
4186 		runType = MolDynamics;
4187 	} else if (Buffer->LocateKeyWord("ACCEPTED AT GLOBAL SEARCH POINT", 20, 1024)) {
4188 		runType = GLOBOPRun;
4189 		wxFileOffset start = Buffer->GetFilePos();
4190 		wxFileOffset fragStart=0;
4191 		if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 40)) {
4192 			fragStart = Buffer->GetFilePos();
4193 		}
4194 		wxFileOffset nextPoint = Buffer->GetFileLength();
4195 		if (Buffer->LocateKeyWord("ACCEPTED AT GLOBAL SEARCH POINT", 20)) {
4196 			nextPoint = Buffer->GetFilePos();
4197 		}
4198 		if (fragStart > 0) {
4199 			Buffer->SetFilePos(fragStart);
4200 			while (Buffer->LocateKeyWord("FRAGNAME", 8, nextPoint)) {
4201 				NumFragments++;
4202 				Buffer->SkipnLines(1);
4203 			}
4204 		} else fragStart = nextPoint;
4205 		Buffer->SetFilePos(start);
4206 		NumAIAtoms = Buffer->GetNumLines(fragStart - start) - 5;//subtract off the header lines
4207 	}
4208 	if (!Append) { //set the runtype
4209 		if (!MainData->InputOptions) MainData->InputOptions = new InputData;
4210 		if (runType) MainData->InputOptions->Control->SetRunType(runType);
4211 	}
4212 	Buffer->SetFilePos(0);
4213 	std::vector<std::pair <std::string, int> > keywords;
4214 	keywords.push_back(make_pair (std::string("DATA PACKET"), 1));
4215 	keywords.push_back(make_pair (std::string("ACCEPTED AT GLOBAL SEARCH POINT"), 2));
4216 
4217 	std::vector<std::pair <std::string, int> > AIkeywords;
4218 	AIkeywords.push_back(make_pair (std::string("----- QM PARTICLE COORDINATES"), 1));
4219 	AIkeywords.push_back(make_pair (std::string("COORDINATES OF ALL ATOMS ARE"), 2));
4220 
4221 	std::vector<std::pair <std::string, int> > FragmentAtomsKeywords;
4222 	FragmentAtomsKeywords.push_back(make_pair (std::string("----- EFP PARTICLE COORDINATES"), 1));
4223 	FragmentAtomsKeywords.push_back(make_pair (std::string("COORDINATES OF FRAGMENT MULTIPOLE CENTERS"), 2));
4224 
4225 	//search for the beginning of the information packet
4226 
4227 	while (Buffer->LocateKeyWord(keywords) > -1) {
4228 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4229 		{ throw UserCancel();}
4230 		//if this is an irc we could pull the point out of the header line
4231 		if (runType == IRCRun) {
4232 			Buffer->GetLine(LineText);
4233 			long point=0;
4234 			long pos = FindKeyWord(LineText, "FOR STEP", 8);
4235 			if (pos >= 0) {
4236 				sscanf(&(LineText[pos+8]), "%ld", &point);
4237 			}
4238 			lFrame->IRCPt = point * flip;
4239 		} else
4240 			Buffer->SkipnLines(1);
4241 		//search for the end of the packet?
4242 		//first line give atom counts, nat=       3 nfrg=       1 nqmmm=       0
4243 		Buffer->GetLine(LineText);
4244 		if (nSkip >= IRCnSkip) {
4245 			nSkip = 0;
4246 			float xvalue=0.0;
4247 			double totE=0.0;
4248 			if (runType == GLOBOPRun) {
4249 				Buffer->BackupnLines(2);	//Need the first line for GlobOp files
4250 				Buffer->GetLine(LineText);
4251 				ReadDoubleKeyword(LineText, "ENERGY", totE);
4252 				int Pos = FindKeyWord(LineText, "POINT", 5);
4253 				if (Pos >= 0) {
4254 					sscanf(&(LineText[Pos+5]), "%f", &xvalue);
4255 				}
4256 			} else {
4257 				if (!ReadLongKeyword(LineText, "NAT", &NumAIAtoms))
4258 					wxLogMessage(_("Unable to locate NAT (ab initio atom count)."));
4259 				if (!ReadLongKeyword(LineText, "NFRG", &NumFragments))
4260 					wxLogMessage(_("Unable to locate NFRG (fragment count)."));
4261 				if (!ReadLongKeyword(LineText, "NQMMM", &NumMDAtoms))
4262 					wxLogMessage(_("Unable to locate NQMM (MM atom count)."));
4263 
4264 				//second line is the x-axis and total energy, either ttotal or stotal
4265 				//STOTAL=   1.49848 sqrt(amu)*bohr   tot. E=      -91.6219797490 Hartree
4266 				Buffer->GetLine(LineText);
4267 				if (runType == IRCRun) {
4268 					if (!ReadFloatKeyword(LineText, "STOTAL", &xvalue)) {
4269 						wxLogMessage(_("Unable to locate STOTAL in IRC data packet. Unable to position this packet in the sequence."));
4270 					}
4271 				} else {	//MD and DRC spell it TTOTAL
4272 					if (!ReadFloatKeyword(LineText, "TTOTAL", &xvalue)) {
4273 						wxLogMessage(_("Unable to locate TOTAL in trajectory data packet. Unable to position this packet in the sequence."));
4274 					}
4275 				}
4276 				ReadDoubleKeyword(LineText, "TOT. E", totE);
4277 			}
4278 
4279 			xvalue *= flip;
4280 			xvalue += offset;
4281 			Frame * lFrame = NULL;
4282 			if (!Append && FirstFrame) {
4283 				lFrame = MainData->Frames;
4284 				lFrame->time = xvalue;
4285 				FirstFrame = false;
4286 			} else
4287 				lFrame = MainData->LocateNewFrame(xvalue);
4288 			if (lFrame) {
4289 				lFrame->Energy = totE;
4290 				// DRCs have an extra line with the kinetic and potential energies
4291 				//POT. E=        -9.1287351998 kin. E=          .0016326701 Hartree
4292 				if (runType == DRCRun) {
4293 					//DRCs conserve energy so Tot E == Pot. E + kinetic E.
4294 					//Thus only need to store two of them.
4295 					Buffer->GetLine(LineText);
4296 					double kinE;
4297 					if (ReadDoubleKeyword(LineText, "KIN. E", kinE))
4298 						lFrame->SetEnergy(kinE, KineticEnergy);
4299 				} else if (runType == MolDynamics) {
4300 				// MD runs have two extra lines for energies
4301 				//POT. E=        -47726.960743 kcal/mol
4302 				//kin. E=             7.015829  trans KE=   5.422237  rot KE=   1.593592 kcal/mol
4303 				//Todo: For MD runs energy is not necessarily conserved so all energies could be stored
4304 				//Don't have the infrastructure for that at the moment.
4305 					Buffer->GetLine(LineText);
4306 					Buffer->GetLine(LineText);
4307 					double kinE;
4308 					if (ReadDoubleKeyword(LineText, "KIN. E", kinE))
4309 						lFrame->SetEnergy(kinE, KineticEnergy);
4310 					else
4311 						wxLogMessage(_("Unable to parse the kinetic energy while reading a molecular dynamics trajectory file. The file format may not be correct."));
4312 				}
4313 
4314 				//setup the frame for the antipated atom count
4315 				if (!MainData->SetupFrameMemory(NumAIAtoms+NumFragments+NumMDAtoms, 0)) throw MemoryError();
4316 
4317 				if (NumAIAtoms > 0) {
4318 					switch (Buffer->LocateKeyWord(AIkeywords)) {
4319 						case 1:
4320 							Buffer->SkipnLines(1);
4321 							ParseGLogLine(Buffer, lFrame, NumAIAtoms, 10, &(MainData->MaxSize));
4322 							break;
4323 						case 2:
4324 							Buffer->SkipnLines(3); //just skip the header lines
4325 							ParseGLogLine(Buffer, lFrame, NumAIAtoms, 10, &(MainData->MaxSize));
4326 							break;
4327 						default:
4328 							wxLogMessage(_("Expected ab initio atoms, but unable to locate header."));
4329 					}
4330 				}
4331 				int fragkey;
4332 				if ((NumFragments > 0)&&(fragkey = Buffer->LocateKeyWord(FragmentAtomsKeywords))) {
4333 					if (fragkey == 1)
4334 						Buffer->SkipnLines(1);
4335 					else if (fragkey == 2)
4336 						Buffer->SkipnLines(3);
4337 					if (fragkey > 0) {
4338 						mpAtom *atm;
4339 						CPoint3D dst_locs[3];
4340 						CPoint3D pos;
4341 						int fstart;
4342 						int match[3] = {0, 0, 0};
4343 						CPoint3D src_locs[3];
4344 						std::string labels[3];
4345 						long fragNum, fragmentsfound=0;
4346 						int i;
4347 						CPoint3D new_pos;
4348 						CPoint3D rot_pos;
4349 						CPoint3D curr_pos;
4350 						CPoint3D orig;
4351 						Matrix4D vec2vec;
4352 						CPoint3D src_vec;
4353 						CPoint3D dst_vec;
4354 						CPoint3D dst_vec2;
4355 						CPoint3D dst_norm;
4356 						CPoint3D mid_norm;
4357 						CPoint3D mid_vec1, mid_vec2;
4358 						float dot;
4359 						char	token[kMaxLineLength+1];
4360 
4361 						Buffer->GetLine(LineText);
4362 						while (ReadStringKeyword(LineText, "FRAGNAME", token)) {
4363 							if (!strcasecmp(token, "H2ORHF") || !strcasecmp(token, "H2ODFT")) {	//builtin EFP1 style is limited to H2O with known labels
4364 								MainData->FragmentNames.push_back(std::string(token));
4365 								long fragNum = MainData->FragmentNames.size();
4366 								CPoint3D	pos;
4367 								int		AtomType;
4368 								for (int i=0; i<3; ++i) {
4369 									AtomType = -1;
4370 									Buffer->GetLine(LineText);
4371 									//lines have format "label x, y, z"
4372 									sscanf(LineText, "%s %f %f %f", token, &pos.x, &pos.y, &pos.z);
4373 									int c = 0;
4374 									if ((token[0] == 'Z')||(token[0] == 'z')) c = 1;
4375 									if (!strcasecmp(&(token[c]), "O1")) AtomType = 8;
4376 									else if (!strcasecmp(&(token[c]), "H2")||!strcasecmp(&(token[c]), "H3")) AtomType = 1;
4377 									if (AtomType > 0) {
4378 										mpAtom * atm = lFrame->AddAtom(AtomType, pos);
4379 										atm->SetFragmentNumber(fragNum);
4380 									}
4381 								}
4382 							}
4383 
4384 							// Custom fragment type.
4385 							else {
4386 
4387 								// Read the three atoms that setup the fragment.  These
4388 								// should be in angstroms.
4389 								MainData->FragmentNames.push_back(std::string(token));
4390 								fragNum = MainData->FragmentNames.size();
4391 								char label[kMaxLineLength];
4392 								for (i = 0; i < 3; ++i) {
4393 									Buffer->GetLine(LineText);
4394 									sscanf(LineText, "%s %f %f %f", label,
4395 										   &(dst_locs[i].x), &(dst_locs[i].y),
4396 										   &(dst_locs[i].z));
4397 									labels[i] = label;
4398 									/* std::cout << "Line: " << Line << std::endl; */
4399 									/* atm = lFrame->AddAtom(1, dst_locs[i]); */
4400 									/* atm->SetFragmentNumber(fragNum); */
4401 								}
4402 
4403 								//The fragment definition must be either already in the local list or in
4404 								//the builder library. FindFragmentDef will find it either way.
4405 								std::map<std::string, EFrag>::const_iterator frag;
4406 								frag = FindFragmentDef(token);
4407 								if (frag == MainData->efrags.end()) {
4408 									wxString msg;
4409 									msg.Printf(_("Unable to locate correct EFP2 fragment definition group named %s"), token);
4410 									wxLogMessage(msg);
4411 									throw DataError();
4412 								}
4413 
4414 								fstart = lFrame->NumAtoms;
4415 								const std::vector<EFragAtom>& labeled_atoms = frag->second.GetAtoms();
4416 								std::vector<EFragAtom>::const_iterator efrag_atom;
4417 
4418 								for (efrag_atom = labeled_atoms.begin();
4419 									 efrag_atom != labeled_atoms.end();
4420 									 ++efrag_atom) {
4421 
4422 									if (efrag_atom->GetLabel().compare(labels[0]) == 0) {
4423 										match[0] = lFrame->NumAtoms;
4424 										src_locs[0] = efrag_atom->GetCoords();
4425 									} else if (efrag_atom->GetLabel().compare(labels[1]) == 0) {
4426 										match[1] = lFrame->NumAtoms;
4427 										src_locs[1] = efrag_atom->GetCoords();
4428 									} else if (efrag_atom->GetLabel().compare(labels[2]) == 0) {
4429 										match[2] = lFrame->NumAtoms;
4430 										src_locs[2] = efrag_atom->GetCoords();
4431 									}
4432 
4433 									atm = lFrame->AddAtom(efrag_atom->GetAtomicNumber(),
4434 														  efrag_atom->GetCoords());
4435 									atm->SetFragmentNumber(fragNum);
4436 								}
4437 
4438 								// We first find a rotation that one will align a vector
4439 								// in the fragment template to the corresponding vector in
4440 								// the destination space.
4441 								dst_vec = dst_locs[1] - dst_locs[0];
4442 								Normalize3D(&dst_vec);
4443 
4444 								src_vec = src_locs[1] - src_locs[0];
4445 								Normalize3D(&src_vec);
4446 
4447 								SetRotationMatrix(vec2vec, &src_vec, &dst_vec);
4448 
4449 								// The common vector now serves as an axis of rotation.  We
4450 								// need to rotate the fragment template plane so that it
4451 								// coincides with the destination plane.  The angle of rotation
4452 								// can be determined by the angle between the two planes'
4453 								// normals.
4454 								lFrame->GetAtomPosition(match[0], orig);
4455 								Rotate3DOffset(vec2vec, src_locs[1] - orig, &mid_vec1);
4456 								Rotate3DOffset(vec2vec, src_locs[2] - orig, &mid_vec2);
4457 								UnitCrossProduct3D(&mid_vec1, &mid_vec2, &mid_norm);
4458 
4459 								dst_vec2 = dst_locs[2] - dst_locs[0];
4460 								UnitCrossProduct3D(&dst_vec, &dst_vec2, &dst_norm);
4461 
4462 								Matrix4D tri2tri;
4463 								dot = DotProduct3D(&mid_norm, &dst_norm);
4464 
4465 								// Technically, the axis of rotation (the aligned vector)
4466 								// might be facing a different direction than we think it
4467 								// is. To be consistent, we instead use the axis that is
4468 								// normal to both planes' normals. It points in the same
4469 								// or opposite direction as dst_vec.
4470 								CPoint3D axis;
4471 								UnitCrossProduct3D(&mid_norm, &dst_norm, &axis);
4472 								RotateAroundAxis(tri2tri, axis, acos(dot) * 180.0f / kPi);
4473 
4474 								// We concatenate the two rotation matrices.
4475 								Matrix4D transform;
4476 								MultiplyMatrix(vec2vec, tri2tri, transform);
4477 
4478 								// Okay, for each atom we added for this fragment instance,
4479 								// we move all fragment atoms into destination space. We
4480 								// translate to make the base fragment atom the origin and
4481 								// then rotate to align the fragment with the destination
4482 								// plane, and then translate by the base destination atom.
4483 								for (long i = fstart; i < lFrame->NumAtoms; ++i) {
4484 									lFrame->GetAtomPosition(i, curr_pos);
4485 									new_pos = curr_pos - orig;
4486 									Rotate3DOffset(transform, new_pos, &rot_pos);
4487 									new_pos = rot_pos + dst_locs[0];
4488 									lFrame->SetAtomPosition(i, new_pos);
4489 								}
4490 							}
4491 							fragmentsfound++;
4492 							if (fragmentsfound < NumFragments) {
4493 								//gamess prints out all the coordinates, but we only read the first three
4494 								//need to skip the rest to the start of the next fragment
4495 								if (Buffer->LocateKeyWord("FRAGNAME", 8))
4496 									Buffer->GetLine(LineText);
4497 							}
4498 						}
4499 					}
4500 
4501 				}
4502 				if ((NumMDAtoms > 0)&&Buffer->LocateKeyWord("----- MM PARTICLE COORDINATES", 29)) {
4503 					Buffer->SkipnLines(1);
4504 				}
4505 
4506 				if (Prefs->GetAutoBond())
4507 					lFrame->SetBonds(Prefs, false, ProgressInd);
4508 			}
4509 		} else
4510 			++ nSkip;
4511 	}
4512 	return 1;
4513 }
OpenGAMESSIRC(BufferFile * Buffer,bool Append,long flip,float offset)4514 long MolDisplayWin::OpenGAMESSIRC(BufferFile * Buffer, bool Append, long flip, float offset)
4515 {	long			LinePos, NumAtoms, point;
4516 	float			Xpos;
4517 	bool			KeyWordFound;
4518 	char			LineText[kMaxLineLength+1];
4519 
4520 	ProgressInd->ChangeText("Reading GAMESS IRC file...");
4521 	Frame * lFrame = MainData->cFrame;
4522 	long IRCnSkip = Prefs->GetDRCSkip();
4523 	long nSkip = 0;
4524 
4525 	if (!Append) {
4526 		if (!Buffer->LocateKeyWord("IRC INFORMATION PACKET", 22)) return 0;
4527 		if (!Buffer->LocateKeyWord("POINT=", 6)) return 0;
4528 		Buffer->GetLine(LineText);
4529 		LinePos = 6;
4530 		sscanf(&(LineText[LinePos]), "%ld", &point);
4531 		lFrame->IRCPt = (long) (flip*point + offset);
4532 		LinePos = FindKeyWord(LineText, "STOTAL=", 7) + 7;
4533 		sscanf(&(LineText[LinePos]), "%f", &(lFrame->time));
4534 		lFrame->time *= flip;
4535 		lFrame->time += offset;
4536 		LinePos = FindKeyWord(LineText, "E=", 2) + 2;
4537 		sscanf(&(LineText[LinePos]), "%lf", &(lFrame->Energy));
4538 		Buffer->SkipnLines(1);	//skip "Coordinates (bohr)... label line
4539 
4540 		wxFileOffset start = Buffer->GetFilePos();
4541 		if (!Buffer->LocateKeyWord("MASS-WEIGHTED GRADIENT", 22)) throw DataError();
4542 		wxFileOffset endpos = Buffer->GetFilePos();
4543 		Buffer->SetFilePos(start);
4544 		NumAtoms = Buffer->GetNumLines(endpos-start);
4545 
4546 		if (!MainData->SetupFrameMemory(NumAtoms, 0)) throw MemoryError();
4547 
4548 		ParseGLogLine(Buffer, lFrame, NumAtoms, 0, &(MainData->MaxSize));
4549 
4550 		if (Prefs->GetAutoBond())
4551 			lFrame->SetBonds(Prefs, false, ProgressInd);
4552 	}
4553 	NumAtoms = lFrame->NumAtoms;
4554 	KeyWordFound = Buffer->LocateKeyWord("POINT=", 6);
4555 	while (KeyWordFound) {
4556 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4557 			{ throw UserCancel();}
4558 		Buffer->GetLine(LineText);
4559 		if (nSkip >= IRCnSkip) {
4560 			nSkip = 0;
4561 			LinePos = 6;
4562 			sscanf(&(LineText[LinePos]), "%ld", &point);
4563 			point *= flip;
4564 			LinePos = FindKeyWord(LineText, "STOTAL=", 7) + 7;
4565 			sscanf(&(LineText[LinePos]), "%f", &Xpos);
4566 			Xpos *= flip;
4567 			Xpos += offset;
4568 			lFrame = MainData->LocateNewFrame(Xpos);
4569 
4570 			if (lFrame) {
4571 				lFrame->IRCPt = point;
4572 				LinePos = FindKeyWord(LineText, "E=", 2) + 2;
4573 				sscanf(&(LineText[LinePos]), "%lf", &(lFrame->Energy));
4574 				Buffer->SkipnLines(1);	//skip "Coordinates (bohr)... label line
4575 
4576 				sprintf(LineText, "Reading in IRC point %ld", point);
4577 				ProgressInd->ChangeText(LineText);
4578 
4579 				if (!MainData->SetupFrameMemory(NumAtoms, 0)) throw MemoryError();
4580 
4581 				if (ParseGLogLine(Buffer, lFrame, NumAtoms, 0, &(MainData->MaxSize)) <= 0) break;
4582 
4583 				if (Prefs->GetAutoBond())
4584 					lFrame->SetBonds(Prefs, false, ProgressInd);
4585 			}
4586 		} else
4587 			++nSkip;
4588 		KeyWordFound = Buffer->LocateKeyWord("POINT=", 6);
4589 	}
4590 	MainData->cFrame = MainData->Frames;
4591 	MainData->CurrentFrame = 1;
4592 	return 1;
4593 }	/*OpenGAMESSIRC*/
OpenGAMESSIRCLog(BufferFile * Buffer,long flip,float offset,long NumOccAlpha,long NumOccBeta,long NumFragmentAtoms)4594 long MolDisplayWin::OpenGAMESSIRCLog(BufferFile * Buffer, long flip, float offset,
4595 		long NumOccAlpha, long NumOccBeta, long NumFragmentAtoms) {
4596 	long			point, LinePos, NumBetaUHFOrbs=0;
4597 	char			LineText[kMaxLineLength+1];
4598 	float			Xpos;
4599 	bool			LINEAR=false;
4600 
4601 	ProgressInd->ChangeText("Reading GAMESS IRC log file...");
4602 	Frame * lFrame = MainData->cFrame;
4603 	long IRCnSkip = Prefs->GetDRCSkip();
4604 	long nSkip = 0;
4605 
4606 	long NumAtoms = lFrame->NumAtoms;
4607 	long NumExpectedAtoms = NumAtoms;
4608 	if (MainData->InputOptions->Control->GetSCFType()==GAMESS_UHF) NumBetaUHFOrbs = NumOccBeta;	//Only seperate Beta spin orbs for UHF wavefunctions
4609 	char NextPointKeyword[30];
4610 	strcpy(NextPointKeyword, "* NEXT POINT ON IRC FOUND *");
4611 	bool KeyWordFound = Buffer->LocateKeyWord(NextPointKeyword, 27);
4612 	if (!KeyWordFound) {	//search for the alternative keyword needed for pace=linear IRC's
4613 		strcpy(NextPointKeyword, "ON THE REACTION PATH");
4614 		KeyWordFound = Buffer->LocateKeyWord(NextPointKeyword, 20);
4615 		if (KeyWordFound) LINEAR=true;
4616 	}
4617 	while (KeyWordFound) {
4618 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4619 			{ throw UserCancel();}
4620 		if (LINEAR) Buffer->BackupnLines(1);
4621 		Buffer->SkipnLines(1);
4622 		if (Buffer->LocateKeyWord("POINT", 5)) {
4623 			Buffer->GetLine(LineText);
4624 			LinePos = 6;
4625 			int result = sscanf(&(LineText[LinePos]), "%ld", &point);
4626 			if (result != 1) break;
4627 		} else break;
4628 		if (Buffer->LocateKeyWord("STOTAL", 6)) {
4629 			Buffer->GetLine(LineText);
4630 			LinePos = 8;
4631 			int result = sscanf(&(LineText[LinePos]), "%f", &Xpos);
4632 			if (result != 1) break;
4633 		} else break;
4634 		lFrame = NULL;
4635 		if (nSkip >= IRCnSkip) {
4636 			nSkip = 0;
4637 			point *= flip;
4638 			Xpos *= flip;
4639 			Xpos += offset;
4640 			lFrame = MainData->LocateNewFrame(Xpos);
4641 			if (lFrame) {
4642 				sprintf(LineText, "Reading in IRC point %ld", point);
4643 				ProgressInd->ChangeText(LineText);
4644 
4645 				lFrame->IRCPt = point;
4646 				if (Buffer->LocateKeyWord("ENERGY            =", 19)) {
4647 					Buffer->GetLine(LineText);
4648 					LinePos = 20;
4649 					sscanf(&(LineText[LinePos]), "%lf", &(lFrame->Energy));
4650 				}
4651 
4652 				if (!Buffer->LocateKeyWord("COORDINATES OF ALL ATOMS", 24)) break;
4653 				Buffer->SkipnLines(3);
4654 
4655 				MainData->SetupFrameMemory(NumAtoms, 0);
4656 
4657 				ParseGLogLine(Buffer, lFrame, NumAtoms, 10, &(MainData->MaxSize));
4658 
4659 				if ((NumFragmentAtoms <= 0)&&(NumExpectedAtoms > MainData->cFrame->NumAtoms))
4660 					NumFragmentAtoms = NumExpectedAtoms - MainData->cFrame->NumAtoms;
4661 				if (NumFragmentAtoms > 0) {
4662 					Buffer->BackupnLines(2);
4663 					if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 41)) {
4664 						Buffer->SkipnLines(3);
4665 						MainData->ReadFragmentCoordinates(Buffer, NumFragmentAtoms);
4666 					}
4667 				}
4668 				if (Prefs->GetAutoBond())
4669 					lFrame->SetBonds(Prefs, false, ProgressInd);
4670 			}
4671 		} else
4672 			++ nSkip;
4673 		wxFileOffset SavedPos = Buffer->GetFilePos();
4674 		KeyWordFound = Buffer->LocateKeyWord(NextPointKeyword, 20);
4675 		wxFileOffset NextPointPos = -1;
4676 		if (KeyWordFound) NextPointPos = Buffer->GetFilePos();
4677 		if (lFrame) {
4678 				//Attempt to read in orbitals for this geometry
4679 			if (MainData->Basis) {
4680 				Buffer->SetFilePos(SavedPos);
4681 				try {
4682 					bool test = Buffer->LocateKeyWord("CONVERGED ORBITALS AT IRC POINT", 31, NextPointPos);
4683 					if (test) {
4684 							//skip over the line to the start of the orbital blocks
4685 							//There is always a blank line before the orbs, but there may a '---' divider line after the key line just found
4686 						if ((NextPointPos<0)||(NextPointPos>Buffer->GetFilePos())) {
4687 							Buffer->SetFilePos(Buffer->FindBlankLine());
4688 							Buffer->SkipnLines(1);
4689 							ProgressInd->ChangeText("Reading eigenvectors");
4690 							if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4691 								{ throw UserCancel();}
4692 							lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
4693 								MainData->GetNumBasisFunctions(), NumBetaUHFOrbs, NumOccAlpha, NumOccBeta,
4694 									(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
4695 	//						if (MainData->InputOptions->Control->GetSCFType()==MCSCF)
4696 	//							lFrame->ExchangeEigenVectors();
4697 						} else Buffer->SetFilePos(SavedPos);
4698 					}
4699 	//				if (lFrame->Orbs) {
4700 	//					lFrame->Orbs->NumOccupiedAlphaOrbs = NumOccAlpha;
4701 	//					lFrame->Orbs->NumOccupiedBetaOrbs = NumOccBeta;
4702 	//					if (lFrame->Orbs->EigenVectors)
4703 	//						lFrame->Orbs->EigenVectors->OrbType = MainData->InputOptions->Control->GetSCFType();
4704 	//				}
4705 				}
4706 				catch (std::bad_alloc) {
4707 	//				if (lFrame->Orbs) delete lFrame->Orbs;
4708 	//				lFrame->Orbs = NULL;
4709 					MessageAlert("Insufficient memory to read in eigenvectors.");
4710 				}
4711 				catch (MemoryError) {
4712 	//				if (lFrame->Orbs) delete lFrame->Orbs;
4713 	//				lFrame->Orbs = NULL;
4714 					MessageAlert("Insufficient memory to read in eigenvectors.");
4715 				}
4716 				catch (DataError) {
4717 					MessageAlert("Error reading eigenvectors, orbitals skipped.");
4718 	//				if (lFrame->Orbs) delete lFrame->Orbs;
4719 	//				lFrame->Orbs = NULL;
4720 				}
4721 			}
4722 			if (NextPointPos >= 0)
4723 				Buffer->SetFilePos(NextPointPos);
4724 		}
4725 	}
4726 	MainData->cFrame = MainData->Frames;
4727 	MainData->CurrentFrame = 1;
4728 	return 1;
4729 }	/*OpenGAMESSIRCLog*/
OpenGAMESSDRC(BufferFile * Buffer,bool LogFile,bool Append,long flip,float offset)4730 long MolDisplayWin::OpenGAMESSDRC(BufferFile * Buffer, bool LogFile, bool Append,
4731 			long flip, float offset) {
4732 
4733 	bool			QPpresent, KeyWordFound, newQPformat=false;
4734 	long			NumAtoms, Elength, nskip=0, LinePos, EStartPos;
4735 	char			Etext[40], LineText[kMaxLineLength+1];
4736 	float			tempfloat;
4737 	double			PE, KE;
4738 
4739 	ProgressInd->ChangeText("Reading GAMESS DRC file...");
4740 	Frame * lFrame = MainData->cFrame;
4741 	if (!Append) {
4742 	}
4743 	wxFileOffset FilePos = Buffer->GetFilePos();
4744 	QPpresent = Buffer->LocateKeyWord("Q          P", 12);
4745 	if (!QPpresent) newQPformat = Buffer->LocateKeyWord("Q              P", 16);
4746 	Buffer->SetFilePos(FilePos);
4747 		//test for Q P since there are two possible formats (Q P... include some mode information)
4748 	if (QPpresent) {
4749 		strncpy(Etext, "ENERGY         ENERGY       ENERGY", 34);
4750 		Elength = 34;
4751 		EStartPos = 41;
4752 	} else if (newQPformat) {	//After Sep62001R5 the header changed a bit
4753 		strncpy(Etext, "E         ENERGY         ENERGY", 31);
4754 		Elength = 31;
4755 		EStartPos = 41;
4756 		QPpresent = true;
4757 	} else {
4758 		strncpy(Etext, "ENERGY        ENERGY          ENERGY", 36);
4759 		Elength = 36;
4760 		EStartPos = 12;
4761 	}
4762 	KeyWordFound = Buffer->LocateKeyWord(Etext, Elength);
4763 	if (!KeyWordFound) return 0;
4764 	if (!Append) {
4765 		Buffer->SkipnLines(1);
4766 		Buffer->GetLine(LineText);
4767 		sscanf(LineText, "%f", &(lFrame->time));
4768 		lFrame->time *= flip;
4769 		lFrame->time += offset;
4770 		LinePos = EStartPos;
4771 		sscanf(&(LineText[LinePos]), "%lf %lf %lf", &KE, &PE,
4772 			&(lFrame->Energy));//Don't worry about the PE since E-KE=PE
4773 		lFrame->SetEnergy(KE, KineticEnergy);
4774 
4775 		if (!Buffer->LocateKeyWord("VELOCITY", 8)) return 0;
4776 		Buffer->SkipnLines(1);
4777 		if (LogFile)
4778 			Buffer->SkipnLines(1);
4779 		FilePos = Buffer->GetFilePos();
4780 		Buffer->LocateKeyWord("--------", 8);
4781 		wxFileOffset endPos = Buffer->GetFilePos();
4782 		Buffer->SetFilePos(FilePos);
4783 		NumAtoms = Buffer->GetNumLines(endPos-FilePos)-1;
4784 		if (NumAtoms <= 0) throw DataError();
4785 
4786 		if (!MainData->SetupFrameMemory(NumAtoms, 0)) throw MemoryError();
4787 
4788 		ParseGLogLine(Buffer, lFrame, NumAtoms, 2, &(MainData->MaxSize));
4789 
4790 		if (Prefs->GetAutoBond())
4791 			lFrame->SetBonds(Prefs, false, ProgressInd);
4792 
4793 		KeyWordFound = Buffer->LocateKeyWord(Etext, Elength);
4794 	}
4795 
4796 	NumAtoms = lFrame->NumAtoms;
4797 	long DRCnSkip = Prefs->GetDRCSkip();
4798 	while (KeyWordFound) {
4799 		Buffer->SkipnLines(1);
4800 		if (nskip >= DRCnSkip) {
4801 			nskip = 0;
4802 			if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4803 				{ throw UserCancel();}
4804 			Buffer->GetLine(LineText);
4805 			sscanf(LineText, "%f", &tempfloat);
4806 			tempfloat *= flip;
4807 			tempfloat += offset;
4808 			lFrame = MainData->LocateNewFrame(tempfloat);
4809 			if (lFrame == NULL) {
4810 				KeyWordFound = Buffer->LocateKeyWord(Etext, Elength);
4811 				continue;
4812 			}
4813 			LinePos = EStartPos;
4814 			sscanf(&(LineText[LinePos]), "%lf %lf %lf", &KE, &PE,
4815 				&(lFrame->Energy));//Don't worry about the PE since E-KE=PE
4816 			lFrame->SetEnergy(KE, KineticEnergy);
4817 
4818 			sprintf(LineText, "Reading DRC time = %f", tempfloat);
4819 			ProgressInd->ChangeText(LineText);
4820 
4821 			if (!MainData->SetupFrameMemory(NumAtoms, 0)) throw MemoryError();
4822 
4823 			if (!Buffer->LocateKeyWord("VELOCITY", 8)) break;;
4824 			Buffer->SkipnLines(1);
4825 			if (LogFile)
4826 				Buffer->SkipnLines(1);
4827 			if (ParseGLogLine(Buffer, lFrame, NumAtoms, 2, &(MainData->MaxSize)) < 0) break;
4828 
4829 			if (Prefs->GetAutoBond())
4830 				lFrame->SetBonds(Prefs, false, ProgressInd);
4831 		} else
4832 			++nskip;
4833 		KeyWordFound = Buffer->LocateKeyWord(Etext, Elength);
4834 	}
4835 
4836 	lFrame = MainData->Frames;
4837 	for (long iframe=0; iframe<MainData->NumFrames; ++iframe) {
4838 		lFrame->IRCPt = iframe + 1;
4839 		lFrame = lFrame->NextFrame;
4840 	}
4841 	MainData->cFrame = MainData->Frames;
4842 	MainData->CurrentFrame = 1;
4843 	return 1;
4844 }	/*OpenGAMESSDRC*/
4845 
OpenGAMESSGlobOpLog(BufferFile * Buffer,long NumOccAlpha,long NumOccBeta,long NumFragmentAtoms)4846 long MolDisplayWin::OpenGAMESSGlobOpLog(BufferFile * Buffer,
4847 									 long NumOccAlpha, long NumOccBeta, long NumFragmentAtoms) {
4848 	long			NumBetaUHFOrbs=0;
4849 	char			LineText[kMaxLineLength+1];
4850 
4851 	ProgressInd->ChangeText("Reading GAMESS GlobOp log file...");
4852 	Frame * lFrame = MainData->cFrame;
4853 
4854 	long NumAtoms = lFrame->NumAtoms;
4855 	long NumExpectedAtoms = NumAtoms;
4856 	MainData->SetCurrentFrame(MainData->GetNumFrames());
4857 		//Setup a new frame for the initial geometry.
4858 	lFrame = MainData->AddFrame(NumExpectedAtoms, lFrame->GetNumBonds());
4859 	lFrame->IRCPt = MainData->GetCurrentFrame();
4860 	lFrame->time = MainData->GetCurrentFrame();
4861 	if (MainData->InputOptions->Control->GetSCFType()==GAMESS_UHF) NumBetaUHFOrbs = NumOccBeta;	//Only seperate Beta spin orbs for UHF wavefunctions
4862 
4863 // There appear to be two type of files, MCMIN=T|F. If true each accepted geometry is optimized
4864 // and the code should only grab the optimized coordinates and energies. If false then there is just
4865 // a single set of coordinates and energy.
4866 // If true look for "EQUILIBRIUM GEOMETRY LOCATED", grab the following coordinates and optionally, orbitals.
4867 // Both types end with an energy "ENERGY ACCEPTED AT POINT", probably best to use it.
4868 // It appears the globop frame is bracketed by "GEOMETRY NUMBER" and "ENERGY ACCEPTED", though not all
4869 // geometries are accepted.
4870 
4871 // Old GlobOp files lack the keywords, but current ones do have them under the heading of
4872 // ---- MONTE CARLO/SIMULATED ANNEALING OPTIONS -----
4873 
4874 	enum GlobOpTags {
4875 		GeomStart=0,
4876 		NonOptGeometry,
4877 		GeomEnd,
4878 		GeomEnd2,
4879 		OptGeometry,
4880 		Orbitals,
4881 		FailedOpt
4882 	};
4883 
4884 	std::vector<std::pair <std::string, int> > keywords;
4885 	keywords.push_back(make_pair (std::string("GEOMETRY NUMBER"), (int) GeomStart));//old style
4886 	keywords.push_back(make_pair (std::string("EVALUATE ENERGY AT NEW TRANSLATIONAL GEOMETRY"), (int) GeomStart));//new style
4887 	keywords.push_back(make_pair (std::string("BEGINNING GEOMETRY SEARCH POINT NSERCH="), (int) NonOptGeometry));//new style
4888 	keywords.push_back(make_pair (std::string("NUCLEAR COORDINATES FOR GLOBAL OPTIMIZATION POINT"), (int) NonOptGeometry));
4889 	keywords.push_back(make_pair (std::string("ENERGY ACCEPTED AT POINT"), (int) GeomEnd));
4890 	keywords.push_back(make_pair (std::string("ENERGY ACCEPTED AT GLOBAL SEARCH POINT"), (int) GeomEnd2));
4891 	keywords.push_back(make_pair(std::string("EQUILIBRIUM GEOMETRY LOCATED"), (int) OptGeometry));
4892 	keywords.push_back(make_pair(std::string("MOLECULAR ORBITALS"), (int) Orbitals));
4893 	keywords.push_back(make_pair(std::string("FAILURE TO LOCATE STATIONARY POINT"), (int) FailedOpt));
4894 
4895 	// In the old style there was a clear beginning and end of a search. In the new style it's a bit murkier.
4896 	// The new style doesn't announce the end of an optimization until you are past the coordinates.
4897 
4898 	int state = 1, kw;
4899 	while (! Buffer->Eof()) {
4900 		if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
4901 		{ throw UserCancel();}
4902 		if (-1 < (kw = Buffer->LocateKeyWord(keywords))) {
4903 			switch (kw) {
4904 				case GeomStart:	//start of a search point
4905 					if (state == 0) {
4906 						state = 1;
4907 					} else {//found another start before finding the end of the previous geometry
4908 						//The most likely reason is that the previous geometry was not accepted.
4909 						//I could search for the rejection text, but this should do the trick.
4910 						MainData->DeleteFrame();
4911 						lFrame = MainData->GetCurrentFramePtr();
4912 					}
4913 					lFrame = MainData->AddFrame(NumExpectedAtoms, lFrame->GetNumBonds());
4914 					lFrame->IRCPt = MainData->GetCurrentFrame();
4915 					lFrame->time = MainData->GetCurrentFrame();
4916 					Buffer->SkipnLines(1);
4917 					break;
4918 				case NonOptGeometry:	// set of coordinates, MCMIN=false, these coords seem to be in an odd format
4919 					if (state == 1) {
4920 						if (lFrame->NumAtoms > 0) {
4921 							MainData->DeleteFrame();
4922 							lFrame = MainData->GetCurrentFramePtr();
4923 							lFrame = MainData->AddFrame(NumExpectedAtoms, lFrame->GetNumBonds());
4924 							lFrame->IRCPt = MainData->GetCurrentFrame();
4925 							lFrame->time = MainData->GetCurrentFrame();
4926 						}
4927 						Buffer->SkipnLines(1);
4928 
4929 						//The output is in the form of index_# atomic name x y z
4930 						if ((NumAtoms-NumFragmentAtoms)>0) {
4931 							bool done=false;
4932 							int nextExpected=1;
4933 							while (!done) {
4934 								if (Buffer->GetLine(LineText) < 1) break;
4935 								int index;
4936 								CPoint3D position;
4937 								unsigned char Label[kMaxLineLength];
4938 								int items = sscanf(LineText, "%d %s %f%f%f", &index, Label, &(position.x),
4939 												   &(position.y), &(position.z));
4940 								if (items == 5) {
4941 									if (index != nextExpected) {
4942 										wxLogMessage(_("Error parsing coordinates, attempting to continue."));
4943 										break;
4944 									} else {
4945 										int atomtype = SetAtomType(Label);
4946 										if (atomtype > 0) {
4947 											lFrame->AddAtom(atomtype, position);
4948 										} else {
4949 											wxLogMessage(_("Error parsing coordinates, attempting to continue."));
4950 											break;
4951 										}
4952 									}
4953 
4954 								} else {
4955 									Buffer->BackupnLines(1);	//reset position and end
4956 									break;
4957 								}
4958 								nextExpected ++;
4959 							}
4960 						}
4961 
4962 						if ((NumFragmentAtoms <= 0)&&(NumExpectedAtoms > MainData->cFrame->NumAtoms))
4963 							NumFragmentAtoms = NumExpectedAtoms - MainData->cFrame->NumAtoms;
4964 						if (NumFragmentAtoms > 0) {
4965 							Buffer->BackupnLines(2);
4966 							if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 41)) {
4967 								Buffer->SkipnLines(3);
4968 								MainData->ReadFragmentCoordinates(Buffer, NumFragmentAtoms);
4969 							}
4970 						}
4971 						if (Prefs->GetAutoBond())
4972 							lFrame->SetBonds(Prefs, false, ProgressInd);
4973 					} else {
4974 						wxLogMessage(_("Unexpected set of coordinates! Skipping and attempting to continue"));
4975 						Buffer->SkipnLines(1);
4976 					}
4977 					break;
4978 				case GeomEnd: // End of the search, read the energy and store the frame.
4979 				case GeomEnd2:
4980 					if (state == 0) {	// Found an end without a matching begining, skip
4981 						wxLogMessage(_("Unexpected end of search point! Skipping and attempting to continue"));
4982 						Buffer->SkipnLines(1);
4983 					} else {
4984 						Buffer->GetLine(LineText);
4985 						int geom;
4986 						int tokenLen = 25;
4987 						if (kw == GeomEnd2) tokenLen = 38;
4988 						int result = sscanf(&(LineText[tokenLen]), "%d IS %lf", &geom, &(lFrame->Energy));
4989 						if (result != 2)
4990 							wxLogMessage(_("Error parsing final energy for a geometry. Attempting to continue."));
4991 						sprintf(LineText, "Completed parsing geometry %d", geom);
4992 						ProgressInd->ChangeText(LineText);
4993 						state = 0;
4994 					}
4995 					break;
4996 				case OptGeometry:	// Final optimized coordinates, parse and overwrite previous set
4997 					if (state == 1) {
4998 						if (!Buffer->LocateKeyWord("COORDINATES OF ALL ATOMS", 24)) break;
4999 						Buffer->SkipnLines(3);
5000 
5001 						ParseGLogLine(Buffer, lFrame, NumAtoms, 10, &(MainData->MaxSize));
5002 
5003 						if ((NumFragmentAtoms <= 0)&&(NumExpectedAtoms > MainData->cFrame->NumAtoms))
5004 							NumFragmentAtoms = NumExpectedAtoms - MainData->cFrame->NumAtoms;
5005 						if (NumFragmentAtoms > 0) {
5006 							Buffer->BackupnLines(2);
5007 							if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 41)) {
5008 								Buffer->SkipnLines(3);
5009 								MainData->ReadFragmentCoordinates(Buffer, NumFragmentAtoms);
5010 							}
5011 						}
5012 						if (Prefs->GetAutoBond())
5013 							lFrame->SetBonds(Prefs, false, ProgressInd);
5014 					} else Buffer->SkipnLines(1);
5015 					break;
5016 				case Orbitals: // Set of Orbitals
5017 					//Attempt to read in orbitals for this geometry
5018 					if (state == 1) {
5019 						if (MainData->Basis) {
5020 							try {
5021 								//skip over the line to the start of the orbital blocks
5022 								//There is always a blank line before the orbs, but there may a '---' divider line after the key line just found
5023 								Buffer->SetFilePos(Buffer->FindBlankLine());
5024 								Buffer->SkipnLines(1);
5025 								ProgressInd->ChangeText("Reading eigenvectors");
5026 								if (!ProgressInd->UpdateProgress(Buffer->PercentRead()))
5027 								{ throw UserCancel();}
5028 								lFrame->ParseGAMESSEigenVectors(Buffer, MainData->GetNumBasisFunctions(),
5029 																MainData->GetNumBasisFunctions(), NumBetaUHFOrbs, NumOccAlpha, NumOccBeta,
5030 																(TypeOfWavefunction)(MainData->InputOptions->Control->GetSCFType()), ProgressInd);
5031 							}
5032 							catch (std::bad_alloc) {
5033 								MessageAlert("Insufficient memory to read in eigenvectors.");
5034 							}
5035 							catch (MemoryError) {
5036 								MessageAlert("Insufficient memory to read in eigenvectors.");
5037 							}
5038 							catch (DataError) {
5039 								MessageAlert("Error reading eigenvectors, orbitals skipped.");
5040 							}
5041 						}
5042 					} else Buffer->SkipnLines(1);
5043 					break;
5044 				case FailedOpt:	//optimization failed.
5045 					if (state == 1) {
5046 						sprintf(LineText, "Geometry optimization incomplete for frame %ld", MainData->GetNumFrames()-1);
5047 						MessageAlert(LineText);
5048 
5049 						if (Buffer->LocateKeyWord("COORDINATES OF ALL ATOMS ARE (ANGS)", 35)) {
5050 							Buffer->SkipnLines(3);
5051 							ParseGLogLine(Buffer, lFrame, NumAtoms, 10, &(MainData->MaxSize));
5052 
5053 							if ((NumFragmentAtoms <= 0)&&(NumExpectedAtoms > MainData->cFrame->NumAtoms))
5054 								NumFragmentAtoms = NumExpectedAtoms - MainData->cFrame->NumAtoms;
5055 							if (NumFragmentAtoms > 0) {
5056 								Buffer->BackupnLines(2);
5057 								if (Buffer->LocateKeyWord("COORDINATES OF FRAGMENT MULTIPOLE CENTERS", 41)) {
5058 									Buffer->SkipnLines(3);
5059 									MainData->ReadFragmentCoordinates(Buffer, NumFragmentAtoms);
5060 								}
5061 							}
5062 							if (Prefs->GetAutoBond())
5063 								lFrame->SetBonds(Prefs, false, ProgressInd);
5064 						}
5065 					} else Buffer->SkipnLines(1);
5066 					break;
5067 			}
5068 		} else break;
5069 	}
5070 	if (state == 1) MainData->DeleteFrame();	//started a frame without finding the end.
5071 	MainData->SetCurrentFrame(1);
5072 	MainData->DeleteFrame();	//Delete the initial frame that has only starting geometry
5073 	return 1;
5074 }	/*OpenGAMESSGlobOpLog*/
5075 
5076 /**
5077  Output the coordinates in gamess input format ($DATA and $EFRAG group).
5078  If AllFrames then a series of $DATA groups will be output for the user to divide as needed.
5079  @param Buffer A buffer to write the text to.
5080  @param AllFrames Should the data for all frames be included or just the current frame?
5081  */
ExportGAMESS(BufferFile * Buffer,bool AllFrames)5082 void MolDisplayWin::ExportGAMESS(BufferFile * Buffer, bool AllFrames) {
5083 	//Utilize the data group class to do all the real work
5084 	InputData * lInputOptions = MainData->GetInputData();
5085 	long basisTest = 1;
5086 	if (lInputOptions->Basis) {
5087 		if (lInputOptions->Basis->GetBasis() != 0) basisTest = 0;
5088 	}
5089 	if (!AllFrames) {
5090 		lInputOptions->Data->WriteToFile(Buffer, MainData, Prefs, basisTest);
5091 	} else {
5092 		long savedFrame	= MainData->GetCurrentFrame();
5093 		MainData->CurrentFrame = 1;
5094 		MainData->cFrame = MainData->Frames;
5095 		for (int iframe=0; iframe<MainData->GetNumFrames(); ++iframe) {
5096 			char		text[kMaxLineLength];
5097 			sprintf(text, "! Frame # %d", iframe+1);
5098 			Buffer->WriteLine(text, true);
5099 
5100 			MainData->SetCurrentFrame(iframe);
5101 
5102 			lInputOptions->Data->WriteToFile(Buffer, MainData, Prefs, basisTest);
5103 		}
5104 
5105 		MainData->SetCurrentFrame(savedFrame);
5106 
5107 		if ((lInputOptions->Data->GetCoordType() == ZMTCoordType)||
5108 			(lInputOptions->Data->GetCoordType() == ZMTMPCCoordType)) {
5109 			//If we are using internals update their values after restoring the frame
5110 			Internals * IntCoords = MainData->GetInternalCoordinates();
5111 			MOPacInternals * mInts = NULL;
5112 			if (IntCoords)
5113 				mInts = IntCoords->GetMOPacStyle();
5114 			if (mInts) {
5115 				mInts->CartesiansToInternals(MainData);
5116 			}
5117 		}
5118 	}
5119 }
WriteTabbedEnergies(BufferFile * Buffer,bool AllFrames)5120 void MolDisplayWin::WriteTabbedEnergies(BufferFile * Buffer, bool AllFrames) {
5121 	char	text[kMaxLineLength];
5122 	long	a1, a2, a3;
5123 
5124 	EnergyOptions * lEOpts = Prefs->GetEnergyOptions();
5125 	GraphOptions * lPOpts = Prefs->GetGraphOptions();
5126 	bool	PlotTE = lEOpts->PlotEnergy();
5127 	bool	PlotMPE = lEOpts->PlotMPEnergy();
5128 	bool PlotKE = lEOpts->PlotKEnergy();
5129 	bool PlotPE = lEOpts->PlotPEnergy();
5130 
5131 	Buffer->PutText("X Pos");
5132 	if (PlotTE) Buffer->PutText("\tEnergy");
5133 	if (PlotMPE) Buffer->PutText("\tMP2 Energy");
5134 	if (PlotKE) Buffer->PutText("\tKinetic Energy");
5135 	if (PlotPE) Buffer->PutText("\tPotential Energy");
5136 	if (lPOpts->PlotRMSGradient()) Buffer->PutText("\tRMS Gradient");
5137 	if (lPOpts->PlotMaxGradient()) Buffer->PutText("\tMax Gradient");
5138 	if (lPOpts->PlotBondLength()) {
5139 		a1 = lPOpts->Get1stAtom();
5140 		a2 = lPOpts->Get2ndAtom();
5141 		sprintf(text, "\tBond %ld-%ld", a1+1, a2+1);
5142 		Buffer->PutText(text);
5143 	}
5144 	if (lPOpts->PlotBondAngle()) {
5145 		a1 = lPOpts->Get1stAtom();
5146 		a2 = lPOpts->Get2ndAtom();
5147 		a3 = lPOpts->Get3rdAtom();
5148 		sprintf(text, "\tAngle %ld-%ld-%ld", a1+1, a2+1, a3+1);
5149 		Buffer->PutText(text);
5150 	}
5151 	Buffer->WriteLine("", true);
5152 
5153 	Frame * lFrame = MainData->Frames;
5154 	float	UnitFactor = 1.0f;
5155 	if (lEOpts->GetDisplayUnits() == kKCalPerMole) UnitFactor = kHartreeTokCalPMol;
5156 	long NumFrames = MainData->NumFrames;
5157 	if (!AllFrames) {
5158 		lFrame = MainData->cFrame;
5159 		NumFrames = 1;
5160 	}
5161 	for (long i=0; i<NumFrames; ++i) {
5162 		sprintf(text, "%f", lFrame->time);
5163 		Buffer->PutText(text);
5164 		if (PlotTE) {
5165 			sprintf(text, "\t%f", (lFrame->Energy-lEOpts->GetY1Zero())*UnitFactor);
5166 			Buffer->PutText(text);
5167 		}
5168 		if (PlotMPE) {
5169 			sprintf(text, "\t%f", (lFrame->GetMP2Energy()-lEOpts->GetY1Zero())*UnitFactor);
5170 			Buffer->PutText(text);
5171 		}
5172 		if (PlotKE) {
5173 			sprintf(text, "\t%f", (lFrame->GetKineticEnergy()-lEOpts->GetY2Zero())*UnitFactor);
5174 			Buffer->PutText(text);
5175 		}
5176 		if (PlotPE) {
5177 			sprintf(text, "\t%f", (lFrame->Energy - lFrame->GetKineticEnergy() - lEOpts->GetY1Zero())*UnitFactor);
5178 			Buffer->PutText(text);
5179 		}
5180 		if (lPOpts->PlotRMSGradient()) {
5181 			sprintf(text, "\t%f", (lFrame->GetRMSGradient() - lEOpts->GetY2Zero()));
5182 			Buffer->PutText(text);
5183 		}
5184 		if (lPOpts->PlotMaxGradient()) {
5185 			sprintf(text, "\t%f", (lFrame->GetMaxGradient() - lEOpts->GetY2Zero()));
5186 			Buffer->PutText(text);
5187 		}
5188 		if (lPOpts->PlotBondLength()) {
5189 				float bLength;
5190 			if (lFrame->GetBondLength(a1, a2, &bLength)) {
5191 				sprintf(text, "\t%f", (bLength - lEOpts->GetY2Zero()));
5192 				Buffer->PutText(text);
5193 			} Buffer->PutText("\t");
5194 		}
5195 		if (lPOpts->PlotBondAngle()) {
5196 				float bAngle;
5197 			if (lFrame->GetBondAngle(a1, a2, a3, &bAngle)) {
5198 				sprintf(text, "\t%f", (bAngle - lEOpts->GetY2Zero()));
5199 				Buffer->PutText(text);
5200 			} Buffer->PutText("\t");
5201 		}
5202 		Buffer->WriteLine("", true);
5203 
5204 		lFrame = lFrame->NextFrame;
5205 		if (!lFrame) break;
5206 	}
5207 }
WriteFrequencies(BufferFile * Buffer)5208 void MolDisplayWin::WriteFrequencies(BufferFile * Buffer) {
5209 	char	text[kMaxLineLength];
5210 	Frame * lFrame;
5211 	lFrame = MainData->cFrame;
5212 
5213 	if (!lFrame->Vibs) return;
5214 
5215 	bool haveInten = (lFrame->Vibs->Intensities.size() > 0);
5216 	bool haveRaman = (lFrame->Vibs->RamanIntensity.size() > 0);
5217 
5218 	Buffer->PutText("Frequency\tIntensity");
5219 	if (haveRaman) Buffer->PutText("\tRaman Intensity");
5220 	Buffer->WriteLine("", true);
5221 	for (long i=0; i<lFrame->Vibs->GetNumModes(); ++i) {
5222 		sprintf(text, "%s", lFrame->Vibs->Frequencies[i].c_str());
5223 		Buffer->PutText(text);
5224 		if (haveInten) {
5225 			sprintf(text, "\t%f", lFrame->Vibs->GetIntensity(i));
5226 			Buffer->PutText(text);
5227 		}
5228 		if (haveRaman) {
5229 			sprintf(text, "\t%f", lFrame->Vibs->GetRamanIntensity(i));
5230 			Buffer->PutText(text);
5231 		}
5232 		Buffer->WriteLine("", true);
5233 	}
5234 }
WriteXYZFile(BufferFile * Buffer,bool AllFrames,bool AllModes,bool AnimateMode)5235 void MolDisplayWin::WriteXYZFile(BufferFile * Buffer, bool AllFrames, bool AllModes,
5236 	bool AnimateMode) {
5237 	char	text[kMaxLineLength];
5238 
5239 	Frame * lFrame;
5240 	lFrame = MainData->Frames;
5241 	long NumFrames = MainData->NumFrames;
5242 	if (!AllFrames) {
5243 		lFrame = MainData->cFrame;
5244 		NumFrames = 1;
5245 	}
5246 
5247 	if (AnimateMode) {	//One geometry with all normal modes
5248 		if (!lFrame->Vibs) return;
5249 		mpAtom * lAtoms = lFrame->Atoms;
5250 		long	i, iatm;
5251 		long cmode = (lFrame->NumAtoms)*(lFrame->Vibs->CurrentMode);
5252 		CPoint3D * ModeOffset = new CPoint3D[lFrame->NumAtoms];
5253 		CPoint3D * tempAtoms = new CPoint3D[lFrame->NumAtoms];
5254 		if (!ModeOffset || !tempAtoms) return;
5255 		float	VectorScale = Prefs->GetVectorScale();
5256 		float offsetFactor = 1.0/40.0;
5257 		for (iatm=0; iatm<(lFrame->NumAtoms); ++iatm) {
5258 			tempAtoms[iatm] = lAtoms[iatm].Position;
5259 			ModeOffset[iatm] = lFrame->Vibs->NormMode[iatm+cmode];
5260 			ModeOffset[iatm] *= VectorScale;
5261 		}
5262 		for (i=0; i<20; ++i) {
5263 			if ((i==5)||(i==15)) {
5264 				offsetFactor *= -1.0f;
5265 			}
5266 			for (iatm=0; iatm<(lFrame->NumAtoms); ++iatm) {
5267 				tempAtoms[iatm].x += offsetFactor*(ModeOffset[iatm].x);
5268 				tempAtoms[iatm].y += offsetFactor*(ModeOffset[iatm].y);
5269 				tempAtoms[iatm].z += offsetFactor*(ModeOffset[iatm].z);
5270 			}	//Now punch out the XYZ frame
5271 			sprintf(text, "%ld", lFrame->NumAtoms);
5272 			Buffer->WriteLine(text, true);
5273 			sprintf(text, "Frequency %s Frame %ld",
5274 					lFrame->Vibs->Frequencies[lFrame->Vibs->CurrentMode].c_str(), i+1);
5275 			Buffer->WriteLine(text, true);
5276 			for (long j=0; j<lFrame->NumAtoms; ++j) {
5277 					Str255	Label;
5278 				Prefs->GetAtomLabel(lAtoms[j].Type-1, Label);
5279 				Label[Label[0]+1]=0;
5280 				sprintf(text, "%s %.4f %.4f %.4f", &(Label[1]), tempAtoms[j].x,
5281 					tempAtoms[j].y, tempAtoms[j].z);
5282 				Buffer->PutText(text);
5283 				CPoint3D * lMode = &(lFrame->Vibs->NormMode[(j + cmode)]);
5284 				sprintf(text," %.4f %.4f %.4f", lMode->x, lMode->y, lMode->z);
5285 				Buffer->WriteLine(text, true);
5286 			}
5287 		}
5288 		delete [] tempAtoms;
5289 		delete [] ModeOffset;
5290 	} else if (AllModes) {
5291 		if (!lFrame->Vibs) return;
5292 			mpAtom * lAtoms = lFrame->Atoms;
5293 		for (long i=0; i<lFrame->Vibs->GetNumModes(); ++i) {
5294 			sprintf(text, "%ld", lFrame->NumAtoms);
5295 			Buffer->WriteLine(text, true);
5296 			sprintf(text, "Frequency %s",
5297 					lFrame->Vibs->Frequencies[i].c_str());
5298 			Buffer->WriteLine(text, true);
5299 			for (long j=0; j<lFrame->NumAtoms; ++j) {
5300 					Str255	Label;
5301 				Prefs->GetAtomLabel(lAtoms[j].Type-1, Label);
5302 				Label[Label[0]+1]=0;
5303 				sprintf(text, "%s %.4f %.4f %.4f", &(Label[1]), lAtoms[j].Position.x,
5304 					lAtoms[j].Position.y, lAtoms[j].Position.z);
5305 				Buffer->PutText(text);
5306 				long cmode = (lFrame->NumAtoms)*i;
5307 				CPoint3D * lMode = &(lFrame->Vibs->NormMode[(j + cmode)]);
5308 				sprintf(text," %.4f %.4f %.4f", lMode->x, lMode->y, lMode->z);
5309 				Buffer->WriteLine(text, true);
5310 			}
5311 		}
5312 	} else {
5313 		for (long i=0; i<NumFrames; ++i) {
5314 				mpAtom * lAtoms = lFrame->Atoms;
5315 			sprintf(text, "%ld", lFrame->NumAtoms);
5316 			Buffer->WriteLine(text, true);
5317 			sprintf(text, "Frame %ld", i+1);
5318 			Buffer->WriteLine(text, true);
5319 			for (long j=0; j<lFrame->NumAtoms; ++j) {
5320 					Str255	Label;
5321 				Prefs->GetAtomLabel(lAtoms[j].GetType()-1, Label);
5322 				Label[Label[0]+1]=0;
5323 				sprintf(text, "%s %.4f %.4f %.4f", &(Label[1]), lAtoms[j].Position.x,
5324 					lAtoms[j].Position.y, lAtoms[j].Position.z);
5325 				Buffer->PutText(text);
5326 				if (lFrame->Vibs) {	//There are normal modes with this frame so setup drawing parameters
5327 					if (MainData->GetDrawMode()) {	//Are we supposed to show the normal mode?
5328 						long cmode = (lFrame->NumAtoms)*(lFrame->Vibs->CurrentMode);
5329 						CPoint3D * lMode = &(lFrame->Vibs->NormMode[(j + cmode)]);
5330 						sprintf(text," %.4f %.4f %.4f", lMode->x, lMode->y, lMode->z);
5331 						Buffer->PutText(text);
5332 					}
5333 				}
5334 				Buffer->WriteLine("", true);
5335 			}
5336 			lFrame = lFrame->NextFrame;
5337 			if (!lFrame) break;
5338 		}
5339 	}
5340 }
WriteMDLMolFile(BufferFile * Buffer)5341 void MolDisplayWin::WriteMDLMolFile(BufferFile * Buffer) {
5342 	char Line[kMaxLineLength];
5343 	Frame * lFrame = MainData->GetCurrentFramePtr();
5344 		//The first line is the molecule name so copy out the current description
5345 	if (MainData->Description)
5346 		Buffer->PutText(MainData->Description);
5347 	else if (MainData->InputOptions) {
5348 		const char * temp = MainData->InputOptions->Data->GetTitle();
5349 		if (temp) {
5350 			Buffer->PutText(temp);
5351 		}
5352 	}
5353 	Buffer->WriteLine("", true);
5354 		//2nd line may contain various program data
5355 	Buffer->PutText("  MacMolPlt                       ");
5356 	if (lFrame->Energy != 0.0) {
5357 		sprintf(Line, "%12.5f", lFrame->Energy);
5358 		Buffer->PutText(Line);
5359 	}
5360 	Buffer->WriteLine("", true);	//finish off 2nd line and leave 3rd line blank
5361 	Buffer->WriteLine("", true);
5362 	sprintf(Line, "%3ld%3ld  0  0  0  0  0  0  0  0  0 v2000",
5363 		lFrame->GetNumAtoms(), lFrame->GetNumBonds());
5364 	Buffer->WriteLine(Line, true);
5365 		mpAtom * lAtoms = lFrame->Atoms;
5366 		long i;
5367 	for (i=0; i<lFrame->GetNumAtoms(); ++i) {
5368 			Str255	Label;
5369 		Prefs->GetAtomLabel(lAtoms[i].GetType()-1, Label);
5370 		Label[Label[0]+1]=0;
5371 		sprintf(Line, "%10.4f%10.4f%10.4f %-3s 0  0  0  0  0  0  0  0  0  0  0  0",
5372 			lAtoms[i].Position.x, lAtoms[i].Position.y,
5373 			lAtoms[i].Position.z, &(Label[1]));
5374 		Buffer->WriteLine(Line, true);
5375 	}
5376 	if (lFrame->GetNumBonds() > 0) {
5377 		Bond * lBonds = lFrame->Bonds;
5378 		for (i=0; i<lFrame->GetNumBonds(); ++i) {
5379 			int	type = lBonds[i].Order;
5380 			if (type>3 || type<=0) type = 1;
5381 			sprintf(Line, "%3ld%3ld%3d  0  0  0  0", lBonds[i].Atom1+1,
5382 				lBonds[i].Atom2+1, type);
5383 			Buffer->WriteLine(Line, true);
5384 		}
5385 	}
5386 		//Final line needs to be end line to terminate properties block
5387 	Buffer->WriteLine("M  END", true);
5388 }
5389 
WriteVRMLFile(BufferFile * Buffer)5390 void MolDisplayWin::WriteVRMLFile(BufferFile * Buffer) {
5391 	Buffer->PutText("#VRML V2.0 utf8\n");  //VRML header
5392 	Buffer->PutText("\n");
5393 
5394 	Frame * lFrame = MainData->GetCurrentFramePtr();
5395 	mpAtom * lAtoms = lFrame->Atoms;
5396 
5397 	//drawing atoms
5398 
5399 	long NumAtoms = lFrame->NumAtoms;
5400 	float AtomScale = Prefs->GetAtomScale();
5401 	long curAtomType;
5402 	RGBColor * AtomColor;
5403 	wxString tmpStr;
5404 	float red, green, blue;
5405 
5406 	for (long iatom=0; iatom<NumAtoms; ++iatom) {
5407 		if (lAtoms[iatom].GetInvisibility()) continue;
5408 
5409 		curAtomType = lAtoms[iatom].GetType() - 1;
5410 		AtomColor = Prefs->GetAtomColorLoc(curAtomType);
5411 		red = AtomColor->red/65536.0;
5412 		green = AtomColor->green/65536.0;
5413 		blue = AtomColor->blue/65536.0;
5414 
5415 		float radius = AtomScale*Prefs->GetAtomSize(curAtomType);
5416 		Buffer->PutText("Transform {\n");
5417 		tmpStr.Printf(wxT("\ttranslation %f %f %f\n"), lAtoms[iatom].Position.x,
5418 					  lAtoms[iatom].Position.y, lAtoms[iatom].Position.z);
5419 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5420 		Buffer->PutText("\tchildren [\n");
5421 		Buffer->PutText("\t\tShape {\n");
5422 		tmpStr.Printf(wxT("\t\t\tgeometry Sphere { radius %f }\n"), radius);
5423 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5424 		Buffer->PutText("\t\t\tappearance Appearance {\n");
5425 		tmpStr.Printf(wxT("\t\t\t\tmaterial Material { diffuseColor %f %f %f }\n"),
5426 					  red, green, blue);
5427 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5428 		Buffer->PutText("\t\t\t}\n");
5429 		Buffer->PutText("\t\t}\n");
5430 		Buffer->PutText("\t]\n");
5431 		Buffer->PutText("}\n");
5432 	}
5433 
5434 	//drawing bonds
5435 	Bond * lBonds = lFrame->Bonds;
5436 	long NumBonds = lFrame->NumBonds;
5437 	double BondSize = Prefs->GetQD3DBondWidth();
5438 	//float dotProd;
5439 	Matrix4D rotMat;
5440 	CPoint3D NormalOffset, NormStart = CPoint3D(0.0f, 1.0f, 0.0f);
5441 	double theta;
5442 	double axisX, axisY, axisZ;
5443 
5444 	for (long ibond=0; ibond<NumBonds; ++ibond) {
5445 		CPoint3D v1, v2, offset;
5446 		long atom1 = lBonds[ibond].Atom1;
5447 		long atom2 = lBonds[ibond].Atom2;
5448 		//BondOrder tmpOrder = lBonds[ibond].Order;
5449 
5450 		//for (int ipipe = 0; ipipe < MAX(tmpOrder,1); ++ipipe) {
5451 
5452 		v1.x = lAtoms[atom1].Position.x; // + offset_vec.x * baseBondOffset +
5453 		//3.5 * tmpBondSize * offset_vec.x * ipipe;
5454 		v1.y = lAtoms[atom1].Position.y; //+ offset_vec.y * baseBondOffset +
5455 		//3.5 * tmpBondSize * offset_vec.y * ipipe;
5456 		v1.z = lAtoms[atom1].Position.z; //+ offset_vec.z * baseBondOffset +
5457 		//3.5 * tmpBondSize * offset_vec.z * ipipe;
5458 		v2.x = lAtoms[atom2].Position.x; //+ offset_vec.x * baseBondOffset +
5459 		//3.5 * tmpBondSize * offset_vec.x * ipipe;
5460 		v2.y = lAtoms[atom2].Position.y; //+ offset_vec.y * baseBondOffset +
5461 		//3.5 * tmpBondSize * offset_vec.y * ipipe;
5462 		v2.z = lAtoms[atom2].Position.z; //+ offset_vec.z * baseBondOffset +
5463 		//3.5 * tmpBondSize * offset_vec.z * ipipe;
5464 
5465 		offset.x = v2.x - v1.x;
5466 		offset.y = v2.y - v1.y;
5467 		offset.z = v2.z - v1.z;
5468 
5469 		double length = offset.Magnitude();
5470 		double radius1 = AtomScale*Prefs->GetAtomSize(lAtoms[atom1].GetType() - 1);
5471 		double radius2 = AtomScale*Prefs->GetAtomSize(lAtoms[atom2].GetType() - 1);
5472 		double percent1 = radius1/length;
5473 		double percent2 = radius2/length;
5474 		double centerPercent = 0.5 + 0.5*(percent1-percent2);
5475 
5476 		if (length>0.00001) {
5477 			NormalOffset.x = offset.x/length;
5478 			NormalOffset.y = offset.y/length;
5479 			NormalOffset.z = offset.z/length;
5480 		} else {
5481 			NormalOffset.x=NormalOffset.y=NormalOffset.z=0.0f;
5482 		}
5483 
5484 		SetRotationMatrix(rotMat, &NormStart, &NormalOffset);
5485 
5486 		double tmp1 = rotMat[2][1]-rotMat[1][2];
5487 		double tmp2 = rotMat[0][2]-rotMat[2][0];
5488 		double tmp3 = rotMat[1][0]-rotMat[0][1];
5489 		double dev = sqrt(tmp1*tmp1+tmp2*tmp2+tmp3*tmp3);
5490 		theta = -1 * acos((rotMat[0][0] + rotMat[1][1] + rotMat[2][2] - 1)/2);
5491 
5492 		if (fabs(dev) > 0.0000001 ) {
5493 			axisX = (rotMat[2][1] - rotMat[1][2]) / dev;
5494 			axisY = (rotMat[0][2] - rotMat[2][0]) / dev;
5495 			axisZ = (rotMat[1][0] - rotMat[0][1]) / dev;
5496 		}
5497 
5498 		CPoint3D v3; //first half bond from atom 1
5499 		v3.x = centerPercent*(v2.x - v1.x)+v1.x;
5500 		v3.y = centerPercent*(v2.y - v1.y)+v1.y;
5501 		v3.z = centerPercent*(v2.z - v1.z)+v1.z;
5502 
5503 		curAtomType = lAtoms[atom1].GetType() - 1;
5504 		AtomColor = Prefs->GetAtomColorLoc(curAtomType);
5505 		red = AtomColor->red/65536.0;
5506 		green = AtomColor->green/65536.0;
5507 		blue = AtomColor->blue/65536.0;
5508 
5509 		Buffer->PutText("Transform {\n");
5510 
5511 		if (fabs(dev) > 0.000001) {
5512 			tmpStr.Printf(wxT("\trotation %lf %lf %lf %lf\n"), axisX, axisY, axisZ, theta);
5513 			Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5514 		}
5515 		tmpStr.Printf(wxT("\ttranslation %lf %lf %lf\n"), (v1.x+v3.x)/2, (v1.y+v3.y)/2, (v1.z+v3.z)/2);
5516 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5517 		Buffer->PutText("\tchildren [\n");
5518 		Buffer->PutText("\t\tShape {\n");
5519 		tmpStr.Printf(wxT("\t\t\tgeometry Cylinder { radius %lf height %lf}\n"), BondSize, (centerPercent)*length);
5520 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5521 		Buffer->PutText("\t\t\tappearance Appearance {\n");
5522 		tmpStr.Printf(wxT("\t\t\t\tmaterial Material { diffuseColor %f %f %f }\n"),
5523 					  red, green, blue);
5524 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5525 		Buffer->PutText("\t\t\t}\n");
5526 		Buffer->PutText("\t\t}\n");
5527 		Buffer->PutText("\t]\n");
5528 		Buffer->PutText("}\n");
5529 
5530 		curAtomType = lAtoms[atom2].GetType() - 1;
5531 		AtomColor = Prefs->GetAtomColorLoc(curAtomType);
5532 		red = AtomColor->red/65536.0;
5533 		green = AtomColor->green/65536.0;
5534 		blue = AtomColor->blue/65536.0;
5535 
5536 		Buffer->PutText("Transform {\n");
5537 
5538 		if (fabs(dev) > 0.000001) {
5539 			tmpStr.Printf(wxT("\trotation %lf %lf %lf %lf\n"), axisX, axisY, axisZ, theta);
5540 			Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5541 		}
5542 		tmpStr.Printf(wxT("\ttranslation %lf %lf %lf\n"), (v2.x+v3.x)/2, (v2.y+v3.y)/2, (v2.z+v3.z)/2);
5543 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5544 		Buffer->PutText("\tchildren [\n");
5545 		Buffer->PutText("\t\tShape {\n");
5546 		tmpStr.Printf(wxT("\t\t\tgeometry Cylinder { radius %lf height %lf}\n"), BondSize, (1-centerPercent)*length);
5547 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5548 		Buffer->PutText("\t\t\tappearance Appearance {\n");
5549 		tmpStr.Printf(wxT("\t\t\t\tmaterial Material { diffuseColor %f %f %f }\n"),
5550 					  red, green, blue);
5551 		Buffer->PutText(tmpStr.mb_str(wxConvUTF8));
5552 		Buffer->PutText("\t\t\t}\n");
5553 		Buffer->PutText("\t\t}\n");
5554 		Buffer->PutText("\t]\n");
5555 		Buffer->PutText("}\n");
5556 	}
5557 }
5558 
WritePOVFile(BufferFile * Buffer)5559 void MolDisplayWin::WritePOVFile(BufferFile *Buffer) {
5560 
5561 	MainData->ExportPOV(Buffer, Prefs);
5562 
5563 }
5564 
ReadGrid(const bool Square,const bool UseMult,const double & MultValue)5565 void General2DSurface::ReadGrid(const bool Square, const bool UseMult, const double & MultValue) {
5566     wxString filename = wxFileSelector(wxT("Choose a file containing the surface data."));
5567     //We are looking for $ VEC groups. Scan to see how many are there. If more than 1 the user will
5568     //have to choose.
5569 	FILE * myfile = NULL;
5570     if (!filename.empty()) {
5571         myfile = fopen(filename.mb_str(wxConvUTF8), "rb");
5572         if (myfile == NULL) {
5573             MessageAlert("Unable to open the selected file!");
5574 			return;
5575         }
5576 	} else
5577 		return;
5578 	bool FirstFile = (Grid == NULL);
5579 
5580 //Ok got a file, create a buffer for it and then attempt to read it in
5581 	if (FirstFile) {
5582 		if (Label) {delete [] Label; Label = NULL;}
5583 		FreeGrid();
5584 	}
5585 
5586 	BufferFile * Buffer = NULL;
5587 
5588 	bool	success = false;
5589 	long	LineLength, LinePos;
5590 	short	scanerr;
5591 	CPoint3D	tempPt;
5592 	try {
5593 			char Line[kMaxLineLength];
5594 		Buffer = new BufferFile(myfile, false);
5595 		Buffer->GetLine(Line);
5596 		if (FirstFile) SetLabel(Line);
5597 		Buffer->GetLine(Line);
5598 		scanerr = sscanf(Line, "%ld", &LinePos);
5599 		if ((scanerr != 1)||(LinePos<=0)) {
5600 			wxLogMessage(_("The second line must contain the # of grid points."));
5601 			throw DataError();
5602 		}
5603 		if (FirstFile) NumGridPoints = LinePos;
5604 		else if (LinePos != NumGridPoints) {
5605 			wxLogMessage(_("The number of grid points does not match the existing grid!"));
5606 			throw DataError();
5607 		}
5608 		Buffer->GetLine(Line);
5609 		scanerr = sscanf(Line, "%f%f%f", &(tempPt.x), &(tempPt.y), &(tempPt.z));
5610 		if (scanerr != 3) {
5611 			wxLogMessage(_("Could not parse the x, y, and z values for the origin of the 3D grid."));
5612 			throw DataError();
5613 		}
5614 		if (FirstFile) Origin = tempPt;
5615 		else if ((fabs(tempPt.x) < fabs(100*(tempPt.x-Origin.x)))||
5616 				(fabs(tempPt.y) < fabs(100*(tempPt.y-Origin.y)))||
5617 				 (fabs(tempPt.z) < fabs(100*(tempPt.z-Origin.z)))) {
5618 					wxLogMessage(_("The origin of the file grid does not match the current origin!"));
5619 					throw DataError();
5620 		}
5621 		Buffer->GetLine(Line);
5622 		scanerr = sscanf(Line, "%f%f%f", &(tempPt.x), &(tempPt.y), &(tempPt.z));
5623 		if (scanerr != 3) {
5624 			wxLogMessage(_("The fourth line must contain a 3D vector indicating the increment along the first side of the grid."));
5625 			throw DataError();
5626 		}
5627 		if (FirstFile) XInc = tempPt;
5628 		else if ((fabs(tempPt.x) < fabs(100*(tempPt.x-XInc.x)))||
5629 				(fabs(tempPt.y) < fabs(100*(tempPt.y-XInc.y)))||
5630 				 (fabs(tempPt.z) < fabs(100*(tempPt.z-XInc.z)))) {
5631 					wxLogMessage(_("The first increment vector does not match the current grid!"));
5632 					throw DataError();
5633 		}
5634 		Buffer->GetLine(Line);
5635 		scanerr = sscanf(Line, "%f%f%f", &(tempPt.x), &(tempPt.y), &(tempPt.z));
5636 		if (scanerr != 3) {
5637 			wxLogMessage(_("The fifth line must contain a 3D vector indicating the increment along the second grid direction."));
5638 			throw DataError();
5639 		}
5640 		if (FirstFile) YInc = tempPt;
5641 		else if ((fabs(tempPt.x) < fabs(100*(tempPt.x-YInc.x)))||
5642 				(fabs(tempPt.y) < fabs(100*(tempPt.y-YInc.y)))||
5643 				 (fabs(tempPt.z) < fabs(100*(tempPt.z-YInc.z)))) {
5644 					wxLogMessage(_("The second increment vector does not match the current grid!"));
5645 					throw DataError();
5646 		}
5647 			//allocate memory for the grid
5648 		long TotalPoints = NumGridPoints*NumGridPoints;
5649 		if (FirstFile) {
5650 			AllocateGrid(TotalPoints);
5651 		}
5652 		if (!Grid) throw MemoryError();
5653 		float * lGrid;
5654 		lGrid = Grid;
5655 		if (FirstFile) for (LinePos=0; LinePos<TotalPoints; ++LinePos)
5656 			lGrid[LinePos] = 0.0;
5657 		Buffer->GetLine(Line);
5658 		LinePos = 0;
5659 		LineLength = strlen(Line);
5660 		long n=0;
5661 		float tempF;
5662 		GridMax = -1.0e20;	//init the Grid max to a value sure to be changed later
5663 		GridMin = 1.0e20;
5664 		while (n<TotalPoints) {
5665 			if (LinePos>=LineLength) {
5666 				Buffer->GetLine(Line);
5667 				LinePos = 0;
5668 				LineLength = strlen(Line);
5669 			}
5670 				int nchar;
5671 			scanerr = sscanf(&(Line[LinePos]), "%f%n", &tempF, &nchar);
5672 			if (scanerr != 1) {
5673 				Buffer->GetLine(Line);
5674 				LinePos = 0;
5675 				LineLength = strlen(Line);
5676 				scanerr = sscanf(&(Line[LinePos]), "%f%n", &tempF, &nchar);
5677 			}
5678 			if (Square) tempF *= tempF;
5679 			if (UseMult) tempF *= MultValue;
5680 			lGrid[n] += tempF;
5681 			GridMax = MAX(GridMax, lGrid[n]);
5682 			GridMin = MIN(GridMin, lGrid[n]);
5683 			LinePos += nchar;
5684 			++n;
5685 		}
5686 
5687 		success = true;
5688 	}
5689 	catch (DataError /*Error*/) {}
5690 	catch (FileError Error) { Error.WriteError();}
5691 	catch (...) {
5692 		success = false;
5693 	}
5694 	if (!success && FirstFile) {	//invalid data or out of memory, etc
5695 		if (Label) {delete [] Label; Label = NULL;}
5696 		FreeGrid();
5697 	}
5698 	if (Buffer) delete Buffer;
5699 	fclose(myfile);
5700 }
ReadGrid(const bool Square,const bool UseValue,const double & MultValue)5701 void General3DSurface::ReadGrid(const bool Square, const bool UseValue, const double & MultValue) {
5702 	//First prompt the user for the file
5703     wxString filename = wxFileSelector(wxT("Choose a file containing the surface data."));
5704 	FILE * myfile = NULL;
5705     if (!filename.empty()) {
5706         myfile = fopen(filename.mb_str(wxConvUTF8), "rb");
5707         if (myfile == NULL) {
5708             MessageAlert("Unable to open the selected file!");
5709 			return;
5710         }
5711 	} else
5712 		return;
5713 
5714 	bool FirstFile = (Grid == NULL);
5715 
5716 //Ok got a file, create a buffer for it and then attempt to read it in
5717 	if (FirstFile) {	//shouldn't have old data if the first file...
5718 		if (Label) {delete [] Label; Label = NULL;}
5719 		if (Grid) FreeGrid();
5720 		if (ContourHndl) FreeContour();
5721 	}
5722 
5723 	BufferFile * Buffer = NULL;
5724 
5725 	bool	success = false;
5726 	long	LineLength, LinePos, tempL;
5727 	CPoint3D	tempPt;
5728 	short	scanerr;
5729 	try {
5730 			char Line[kMaxLineLength];
5731 		Buffer = new BufferFile(myfile, false);
5732 		Buffer->GetLine(Line);
5733 		if (FirstFile) SetLabel(Line);	//grab the label only if this is the first data file
5734 
5735 		Buffer->GetLine(Line);
5736 		scanerr = sscanf(Line, "%ld%ld%ld", &LineLength, &LinePos, &tempL);
5737 		if ((scanerr != 3)||(LineLength<=0)||(LinePos<=0)||(tempL<=0)) {
5738 			wxLogMessage(_("The second line must contain the # of x, y, and z grid points."));
5739 			throw DataError();
5740 		}
5741 		if (FirstFile) {
5742 			NumXGridPoints = LineLength;
5743 			NumYGridPoints = LinePos;
5744 			NumZGridPoints = tempL;
5745 		} else if ((NumXGridPoints!=LineLength)||(NumYGridPoints!=LinePos)||
5746 				   (NumZGridPoints!=tempL)) {
5747 			wxLogMessage(_("The number of grid points does not match the existing grid!"));
5748 			throw DataError();
5749 		}
5750 
5751 		Buffer->GetLine(Line);
5752 		scanerr = sscanf(Line, "%f%f%f", &(tempPt.x), &(tempPt.y), &(tempPt.z));
5753 		if (scanerr != 3) {
5754 			wxLogMessage(_("Could not parse the x, y, and z values for the origin of the 3D grid."));
5755 			throw DataError();
5756 		}
5757 		if (FirstFile) Origin = tempPt;
5758 		else if ((fabs(tempPt.x) < fabs(100*(tempPt.x-Origin.x)))||
5759 				(fabs(tempPt.y) < fabs(100*(tempPt.y-Origin.y)))||
5760 				 (fabs(tempPt.z) < fabs(100*(tempPt.z-Origin.z)))) {
5761 					wxLogMessage(_("The origin of the file grid does not match the current origin!"));
5762 					throw DataError();
5763 		}
5764 
5765 		Buffer->GetLine(Line);
5766 		scanerr = sscanf(Line, "%f%f%f", &(tempPt.x), &(tempPt.y), &(tempPt.z));
5767 		if (scanerr != 3) {
5768 			wxLogMessage(_("Could not parse the x, y, and z increment values from the fourth line."));
5769 			throw DataError();
5770 		}
5771 		if (FirstFile) {
5772 			XGridInc = tempPt.x;
5773 			YGridInc = tempPt.y;
5774 			ZGridInc = tempPt.z;
5775 		} else if ((fabs(tempPt.x) < fabs(100*(tempPt.x-XGridInc)))||
5776 				(fabs(tempPt.y) < fabs(100*(tempPt.y-YGridInc)))||
5777 				   (fabs(tempPt.z) < fabs(100*(tempPt.z-ZGridInc)))) {
5778 					wxLogMessage(_("The x, y, and z grid increments must match those of the existing grid."));
5779 					throw DataError();
5780 		}
5781 			//allocate memory for the grid (if needed)
5782 		long TotalPoints = NumXGridPoints*NumYGridPoints*NumZGridPoints;
5783 		if (FirstFile) AllocateGrid(TotalPoints);
5784 		if (!Grid) throw MemoryError();
5785 			float * lGrid;
5786 		lGrid = Grid;
5787 		if (FirstFile) for (LinePos=0; LinePos<TotalPoints; ++LinePos)
5788 			lGrid[LinePos] = 0.0;
5789 		Buffer->GetLine(Line);
5790 		LinePos = 0;
5791 		LineLength = strlen(Line);
5792 		long n=0;
5793 		float tempF;
5794 		GridMax = -1.0e20;	//init the Grid max to a value sure to be changed later
5795 		GridMin = 1.0e20;
5796 		while (n<TotalPoints) {
5797 			if (LinePos>=LineLength) {
5798 				Buffer->GetLine(Line);
5799 				LinePos = 0;
5800 				LineLength = strlen(Line);
5801 			}
5802 				int nchar;
5803 			scanerr = sscanf(&(Line[LinePos]), "%f%n", &tempF, &nchar);
5804 			if (scanerr != 1) {
5805 				Buffer->GetLine(Line);
5806 				LinePos = 0;
5807 				LineLength = strlen(Line);
5808 				scanerr = sscanf(&(Line[LinePos]), "%f%n", &tempF, &nchar);
5809 			}
5810 			if (Square) tempF *= tempF;
5811 			if (UseValue) tempF *= MultValue;
5812 			lGrid[n] += tempF;
5813 			GridMax = MAX(GridMax, lGrid[n]);
5814 			GridMin = MIN(GridMin, lGrid[n]);
5815 			LinePos += nchar;
5816 			++n;
5817 		}
5818 
5819 		success = true;
5820 	}
5821 	catch (DataError /*Error*/) {}
5822 	catch (FileError Error) { Error.WriteError();}
5823 	catch (...) {
5824 		success = false;
5825 	}
5826 	if (!success && FirstFile) {	//invalid data or out of memory, etc
5827 		if (Label) {delete [] Label; Label = NULL;}
5828 		if (Grid) FreeGrid();
5829 	}
5830 	if (Buffer) delete Buffer;
5831 	fclose(myfile);
5832 }
LocateKeyWord(const char * Buffer,const char * KeyWord,long length,long bytecount)5833 long LocateKeyWord(const char *Buffer, const char * KeyWord, long length, long bytecount)
5834 {	long	test=0, pos=-1;
5835 
5836 	while (!test) {
5837 		for (pos++; ((toupper(Buffer[pos]) != toupper(KeyWord[0]))||
5838 					 (toupper(Buffer[pos+1]) != toupper(KeyWord[1])))&&(pos<bytecount)&&
5839 			 (Buffer[pos]!='\0'); pos++) ;
5840 		if (pos>=bytecount) return -1;
5841 		if (Buffer[pos]=='\0') return -1;
5842 		test = 2;
5843 		while ((toupper(Buffer[pos+test]) == toupper(KeyWord[test]))&&(test<length)&&
5844 			   ((pos+test)<bytecount)) test++;
5845 		test = (long) test==length;
5846 	}
5847 	return pos;
5848 }	/*LocateKeyWord*/
5849 /* ParseGLogLine converts the various cartesian coordinate formats in
5850 	GAMESS output files to my internal binary coordinate array. Type's
5851 	less than ten mean coordinates are in Bohr and thus need conversion,
5852 	greater than ten means they are already in Angstroms. */
ParseGLogLine(BufferFile * Buffer,Frame * lFrame,long numExpected,long Type,float * maxsize)5853 long ParseGLogLine(BufferFile * Buffer, Frame * lFrame, long numExpected, long Type, float *maxsize)
5854 {	long	LinePos=0, iscanerr=0, iatm;
5855 	float	temp;
5856 	char	LineText[kMaxLineLength+1];
5857 	CPoint3D	Position;
5858 
5859 	for (iatm=0; iatm<numExpected; ++iatm) {
5860 		Buffer->GetLine(LineText);
5861 		switch (Type) {
5862 			case 0:	//Standard Coordinates at the top of the log file
5863 			case 10: // IRC Log file format (same as above but in angstroms)
5864 					//1/1998 changed standard log format to 10
5865 				LinePos = 11;	//Skip the name and space before the nuclear charge
5866 			break;
5867 			case 1: //format used during geometry optimizations
5868 				LinePos = 15;	//skip # and name before the nuclear charge
5869 			break;
5870 			case 2: //DRC irc and log file format, atom labels are missing
5871 				LinePos = 1;
5872 			break;
5873 			default:
5874 				LinePos = 0;
5875 		}
5876 		iscanerr = sscanf(&(LineText[LinePos]), "%f%f%f%f", &temp, &Position.x,
5877 			&Position.y, &Position.z);
5878 		if (iscanerr == 4) {	/*Convert the coordinates to Angstroms*/
5879 			if (Type < 10) {
5880 				Position.x *= kBohr2AngConversion;
5881 				Position.y *= kBohr2AngConversion;
5882 				Position.z *= kBohr2AngConversion;
5883 			}
5884 			*maxsize = MAX(*maxsize, Position.x);
5885 			*maxsize = MAX(*maxsize, Position.y);
5886 			*maxsize = MAX(*maxsize, Position.z);
5887 			if (temp == 0) temp = 115;
5888 			lFrame->AddAtom((long) temp, Position);
5889 		} else break;
5890 	}
5891 	return iatm;
5892 } /*ParseGLogLine*/
ParseCartLine(char * Line,long * atomtype,CPoint3D * coord,CPoint3D * offset,long Mode)5893 long ParseCartLine(char *Line, long *atomtype, CPoint3D *coord, CPoint3D *offset, long Mode)
5894 {	long	iscanerr=0, junk;
5895 	unsigned char Label[kMaxLineLength]="\0";
5896 
5897 	if (!sscanf(Line, "%s", Label)) return -1;
5898 	if ((Label[0] > 47)&&(Label[0] < 58)) {	/*A number? must be Gaussian style (bleah)*/
5899 			float arg6;
5900 		iscanerr = sscanf(Line, "%ld%ld%f%f%f%f",&junk, atomtype, &(coord->x),
5901 			&(coord->y), &(coord->z), &arg6);
5902 			//G98 adds an integer column for the 'atomic type' which is normally 0???
5903 		if (iscanerr == 6) {
5904 			coord->x = coord->y;
5905 			coord->y = coord->z;
5906 			coord->z = arg6;
5907 		}
5908 		if ((*atomtype>130)||(*atomtype<1))	//bad atom type: assume whole line is garbage
5909 			return -1;
5910 		if ((iscanerr != 5)&&(iscanerr != 6)) return -iscanerr;
5911 	} else {
5912 		float	tempx, tempy, tempz;
5913 
5914 		iscanerr = sscanf(Line, "%s%f%f%f%f%f%f", Label, &(coord->x),
5915 			&(coord->y), &(coord->z), &tempx, &tempy, &tempz);
5916 
5917 		if (iscanerr == 7) {
5918 			*atomtype = SetAtomType(Label);
5919 			if (*atomtype == 116) {
5920 				offset->x = tempx*kDebyeToAU;	/*convert the units from Debye to AU for better viewing*/
5921 				offset->y = tempy*kDebyeToAU;
5922 				offset->z = tempz*kDebyeToAU;
5923 			} else if (*atomtype == 117) {
5924 				coord->x *= kBohr2AngConversion;
5925 				coord->y *= kBohr2AngConversion;
5926 				coord->z *= kBohr2AngConversion;
5927 				offset->x = tempx*kDebyeToAU;	/*convert the units from Debye to AU for better viewing*/
5928 				offset->y = tempy*kDebyeToAU;
5929 				offset->z = tempz*kDebyeToAU;
5930 				*atomtype = 116;
5931 			} else if (Mode==-1) {	// Normal mode is not mass-weighted here!
5932 				offset->x = tempx;
5933 				offset->y = tempy;
5934 				offset->z = tempz;
5935 			}
5936 		} else {
5937 			if (iscanerr == 5) {	/*looks like GAMESS unit=bohr format --  label  Atomic_num  x, y, z*/
5938 				*atomtype = (long) coord->x;
5939 				coord->x = coord->y;
5940 				coord->y = coord->z;
5941 				coord->z = tempx;
5942 			} else if (iscanerr == 4) {
5943 					//Check for Fragment coords - I "think" a fragment is ZLabel#
5944 				if (Label[0] == 'Z' || Label[0] == 'z') {
5945 					if ((Label[2]!=0)||((Label[1]!='R')&&(Label[1]!='r')&&
5946 						(Label[1]!='N')&&(Label[1]!='n'))) {
5947 						Label[0] = Label[1];
5948 						Label[1] = 0;
5949 					}
5950 				}
5951 				*atomtype = SetAtomType(Label);
5952 			} else return iscanerr;	//return the error code
5953 		}
5954 	}
5955 	return iscanerr;
5956 } /*ParseCartLine*/
SetAtomType(const unsigned char * TestLabel)5957 long SetAtomType(const unsigned char *TestLabel) {
5958 	char	label[2];
5959 	long result = -1;
5960 
5961 	label[0] = TestLabel[0];	label[1]=TestLabel[1];
5962 	if ((label[0]>96)&&(label[0]<123)) label[0] = label[0] - 32;	/* Make the first character upper case */
5963 	if ((label[1]>64)&&(label[1]<91)) label[1] = label[1] + 32;		/* and the second character lower case */
5964 	if ((label[1]<'a')||(label[1]>'z')) label[1] = ' ';	//Not a letter!
5965 	switch (label[0]) {
5966 		case 'H':
5967 			switch (label[1]) {
5968 				case 'e':			/* Helium */
5969 					result = 2;
5970 					break;
5971 				case 'o':			/* Holmium */
5972 					result = 67;
5973 					break;
5974 				case 'f':			/* Hafnium */
5975 					result = 72;
5976 					break;
5977 				case 'g':			/* Mercury */
5978 					result = 80;
5979 					break;
5980 				case 's':
5981 					result = 108;
5982 					break;
5983 				default:			/* Hydrogen */
5984 					result = 1;
5985 					break;
5986 			}
5987 			break;
5988 		case 'L':
5989 			switch (label[1]) {
5990 				case 'i':			/* Lithium */
5991 					result = 3;
5992 					break;
5993 				case 'a':			/* Lathanum */
5994 					result = 57;
5995 					break;
5996 				case 'u':			/* Lutetium */
5997 					result = 71;
5998 					break;
5999 				case 'r':			/* Lawrencium */
6000 					result = 103;
6001 					break;
6002 				case 'v':			/* Livermorium */
6003 					result = 116;
6004 					break;
6005 			}
6006 			break;
6007 		case 'B':
6008 			switch (label[1]) {
6009 				case 'e':			/* Beryllium */
6010 					result = 4;
6011 					break;
6012 				case 'r':			/* Bromine */
6013 					result = 35;
6014 					break;
6015 				case 'a':			/* Barium */
6016 					result = 56;
6017 					break;
6018 				case 'i':			/* Bismuth */
6019 					result = 83;
6020 					break;
6021 				case 'k':			/* Berkelium */
6022 					result = 97;
6023 					break;
6024 				case 'h':			//Bh
6025 					result = 107;
6026 					break;
6027 				default:			/* Boron */
6028 					result = 5;
6029 					break;
6030 			}
6031 			break;
6032 		case 'C':
6033 			switch (label[1]) {
6034 				case 'l':			/* Chlorine */
6035 					result = 17;
6036 					break;
6037 				case 'a':			/* Calcium */
6038 					result = 20;
6039 					break;
6040 				case 'r':			/* Chromium */
6041 					result = 24;
6042 					break;
6043 				case 'o':			/* Cobalt */
6044 					result = 27;
6045 					break;
6046 				case 'u':			/* Copper */
6047 					result = 29;
6048 					break;
6049 				case 'd':			/* Cadmium */
6050 					result = 48;
6051 					break;
6052 				case 's':			/* Cesium */
6053 					result = 55;
6054 					break;
6055 				case 'e':			/* Cerium */
6056 					result = 58;
6057 					break;
6058 				case 'm':			/* Curium */
6059 					result = 96;
6060 					break;
6061 				case 'f':			/* Californium */
6062 					result = 98;
6063 					break;
6064 				case 'n':			/* Copernicium */
6065 					result = 112;
6066 					break;
6067 				default:			/* Carbon */
6068 					result = 6;
6069 					break;
6070 			}
6071 			break;
6072 		case 'N':
6073 			switch (label[1]) {
6074 				case 'e':			/* Neon */
6075 					result = 10;
6076 					break;
6077 				case 'a':			/* Sodium */
6078 					result = 11;
6079 					break;
6080 				case 'i':			/* Nickel */
6081 					result = 28;
6082 					break;
6083 				case 'b':			/* Niobium */
6084 					result = 41;
6085 					break;
6086 				case 'd':			/* Neodymium */
6087 					result = 60;
6088 					break;
6089 				case 'p':			/* Neptunium */
6090 					result = 93;
6091 					break;
6092 				case 'o':			/* Nobelium */
6093 					result = 102;
6094 					break;
6095 				default:			/* Nitrogen */
6096 					result = 7;
6097 					break;
6098 			}
6099 			break;
6100 		case 'O':
6101 			switch (label[1]) {
6102 				case 's':			/* Osmium */
6103 					result = 76;
6104 					break;
6105 				default:			/* Oxygen */
6106 					result = 8;
6107 					break;
6108 			}
6109 			break;
6110 		case 'F':
6111 			switch (label[1]) {
6112 				case 'e':			/* Iron */
6113 					result = 26;
6114 					break;
6115 				case 'r':			/* Francium */
6116 					result = 87;
6117 					break;
6118 				case 'm':			/* Fermium */
6119 					result = 100;
6120 					break;
6121 				case 'l':			/* Flerovium */
6122 					result = 114;
6123 					break;
6124 				default:			/* Fluorine */
6125 					result = 9;
6126 					break;
6127 			}
6128 			break;
6129 		case 'M':
6130 			switch (label[1]) {
6131 				case 'g':			/* Magnesium */
6132 					result = 12;
6133 					break;
6134 				case 'n':			/* Manganese */
6135 					result = 25;
6136 					break;
6137 				case 'o':			/* Molybdenum */
6138 					result = 42;
6139 					break;
6140 				case 'd':			/* Mendelevium */
6141 					result = 101;
6142 					break;
6143 				case 't':
6144 					result = 109;
6145 					break;
6146 			}
6147 			break;
6148 		case 'A':
6149 			switch (label[1]) {
6150 				case 'l':			/* Aluminum */
6151 					result = 13;
6152 					break;
6153 				case 'r':			/* Argon */
6154 					result = 18;
6155 					break;
6156 				case 's':			/* Arsenic */
6157 					result = 33;
6158 					break;
6159 				case 'g':			/* Silver */
6160 					result = 47;
6161 					break;
6162 				case 'u':			/* Gold */
6163 					result = 79;
6164 					break;
6165 				case 't':			/* Astatine */
6166 					result = 85;
6167 					break;
6168 				case 'c':			/* Actinium */
6169 					result = 89;
6170 					break;
6171 				case 'm':			/* Americium */
6172 					result = 95;
6173 					break;
6174 			}
6175 			break;
6176 		case 'S':
6177 			switch (label[1]) {
6178 				case 'i':			/* Silicon */
6179 					result = 14;
6180 					break;
6181 				case 'c':			/* Scandium */
6182 					result = 21;
6183 					break;
6184 				case 'e':			/* Selenium */
6185 					result = 34;
6186 					break;
6187 				case 'r':			/* Strontium */
6188 					result = 38;
6189 					break;
6190 				case 'n':			/* Tin */
6191 					result = 50;
6192 					break;
6193 				case 'b':			/* Antimony */
6194 					result = 51;
6195 					break;
6196 				case 'm':			/* Samarium */
6197 					result = 62;
6198 					break;
6199 				case 'g':			/* Seaborgium */
6200 					result = 106;
6201 					break;
6202 				default:			/* Sulfur */
6203 					result = 16;
6204 					break;
6205 			}
6206 			break;
6207 		case 'P':
6208 			switch (label[1]) {
6209 				case 'd':			/* Palladium */
6210 					result = 46;
6211 					break;
6212 				case 'r':			/* Praseodymium */
6213 					result = 59;
6214 					break;
6215 				case 'm':			/* Promethium */
6216 					result = 61;
6217 					break;
6218 				case 't':			/* Platinum */
6219 					result = 78;
6220 					break;
6221 				case 'b':			/* Lead */
6222 					result = 82;
6223 					break;
6224 				case 'o':			/* Polonium */
6225 					result = 84;
6226 					break;
6227 				case 'a':			/* Protoactinium */
6228 					result = 91;
6229 					break;
6230 				case 'u':			/* Plutonium */
6231 					result = 94;
6232 					break;
6233 				default:			/* Phosphorus */
6234 					result = 15;
6235 					break;
6236 			}
6237 			break;
6238 		case 'K':
6239 			switch (label[1]) {
6240 				case 'r':			/* Krypton */
6241 					result = 36;
6242 					break;
6243 				default:			/* Potassium */
6244 					result = 19;
6245 					break;
6246 			}
6247 			break;
6248 		case 'T':
6249 			switch (label[1]) {
6250 				case 'i':			/* Titanium */
6251 					result = 22;
6252 					break;
6253 				case 'c':			/* Technetium */
6254 					result = 43;
6255 					break;
6256 				case 'e':			/* Tellurium */
6257 					result = 52;
6258 					break;
6259 				case 'b':			/* Terbium */
6260 					result = 65;
6261 					break;
6262 				case 'm':			/* Thullium */
6263 					result = 69;
6264 					break;
6265 				case 'a':			/* Tantalum */
6266 					result = 73;
6267 					break;
6268 				case 'l':			/* Thallium */
6269 					result = 81;
6270 					break;
6271 				case 'h':			/* Thorium */
6272 					result = 90;
6273 					break;
6274 			}
6275 			break;
6276 		case 'V':					/* Vanadium */
6277 					result = 23;
6278 					break;
6279 		case 'Z':
6280 			switch (label[1]) {
6281 				case 'n':			/* Zinc */
6282 					result = 30;
6283 					break;
6284 				case 'r':			/* Zirconium */
6285 					result = 40;
6286 					break;
6287 			}
6288 			break;
6289 		case 'G':
6290 			switch (label[1]) {
6291 				case 'a':			/* Gallium */
6292 					result = 31;
6293 					break;
6294 				case 'e':			/* Germanium */
6295 					result = 32;
6296 					break;
6297 				case 'd':			/* Gadolinium */
6298 					result = 64;
6299 					break;
6300 			}
6301 			break;
6302 		case 'R':
6303 			switch (label[1]) {
6304 				case 'b':			/* Rubidium */
6305 					result = 37;
6306 					break;
6307 				case 'u':			/* Ruthenium */
6308 					result = 44;
6309 					break;
6310 				case 'g':
6311 					result = 111;	//Roentgenium
6312 					break;
6313 				case 'h':			/* Rhodium */
6314 					result = 45;
6315 					break;
6316 				case 'e':			/* Rhenium */
6317 					result = 75;
6318 					break;
6319 				case 'n':			/* Radon */
6320 					result = 86;
6321 					break;
6322 				case 'a':			/* Radium */
6323 					result = 88;
6324 					break;
6325 				case 'f':			/* Rutherfordium */
6326 					result = 104;
6327 					break;
6328 			}
6329 			break;
6330 		case 'Y':
6331 			switch (label[1]) {
6332 				case 'b':			/* Ytterbium */
6333 					result = 70;
6334 					break;
6335 				default:			/* Yttrium */
6336 					result = 39;
6337 					break;
6338 			}
6339 			break;
6340 		case 'I':
6341 			switch (label[1]) {
6342 				case 'n':			/* Indium */
6343 					result = 49;
6344 					break;
6345 				case 'r':			/* Iridium */
6346 					result = 77;
6347 					break;
6348 				default:			/* Iodine */
6349 					result = 53;
6350 					break;
6351 			}
6352 			break;
6353 		case 'X':					/* Xenon */
6354 					result = 54;
6355 					break;
6356 		case 'E':
6357 			switch (label[1]) {
6358 				case 'u':			/* Europium */
6359 					result = 63;
6360 					break;
6361 				case 'r':			/* Erbium */
6362 					result = 68;
6363 					break;
6364 				case 's':			/* Einsteinium */
6365 					result = 99;
6366 					break;
6367 			}
6368 			break;
6369 		case 'D':
6370 			switch (label[1]) {
6371 				case 'y':/* Dysprosium */
6372 					result = 66;
6373 					break;
6374 				case 'b':	/* Dubnium */
6375 					result = 105;
6376 					break;
6377 				case 's':	//Darmstadtium
6378 					result = 110;
6379 					break;
6380 				default:	//Deuterium
6381 					result = 1;
6382 					break;
6383 			}
6384 			break;
6385 		case 'W':					/* Tungsten */
6386 					result = 74;
6387 					break;
6388 		case 'U':					/* Uranium */
6389 					result = 92;
6390 					break;
6391 		case '*':	/*special atom types for special vectors*/
6392 			switch (label[1]) {
6393 				case 'c':	/*Charge centroids with dipole vectors*/
6394 					if (TestLabel[2]=='B' || TestLabel[2]=='b')
6395 						result = 117;
6396 					else
6397 						result = 116;
6398 					break;
6399 		/*		case 'd':	The next two are not yet implemented
6400 					result = 117;
6401 					break;
6402 				case 'p':
6403 					result = 118;
6404 					break;	*/
6405 				case 'v':	/*arbitrary vectors*/
6406 					result = 119;
6407 					break;
6408 				default:	/*This should only be used for *# cases*/
6409 					sscanf((char *)&(label[1]), "%ld", &result);
6410 			}
6411 			break;
6412 	}
6413 	return result;
6414 } /* SetAtomType */
6415 
6416 /**
6417  * This function opens the file specified by file_name and copies the contents
6418  * to a string.
6419  * @param file_name Name of file to read
6420  * @param contents String to write contents to
6421  * @\return True
6422 */
FileToString(const std::string & file_name,std::string & contents)6423 bool FileToString(const std::string& file_name,
6424 				  std::string& contents) {
6425 
6426 	std::ifstream f(file_name.c_str(), std::ios::in | std::ios::ate);
6427 	if (!f.is_open()) {
6428 		return false;
6429 	}
6430 
6431 	int size;
6432 
6433 	// Get file size.
6434 	size = (int) f.tellg();
6435 	f.seekg(0, std::ios::beg);
6436 
6437 	// Allocate buffer, read contents in.
6438 	char *cstr = new char[size];
6439 	f.read(cstr, size);
6440 	f.close();
6441 	contents = std::string(cstr, size);
6442 	delete[] cstr;
6443 
6444 	return true;
6445 
6446 }
6447