OSDN Git Service

d965fcb226ea498a7577aece514873e7f6ce6de4
[molby/Molby.git] / Scripts / gamess.rb
1 # coding: utf-8
2 #
3 #  gamess.rb
4 #
5 #  Created by Toshi Nagata on 2009/11/22.
6 #  Copyright 2009 Toshi Nagata. All rights reserved.
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation version 2 of the License.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 class MemoryIO < IO
18   def initialize
19     @buffer = ""
20   end
21   def write(s)
22         @buffer << s
23   end
24   def buffer
25     @buffer
26   end
27   def empty
28     @buffer = ""
29   end
30 end
31
32 class Molecule
33
34   #  Import nbo log.  The argument is either an array of Strings
35   #  or an IO object.
36   def import_nbo_log(lines)
37     if lines.is_a?(IO)
38           getline = lambda { lines.gets }
39         else
40           getline = lambda { lines.shift }
41     end
42     nbo = Hash.new
43         while (ln = getline.call) != nil
44           if ln =~ /done with NBO analysis/
45             break
46           end
47           if ln =~ /NATURAL POPULATIONS:  Natural atomic orbital occupancies/
48             #  List of Natural AOs
49                 getline.call
50                 getline.call
51                 getline.call
52                 nbo["nao"] = []
53                 while (ln = getline.call) != nil
54                   if ln =~ /^\s*$/
55                     #  Skip a blank line
56                     ln = getline.call
57                         if ln =~ /^\s*$/
58                           #  Double blank lines indicates the end of the table
59                           break
60                         end
61                   end
62                   ln.chomp!
63                   next unless ln =~ /^ *(\d+) *([A-Za-z]+) *(\d+) *([a-z]+) +([A-Za-z]+)\( *(\d+)([a-z]+)\)/
64                   i = $1.to_i - 1
65                   an = $3.to_i - 1
66                   atom_label = $2 + $3.to_s
67                   label = $4
68                   type = $5
69                   pn = $6
70                   vals = $~.post_match.split.map { |e| e.to_f }
71                   #  atom_index, type, pn+label, occupancy[, energy]
72                   nbo["nao"].push([atom_label, type, pn + label] + vals)
73                 end
74           elsif ln =~ / NATURAL BOND ORBITALS \(Summary\):/
75             nbo["nbo"] = []
76                 getline.call
77             while (ln = getline.call) != nil
78                   break if ln =~ /Total Lewis/
79                   if ln =~ /^\s*$/
80                         #  Skip a blank line
81                         ln = getline.call
82                         if ln =~ /^\s*$/
83                           #  Double blank lines indicates the end of the table
84                           break
85                         end
86                   end
87                   if ln =~ /^\s*(\d+)\. *([A-Za-z]+\*?) *\( *(\d+)\) *([A-Za-z]+) *(\d+)(- *([A-Za-z]+) *(\d+))? *(\d\.\d+)/
88                         idx = $1.to_i
89                         orb_kind = $2
90                         orb_idx = $3
91                         atom_label = $4 + ($5.to_i - 1).to_s
92                         if $6 != nil
93                           atom_label += "-" + $7 + ($8.to_i - 1).to_s
94                         end
95                         occ = $9.to_f
96                         nbo["nbo"].push([orb_kind + "_" + orb_idx, atom_label, occ])
97                   end
98                 end
99           elsif ln =~ /([A-Z]+)s in the ([A-Z]+) basis:/ || ln =~ /([A-Z]+) Fock matrix:/
100             #  Read matrix
101             dst = $1
102                 src = $2
103                 if src == nil
104                   src = "F"   #  Fock
105                 end
106                 key = src + "/" + dst
107                 getline.call
108                 getline.call
109                 getline.call
110                 elements = []
111                 labels = []
112                 idx = 0
113                 block = 0
114                 while (ln = getline.call) != nil
115                   if ln =~ /^\s*$/
116                     #  Blank line: end of one block
117                     ln = getline.call
118                         if ln =~ /^\s*$/
119                           #  Double blank lines indicates the end of the table
120                           break
121                         else
122                           #  Begin next section
123                           ln = getline.call
124                           idx = 0
125                           block += 1
126                           next
127                         end
128                   end
129                   ln.chomp!
130                   ln =~ /-?\d+\.\d+/
131                   lab = $~.pre_match.strip
132                   a = ([$~[0]] + $~.post_match.split).map { |e| e.to_f }
133                   if block == 0
134                     lab =~ /^[0-9]+\. *(.*)$/
135                     labels.push($1)
136                   end
137                   (elements[idx] ||= []).concat(a)
138                   idx += 1
139                 end
140                 nbo[key] = LAMatrix.new(elements).transpose!
141                 key2 = (src == "F" ? dst : src) + "_L"
142                 if nbo[key2] == nil
143                   nbo[key2] = labels
144                 end
145           end
146         end
147         @nbo = nbo
148         if @nbo["AO/NAO"]
149           #  Convert NAO based matrix into AO based matrix
150           @nbo.keys.each { |key|
151             if key[0..3] == "NAO/"
152                   key2 = "AO/" + key[4..-1]
153                   @nbo[key2] = @nbo["AO/NAO"] * @nbo[key]
154                 end
155           }
156         end
157         # puts @nbo.inspect
158   end
159   
160   def Molecule.read_gamess_basis_sets(fname)
161     # $gamess_basis = Hash.new unless $gamess_basis
162         $gamess_ecp = Hash.new unless $gamess_ecp
163         # $gamess_basis_desc = Hash.new unless $gamess_basis_desc
164         # $gamess_basis_keys = [] unless $gamess_basis_keys
165         basename = File.basename(fname, ".*")
166         keys = []
167         descname = nil
168     File.open(fname, "r") { |fp|
169           while (s = fp.gets)
170             if s =~ /^\s*!\s*/ && descname == nil
171               #  Get the descriptive name from the first comment line
172                   s = Regexp.last_match.post_match
173                   if s =~ /  EMSL/
174                     descname = Regexp.last_match.pre_match
175                   else
176                     descname = (s.split)[0]
177                   end
178                   $gamess_basis_desc[basename] = descname
179                   next
180                 end
181                 ss, bas = (s.split)[0..1]     #  Tokens delimited by whitespaces
182                 next if ss == nil || ss == ""
183                 if ss == "$ECP"
184                 #  Read the ECP section
185                   ecp = $gamess_ecp[basename]
186                   if !ecp
187                     ecp = []
188                         $gamess_ecp[basename] = ecp
189                   end
190                   keys << basename unless keys.include?(basename)
191                   while (s = fp.gets)
192                     break if s=~ /\$END/
193                         ary = s.split  #  (PNAME, PTYPE, IZCORE, LMAX+1)
194                         elem = ary[0].match(/\w{1,2}/).to_a[0]  #  ary[0] should begin with an element name
195                         ap = Parameter.builtin.elements.find { |p| p.name.casecmp(elem) == 0 }
196                         raise MolbyError, "the ECP definition does not begin with an element name: #{s}" if !ap
197                         ecpdef = s
198                         ln = 1
199                         (0..Integer(ary[3])).each {
200                           s = fp.gets
201                           raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
202                           ln += 1
203                           ary = s.split  #  (NGPOT, comment)
204                           ecpdef += s
205                           (1..Integer(ary[0])).each {
206                             s = fp.gets
207                                 raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
208                                 ln += 1
209                                 ecpdef += s
210                           }
211                         }
212                     ecp[ap.index] = ecpdef
213                   end
214                 elsif ss =~ /\W/
215                   #  Comments or other unrecognizable lines
216                   next
217                 elsif (ap = Parameter.builtin.elements.find { |p| p.name.casecmp(ss) == 0 || p.fullname.casecmp(ss) == 0 })
218                   #  Valid basis definition
219                   if bas == nil || bas =~ /\W/
220                     bas = basename
221                   end
222                   basis = $gamess_basis[bas]
223                   if !basis
224                     basis = []
225                         $gamess_basis[bas] = basis
226                   end
227                   keys << bas unless keys.include?(bas)
228                   basdef = ""
229                   while (s = fp.gets) && s =~ /\S/
230                     basdef += s
231                   end
232                   basis[ap.index] = basdef
233                 else
234                   raise MolbyError, "ss is not a valid element symbol or name: #{s}"
235                 end
236           end
237     }
238         unless $gamess_basis_keys.include?(basename)
239           $gamess_basis_keys.push(basename)
240         end
241   end
242
243   #  Execute GAMESS (inferior copy of rungms script)
244   #  inpname is the input file
245   #  mol (optional) is the molecule from which the GAMESS input was built.
246   #  If mol is specified and RUNTYP=OPTIMIZE, then the intermediate structures are
247   #  displayed real-time.
248   def Molecule.execute_gamess(inpname, mol = nil)
249     gmsname = get_global_settings("gamess.executable_path")
250     gmsdir = nil
251     gmsvers = nil
252
253         cygwin_version = false  #  For windows: old cygwin version
254         
255     while 1
256       if gmsname == nil || !File.exist?(gmsname)
257         gmsname = Dialog.open_panel("Please locate the GAMESS executable")
258         exit if gmsname == nil
259       end
260       gmsbase = File.basename(gmsname)
261       gmsdir = File.dirname(gmsname)
262       if gmsbase =~ /gamess\.(.*)\.(exe|x)$/i
263         gmsvers = $1
264         break
265       else
266         gmsname = nil
267         error_message_box(gmsbase + " does not look like a GAMESS executable!")
268       end
269     end
270
271 #       if mol == nil
272 #               mol = Molecule.open(inpname)
273 #               if mol == nil
274 #                       error_message_box("Cannot open #{inpname} as GAMESS input")
275 #                       return
276 #               end
277 #       end
278         
279     inpbase = File.basename(inpname)
280     inpdir = File.dirname(inpname)
281     inpbody = inpbase.sub(/\.inp$/, "")
282     logbase = inpbody + ".log"
283
284     set_global_settings("gamess.executable_path", gmsname)
285
286     ncpus = get_global_settings("gamess.ncpus").to_i
287         if ncpus == 0
288           ncpus = 1
289         end
290         
291     #  Prepare the scratch directory
292         begin
293           scrdir = create_temp_dir("gamess", inpbody)
294         rescue
295           error_message_box($!.to_s)
296           return
297         end
298 #    scrdir = $home_directory + "/Molby/gamess"
299 #       begin
300 #         mkdir_recursive(scrdir)
301 #       rescue
302 #         error_message_box("Cannot create directory #{scrdir}: " + $!.to_s)
303 #         return
304 #       end
305
306 #    scrdir = scrdir + "/" + inpbody + "." + $$.to_s + ".0"
307 #    n = 0
308 #    while File.exist?(scrdir)
309 #      scrdir = scrdir.sub(".#{n}", ".#{n + 1}")
310 #      n += 1
311 #    end
312 #    Dir.mkdir(scrdir)
313
314     if $platform == "win"
315       sep = "\\"
316       scrdir.gsub!("/", sep)
317       gmsdir.gsub!("/", sep)
318     else
319       sep = "/"
320     end
321
322         #  Old (obsolete) cygwin version, using ddikick
323     if $platform == "win"
324           if gmsvers == "11"
325             cygwin_version = true
326           end
327         end
328
329     #  Get the host name etc.
330     hostname = backquote("hostname").chomp
331     if $platform == "win"
332           s = backquote("cmd.exe /c dir \"#{scrdir}\"")
333       freebytes = s.split("\n").pop.match(/([0-9,]+)[^0-9]*$/).to_a[1]
334       if freebytes
335         freebytes = (freebytes.gsub(",","").to_i / 1024).to_s + " Kbytes"
336       else
337         freebytes = "(unknown)"
338       end
339       uname = backquote("cmd.exe /c ver").to_s.gsub("\n", "")
340     else
341       freebytes = `df -k "#{scrdir}"`
342       uname = `uname`.chomp
343     end
344
345     #  Redirect standard output to the log file
346     logname = scrdir + sep + logbase
347     fpout = File.open(logname, "w")
348         if cygwin_version
349           #  The cygwin version uses LF as the eol character
350           fpout.binmode
351         end
352     fpout.print "----- GAMESS execution script -----\n"
353     fpout.print "This job is running on host #{hostname}\n"
354     fpout.print "under operating system #{uname} at #{Time.now.to_s}\n"
355     fpout.print "Available scratch disk space (Kbyte units) at beginning of the job is\n"
356     fpout.print freebytes + "\n"
357
358     #  Copy the input file
359         scrprefix = scrdir + sep + inpbody
360         if $platform == "win"
361           scrbody = inpbody
362         else
363       scrbody = scrprefix
364         end
365     filecopy(inpname, scrprefix + ".F05")
366     File.open("#{scrdir}/.in_use", "w") { |fp| }
367
368     #  Prepare environmental variables
369     auxdir = "#{gmsdir}#{sep}auxdata"
370     ENV["ERICFMT"] = "#{auxdir}#{sep}ericfmt.dat"
371     ENV["MCPPATH"] = "#{auxdir}#{sep}MCP"
372     ENV["BASPATH"] = "#{auxdir}#{sep}BASES"
373     ENV["QUANPOL"] = "#{auxdir}#{sep}QUANPOL"
374     ENV["EXTBAS"] = "/dev/null"
375     ENV["IRCDATA"] = "#{scrbody}.irc"
376         ENV["RESTART"] = "#{scrbody}.rst"
377         ENV["TRAJECT"] = "#{scrbody}.trj"
378     ENV["PUNCH"] = "#{scrbody}.dat"
379     ENV["INPUT"] = "#{scrbody}.F05"
380     ENV["AOINTS"] = "#{scrbody}.F08"
381     ENV["MOINTS"] = "#{scrbody}.F09"
382     ENV["DICTNRY"] = "#{scrbody}.F10"
383     ENV["DRTFILE"] = "#{scrbody}.F11"
384     ENV["CIVECTR"] = "#{scrbody}.F12"
385     ENV["CASINTS"] = "#{scrbody}.F13"
386     ENV["CIINTS"] = "#{scrbody}.F14"
387     ENV["WORK15"] = "#{scrbody}.F15"
388     ENV["WORK16"] = "#{scrbody}.F16"
389     ENV["CSFSAVE"] = "#{scrbody}.F17"
390     ENV["FOCKDER"] = "#{scrbody}.F18"
391     ENV["WORK19"] = "#{scrbody}.F19"
392     ENV["DASORT"] = "#{scrbody}.F20"
393     ENV["DFTINTS"] = "#{scrbody}.F21"
394     ENV["DFTGRID"] = "#{scrbody}.F22"
395     ENV["JKFILE"] = "#{scrbody}.F23"
396     ENV["ORDINT"] = "#{scrbody}.F24"
397     ENV["EFPIND"] = "#{scrbody}.F25"
398     ENV["PCMDATA"] = "#{scrbody}.F26"
399     ENV["PCMINTS"] = "#{scrbody}.F27"
400     ENV["MLTPL"] = "#{scrbody}.F28"
401     ENV["MLTPLT"] = "#{scrbody}.F29"
402     ENV["DAFL30"] = "#{scrbody}.F30"
403     ENV["SOINTX"] = "#{scrbody}.F31"
404     ENV["SOINTY"] = "#{scrbody}.F32"
405     ENV["SOINTZ"] = "#{scrbody}.F33"
406     ENV["SORESC"] = "#{scrbody}.F34"
407     ENV["SIMEN"] = "#{scrbody}.simen"
408     ENV["SIMCOR"] = "#{scrbody}.simcor"
409     ENV["GCILIST"] = "#{scrbody}.F37"
410     ENV["HESSIAN"] = "#{scrbody}.F38"
411     ENV["SOCCDAT"] = "#{scrbody}.F40"
412     ENV["AABB41"] = "#{scrbody}.F41"
413     ENV["BBAA42"] = "#{scrbody}.F42"
414     ENV["BBBB43"] = "#{scrbody}.F43"
415     ENV["MCQD50"] = "#{scrbody}.F50"
416     ENV["MCQD51"] = "#{scrbody}.F51"
417     ENV["MCQD52"] = "#{scrbody}.F52"
418     ENV["MCQD53"] = "#{scrbody}.F53"
419     ENV["MCQD54"] = "#{scrbody}.F54"
420     ENV["MCQD55"] = "#{scrbody}.F55"
421     ENV["MCQD56"] = "#{scrbody}.F56"
422     ENV["MCQD57"] = "#{scrbody}.F57"
423     ENV["MCQD58"] = "#{scrbody}.F58"
424     ENV["MCQD59"] = "#{scrbody}.F59"
425     ENV["MCQD60"] = "#{scrbody}.F60"
426     ENV["MCQD61"] = "#{scrbody}.F61"
427     ENV["MCQD62"] = "#{scrbody}.F62"
428     ENV["MCQD63"] = "#{scrbody}.F63"
429     ENV["MCQD64"] = "#{scrbody}.F64"
430     ENV["NMRINT1"] = "#{scrbody}.F61"
431     ENV["NMRINT2"] = "#{scrbody}.F62"
432     ENV["NMRINT3"] = "#{scrbody}.F63"
433     ENV["NMRINT4"] = "#{scrbody}.F64"
434     ENV["NMRINT5"] = "#{scrbody}.F65"
435     ENV["NMRINT6"] = "#{scrbody}.F66"
436     ENV["DCPHFH2"] = "#{scrbody}.F67"
437     ENV["DCPHF21"] = "#{scrbody}.F68"
438     ENV["GVVPT"] = "#{scrbody}.F69"
439
440     #    next files are used only during coupled cluster runs, so let's
441     #    display the numerous definitions only if they are to be used.
442         #    Don't set these variables on windows, where the memory for environmental variables
443         #    is limited.
444         if $platform != "win"
445     ENV["CCREST"] = "#{scrbody}.F70"
446     ENV["CCDIIS"] = "#{scrbody}.F71"
447     ENV["CCINTS"] = "#{scrbody}.F72"
448     ENV["CCT1AMP"] = "#{scrbody}.F73"
449     ENV["CCT2AMP"] = "#{scrbody}.F74"
450     ENV["CCT3AMP"] = "#{scrbody}.F75"
451     ENV["CCVM"] = "#{scrbody}.F76"
452     ENV["CCVE"] = "#{scrbody}.F77"
453     ENV["EOMSTAR"] = "#{scrbody}.F80"
454     ENV["EOMVEC1"] = "#{scrbody}.F81"
455     ENV["EOMVEC2"] = "#{scrbody}.F82"
456     ENV["EOMHC1"] = "#{scrbody}.F83"
457     ENV["EOMHC2"] = "#{scrbody}.F84"
458     ENV["EOMHHHH"] = "#{scrbody}.F85"
459     ENV["EOMPPPP"] = "#{scrbody}.F86"
460     ENV["EOMRAMP"] = "#{scrbody}.F87"
461     ENV["EOMRTMP"] = "#{scrbody}.F88"
462     ENV["EOMDG12"] = "#{scrbody}.F89"
463     ENV["MMPP"] = "#{scrbody}.F90"
464     ENV["MMHPP"] = "#{scrbody}.F91"
465     ENV["MMCIVEC"] = "#{scrbody}.F92"
466     ENV["MMCIVC1"] = "#{scrbody}.F93"
467     ENV["MMCIITR"] = "#{scrbody}.F94"
468     ENV["MMNEXM"] = "#{scrbody}.F95"
469     ENV["MMNEXE"] = "#{scrbody}.F96"
470     ENV["MMNREXM"] = "#{scrbody}.F97"
471     ENV["MMNREXE"] = "#{scrbody}.F98"
472         end
473     #
474     #     next are for TDHFX code, not used by current GAMESS
475     #
476         if false
477     ENV["OLI201"] = "#{scrbody}.F201"
478     ENV["OLI202"] = "#{scrbody}.F202"
479     ENV["OLI203"] = "#{scrbody}.F203"
480     ENV["OLI204"] = "#{scrbody}.F204"
481     ENV["OLI205"] = "#{scrbody}.F205"
482     ENV["OLI206"] = "#{scrbody}.F206"
483     ENV["OLI207"] = "#{scrbody}.F207"
484     ENV["OLI208"] = "#{scrbody}.F208"
485     ENV["OLI209"] = "#{scrbody}.F209"
486     ENV["OLI210"] = "#{scrbody}.F210"
487     ENV["OLI211"] = "#{scrbody}.F211"
488     ENV["OLI212"] = "#{scrbody}.F212"
489     ENV["OLI213"] = "#{scrbody}.F213"
490     ENV["OLI214"] = "#{scrbody}.F214"
491     ENV["OLI215"] = "#{scrbody}.F215"
492     ENV["OLI216"] = "#{scrbody}.F216"
493     ENV["OLI217"] = "#{scrbody}.F217"
494     ENV["OLI218"] = "#{scrbody}.F218"
495     ENV["OLI219"] = "#{scrbody}.F219"
496     ENV["OLI220"] = "#{scrbody}.F220"
497     ENV["OLI221"] = "#{scrbody}.F221"
498     ENV["OLI222"] = "#{scrbody}.F222"
499     ENV["OLI223"] = "#{scrbody}.F223"
500     ENV["OLI224"] = "#{scrbody}.F224"
501     ENV["OLI225"] = "#{scrbody}.F225"
502     ENV["OLI226"] = "#{scrbody}.F226"
503     ENV["OLI227"] = "#{scrbody}.F227"
504     ENV["OLI228"] = "#{scrbody}.F228"
505     ENV["OLI229"] = "#{scrbody}.F229"
506     ENV["OLI230"] = "#{scrbody}.F230"
507     ENV["OLI231"] = "#{scrbody}.F231"
508     ENV["OLI232"] = "#{scrbody}.F232"
509     ENV["OLI233"] = "#{scrbody}.F233"
510     ENV["OLI234"] = "#{scrbody}.F234"
511     ENV["OLI235"] = "#{scrbody}.F235"
512     ENV["OLI236"] = "#{scrbody}.F236"
513     ENV["OLI237"] = "#{scrbody}.F237"
514     ENV["OLI238"] = "#{scrbody}.F238"
515     ENV["OLI239"] = "#{scrbody}.F239"
516     end
517         
518     if $platform == "win"
519         #  if ncpus < 2
520         #    ncpus = 2
521         #  end
522           if cygwin_version
523             #  Old (obsolete) cygwin version, using ddikick
524         fpout.print "ddikick will run #{ncpus} compute process\n"
525                 ENV["CYGWIN"] = "nodosfilewarning"
526           else
527         fpout.print "Microsoft MPI will be running GAMESS on 1 node.\n"
528         fpout.print "The binary kicked off by 'mpiexec' is gamess.#{gmsvers}.exe\n"
529         fpout.print "MS-MPI will run #{ncpus*2} compute process\n"
530         #  File containing environmental variables
531         envfil = "#{scrprefix}.GMS.ENV"
532         fp = File.open(envfil, "w")
533         ENV.each { |k, v| fp.print "#{k}=#{v}\n" }
534         fp.close
535         #  File containing arguments to mpiexec
536         procfil = "#{scrprefix}.processes.mpd"
537         fp = File.open(procfil, "w")
538         fp.print "-env ENVFIL \"#{envfil}\" -wdir \"#{scrdir}\" -n #{ncpus*2} \"#{gmsdir}#{sep}gamess.#{gmsvers}.exe\"\n"
539         fp.close
540           end
541     end
542     
543     fpout.close
544     fplog = File.open(logname, "r")
545     size = 0
546     lines = []
547         lineno = 0
548     last_line = ""
549     search_mode = 0
550         nserch = -1
551         rflag = 0
552         ne_alpha = ne_beta = 0
553         mo_count = 0
554         ncomps = 0
555         
556     #  Callback procs
557         term_callback = lambda { |m, n|
558           msg = "GAMESS execution on #{inpbase} "
559           hmsg = "GAMESS "
560           if n == 0
561             msg += "succeeded."
562                 hmsg += "Completed"
563                 icon = :info
564           else
565             msg += "failed with status #{n}."
566                 hmsg += "Failed"
567                 icon = :error
568           end
569           msg += "\n(In directory #{inpdir})"
570
571           File.delete("#{scrdir}/.in_use")
572
573           ext_to_keep = [".dat", ".rst", ".trj", ".efp", ".gamma", ".log"]
574           ext_to_keep.each { |ex|
575             if File.exists?("#{scrprefix}#{ex}")
576                   filecopy("#{scrprefix}#{ex}", "#{inpdir}#{sep}#{inpbody}#{ex}")
577             end
578           }
579           Dir.foreach(scrdir) { |file|
580             if file != "." && file != ".." && !ext_to_keep.include?(File.extname(file))
581                   File.delete("#{scrdir}#{sep}#{file}")
582             end
583           }
584
585           begin
586             erase_old_logs(scrdir, "latest", 5)
587           rescue
588             error_message_box($!.to_s)
589                 return
590           end
591           
592           if (script = get_global_settings("gamess.postfix_script")) != nil && script != ""
593             eval(script)
594           end
595
596           if mol != nil
597             message_box(msg, hmsg, :ok, icon)
598       end
599     }
600         
601     timer_callback = lambda { |m, n|
602       fplog.seek(0, IO::SEEK_END)
603       sizec = fplog.tell
604       if sizec > size
605         #  Read new lines
606         fplog.seek(size, IO::SEEK_SET)
607         fplog.each_line { |line|
608           if line[-1, 1] == "\n"
609             lines.push(last_line + line)
610             last_line = ""
611           else
612             last_line += line
613             break
614           end
615         }
616         size = fplog.tell
617         last_i = nil
618         i = 0
619         while i < lines.count
620           line = lines[i]
621           if line =~ /GEOMETRY SEARCH POINT NSERCH= *(\d+)/
622             nserch = $1.to_i
623             last_i = i
624                         search_mode = 1
625                         energy = nil
626                   elsif line =~ /START OF DRC CALCULATION/
627                     search_mode = 3
628                         nserch = 1
629                         energy = nil
630                   elsif line =~ /CONSTRAINED OPTIMIZATION POINT/
631                     search_mode = 2
632                         energy = nil
633                   elsif line =~ /POINT *([0-9]+) *ON THE REACTION PATH/
634                     nserch = $1.to_i
635                         last_i = i
636                   elsif line =~ /ATOMIC BASIS SET/
637                         j = i
638                         while j < lines.count
639                           line = lines[j]
640                           break if line =~ /TOTAL NUMBER OF BASIS SET/
641                           j += 1
642                         end
643                         if j < lines.count
644                           #  Found
645                           bs_lines = []
646                           ii = i
647                           while ii <= j
648                             bs_lines.push(lines[ii].chomp)
649                                 ii += 1
650                           end
651                           begin
652                             if mol
653                                   ncomps = mol.sub_load_gamess_log_basis_set(bs_lines, lineno + i)
654                                 end
655                           rescue
656                             puts $!.to_s
657                             puts $!.backtrace.inspect
658                           end
659                           last_i = j
660                         else
661                           break  #  Wait until all basis set lines are read
662                         end
663                   elsif line =~ /NUMBER OF OCCUPIED ORBITALS/
664                         line =~ /=\s*(\d+)/
665                         n = Integer($1)
666                         if line =~ /ALPHA/
667                           ne_alpha = n
668                         else
669                           ne_beta = n
670                         end
671                   elsif line =~ /SCFTYP=(\w+)/
672                         scftyp = $1
673                         if ne_alpha > 0 || ne_beta > 0
674                           rflag = 0
675                           case scftyp
676                           when "RHF"
677                                 rflag = 1
678                           when "ROHF"
679                                 rflag = 2
680                           end
681                         end
682                   elsif line =~ /^\s*(EIGENVECTORS|MOLECULAR ORBITALS)\s*$/
683                         if mo_count == 0 && mol
684                           mol.clear_mo_coefficients
685                           mol.set_mo_info(:type=>["UHF", "RHF", "ROHF"][rflag], :alpha=>ne_alpha, :beta=>ne_beta)
686                         end
687                         i += 2
688                         j = i
689                         mo_count += 1
690                         while j < lines.count
691                           line = lines[j]
692                           break if line =~ /\.\.\.\.\.\./ || line =~ /----------------/
693                           j += 1
694                         end
695                         if j == lines.count
696                           break  #  Wait until complete MO info are read
697                         end
698                         ii = i
699                         mo_lines = []
700                         while ii < j
701                           mo_lines.push(lines[ii].chomp)
702                           ii += 1
703                         end
704                         begin
705                           if mol
706                             mol.sub_load_gamess_log_mo_coefficients(mo_lines, lineno + i, ncomps)
707                           end
708                         rescue
709                           puts $!.to_s
710                           puts $!.backtrace.inspect
711                         end
712                         last_i = j
713           elsif line =~ /NSERCH: *([0-9]+)/
714           #  print line
715                         if mol
716                           n = $1
717                           line =~ /E= +([-.0-9]+)/
718                           energy = $1.to_f
719                           line =~ /GRAD\. MAX= +([-.0-9]+)/
720                           grad = $1
721                           mol.show_text("Search: #{n}\nGradient: #{grad}")
722                           # mol.set_property("energy", energy)
723                         end
724                         last_i = i
725                   elsif line =~ /TOTAL ENERGY += *([-.0-9]+)/
726                     energy = $1
727                         if mol && search_mode == 2
728                           mol.show_text("Point: #{nserch}\nEnergy: #{energy}")
729                         end
730                         energy = energy.to_f
731                   elsif line =~ /FINAL .* ENERGY IS +([-.0-9]+) *AFTER/
732                     energy = $1.to_f
733                         if mol && search_mode == 0
734                           mol.set_property("energy", energy)
735                         end
736           elsif nserch > 0 && line =~ /ddikick\.x/
737             last_i = -1
738             break
739           elsif mol && nserch > 0 && (line =~ /COORDINATES OF ALL ATOMS/ || line =~ /COORDINATES \(IN ANGSTROM\) FOR \$DATA GROUP ARE/)
740             #  There should be (natoms) lines
741                         if line =~ /COORDINATES OF ALL ATOMS/
742                           #  Skip header lines
743                           i += 2
744                     end
745             if i + mol.natoms + 1 <= lines.count
746               coords = []
747               (i + 1...i + 1 + mol.natoms).each { |j|
748                 name, charge, x, y, z = lines[j].split
749                 coords.push(Vector3D[x.to_f, y.to_f, z.to_f])
750               }
751               mol.create_frame([coords])
752                           if search_mode == 1 && energy
753                             mol.set_property("energy", energy)
754                           end
755               mol.display
756               last_i = i + mol.natoms
757               i = last_i   #  Skip the processed lines
758             end
759                   elsif line =~ /N A T U R A L   B O N D   O R B I T A L   A N A L Y S I S/
760                     #  NBO output
761                     j = i + 1
762                         while j < lines.count
763                           break if lines[j] =~ /done with NBO analysis/
764                           j += 1
765                         end
766                         if j < lines.count
767                           nbo_lines = lines[i..j]
768                           mol.import_nbo_log(nbo_lines) rescue puts "Error: #{$!}, #{$!.backtrace.inspect}"
769                           last_i = j
770                           i = last_i  #  Skip the processed lines
771                         else
772                           break  #  Wait until NBO is done
773                         end
774           end
775           i += 1
776         end
777         if last_i == -1
778           lines.clear
779           break
780         elsif last_i
781           lines[0..last_i] = nil
782                   lineno += last_i + 1
783         end
784       end
785       true
786     }
787
788     if (script = get_global_settings("gamess.prefix_script")) != nil && script != ""
789           eval(script)
790         end
791
792     if $platform == "win"
793           if gmsvers == "11"
794             hosts = "localhost " * ncpus
795             cmdline = "cmd.exe /c \"#{gmsdir}/ddikick.exe #{gmsdir}/gamess.#{gmsvers}.exe #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < NUL >>#{logname}"
796           else
797             cmdline = "cmd.exe /c \"mpiexec -configfile #{procfil} >>#{logname}"
798           end
799         else
800           hosts = "localhost " * ncpus
801           cmdline = "/bin/sh -c '#{gmsdir}/ddikick.x #{gmsdir}/gamess.#{gmsvers}.x #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < /dev/null >>#{logname}'"
802         end
803         
804         if mol
805           pid = mol.call_subprocess_async(cmdline, term_callback, timer_callback)
806           if pid < 0
807             error_message_box("GAMESS failed to start. Please examine GAMESS installation.")
808             return
809           end
810         else
811           pid = call_subprocess(cmdline, "Running GAMESS")
812           term_callback.call(nil, pid)
813           return pid
814         end
815
816   end
817
818   def export_gamess(fname, hash)
819
820     def reorder_array(ary, ordered_sub_ary)
821           return (ordered_sub_ary & ary) + (ary - ordered_sub_ary)
822         end
823         
824         now = Time.now.to_s
825         if fname
826           basename = File.basename(fname, ".*")
827         else
828           basename = File.basename(self.name, ".*")
829         end
830         
831         #  Various settings
832         icharg = hash["charge"]
833         mult = hash["mult"]
834         runtyp = ["ENERGY", "PROP", "OPTIMIZE"][hash["runtype"].to_i]
835         scftyp = ["RHF", "ROHF", "UHF"][hash["scftype"].to_i]
836         bssname = hash["basis"]
837         bssname2 = hash["secondary_basis"]
838         if hash["use_secondary_basis"].to_i != 0 && bssname2 != bssname
839           use_2nd = true
840           element2 = hash["secondary_elements"].split(/[\s,]+/).map { |name| name.capitalize }
841         else
842           use_2nd = false
843           bssname2 = bssname
844         end
845         basis = $gamess_basis[bssname]
846         basis2 = $gamess_basis[bssname2]
847
848         #  Use effective core potentials?
849         ecp = $gamess_ecp[bssname]
850         ecp2 = $gamess_ecp[bssname2]
851         ecp_read = (ecp || ecp2 ? "ECP=READ " : "")
852
853         #  Use only one built-in basis set?
854         gbasis = nil
855         if !use_2nd
856           case bssname
857           when "PM3"
858                 gbasis = "PM3 NGAUSS=3"
859           when "STO3G"
860                 gbasis = "STO NGAUSS=3"
861           when "321G"
862                 gbasis = "N21 NGAUSS=3"
863           when "631G"
864                 gbasis = "N31 NGAUSS=6"
865           when "631Gd"
866                 gbasis = "N31 NGAUSS=6 NDFUNC=1"
867           when "631Gdp"
868                 gbasis = "N31 NGAUSS=6 NDFUNC=1 NPFUNC=1"
869           when "6311G"
870                 gbasis = "N311 NGAUSS=6"
871           when "6311Gdp"
872                 gbasis = "N311 NGAUSS=6 NDFUNC=1 NPFUNC=1"
873           end
874         end
875     
876         #  Count non-dummy atoms
877         natoms = 0
878         each_atom { |ap|
879           natoms += 1 if ap.atomic_number != 0
880         }
881         
882         #  Fill hash with default values
883         h = (hash["CONTRL"] ||= Hash.new)
884         h["COORD"] ||= "UNIQUE"
885         h["EXETYP"] ||= "RUN"
886         h["ICHARG"] ||= (icharg || 0).to_s
887         h["ICUT"] ||= "20"
888         h["INTTYP"] ||= "HONDO"
889         h["ITOL"] ||= "30"
890         h["MAXIT"] ||= "200"
891         h["MOLPLT"] ||= ".T."
892         h["MPLEVL"] ||= "0"
893         h["MULT"] ||= mult.to_s
894         h["QMTTOL"] ||= "1e-08"
895         h["RUNTYP"] ||= runtyp
896         if (hash["dft"] || 0) != 0 && hash["dfttype"]
897           h["DFTTYP"] ||= hash["dfttype"]
898         end
899         if (hash["use_internal"] || 0) != 0 && (hash["runtype"] == 2 || h["RUNTYP"] == "OPTIMIZE")
900           nzvar = natoms * 3 - 6  #  TODO: 3N-5 for linear molecules
901           h["NZVAR"] ||= nzvar.to_s
902         else
903           nzvar = 0
904         end
905         h["SCFTYP"] ||= scftyp
906         if ecp_read != ""
907           h["ECP"] ||= "READ"
908         end
909         h["UNITS"] ||= "ANGS"
910         
911         h = (hash["SCF"] ||= Hash.new)
912         h["CONV"] ||= "1.0E-06"
913         h["DIRSCF"] ||= ".T."
914         h["FDIFF"] ||= ".T."
915         h["DAMP"] ||= ".T."
916         
917         h = (hash["STATPT"] ||= Hash.new)
918         h["NSTEP"] ||= "400"
919         h["OPTTOL"] ||= "1.0E-06"
920     if hash["eliminate_freedom"] == 0
921       h["PROJCT"] ||= ".F."
922     end
923
924         h = (hash["SYSTEM"] ||= Hash.new)
925         h["MEMDDI"] ||= "0"
926         h["MWORDS"] ||= "16"
927         h["TIMLIM"] ||= "50000"
928         
929         h = (hash["GUESS"] ||= Hash.new)
930         h["GUESS"] ||= "HUCKEL"
931         
932         if gbasis
933           h = (hash["BASIS"] ||= Hash.new)
934           h["GBASIS"] ||= gbasis
935         end
936         
937         if nzvar > 0
938           h = (hash["ZMAT"] ||= Hash.new)
939           h["DLC"] ||= ".T."
940           h["AUTO"] ||= ".T."
941         end
942         
943         if (hash["esp"] || 0) != 0
944           h = (hash["ELPOT"] ||= Hash.new)
945           h["IEPOT"] ||= "1"
946           h["OUTPUT"] ||= "PUNCH"
947           h["WHERE"] ||= "PDC"
948           h = (hash["PDC"] ||= Hash.new)
949           h["CONSTR"] ||= "NONE"
950           h["PTSEL"] ||= "CONNOLLY"
951         end
952         
953     if (hash["include_nbo"] || 0) != 0
954       h = (hash["NBO"] ||= Hash.new)
955       s = ""
956       ["nao", "nbo", "nho", "nlmo", "pnao", "pnbo", "pnho", "pnlmo"].each { |nao|
957         if (hash[nao] || 0) != 0
958           s += " f" + nao + " ao" + nao
959         end
960       }
961       h[s] = ""
962     end
963
964         if fname
965           fp = File.open(fname, "wb")
966         else
967           fp = MemoryIO.new
968         end
969     if fp
970           fp.print "!  GAMESS input\n"
971           fp.print "!  Generated by Molby at #{now}\n"
972           fp.print "!  Basis set: " + ($gamess_basis_desc[bssname] || "(not specified)") + "\n"
973           if use_2nd
974             fp.print "!  [" + element2.join(", ") + "]: " + ($gamess_basis_desc[bssname2] || "(not specified)") + "\n"
975           end
976           ordered = ["CONTRL", "SCF", "STATPT", "SYSTEM", "GUESS", "BASIS", "ZMAT", "ELPOT", "PDC"]
977           controls = reorder_array(hash.keys.select { |k| k != "key_order" && hash[k].is_a?(Hash) },
978                 hash["key_order"] || ordered)
979           controls.each { |k|
980             h = hash[k]
981                 next if h == nil || h.size == 0 || (h["key_order"] && h.size == 1)
982                 if k == "CONTRL"
983                   ordered = ["COORD", "EXETYP", "ICHARG", "ICUT", "INTTYP", "ITOL", "MAXIT", "MOLPLT", "MPLEVL",
984                              "MULT", "QMTTOL", "RUNTYP", "SCFTYP", "ECP", "UNITS", "DFTTYP", "NZVAR"]
985                 elsif k == "SCF"
986                   ordered = ["CONV", "DIRSCF", "FDIFF", "DAMP"]
987                 elsif k == "STATPT"
988                   ordered = ["NSTEP", "OPTTOL"]
989                 elsif k == "SYSTEM"
990                   ordered = ["MEMDDI", "MWORDS", "TIMLIM"]
991                 elsif k == "GUESS"
992                   ordered = ["GUESS"]
993                 elsif k == "BASIS"
994                   ordered = ["GBASIS"]
995                 elsif k == "ZMAT"
996                   ordered = ["DLC", "AUTO"]
997                 elsif k == "ELPOT"
998                   ordered = ["IEPOT", "OUTPUT", "WHERE"]
999                 elsif k == "PDC"
1000                   ordered = ["CONSTR", "PTSEL"]
1001                 else
1002                   ordered = []
1003                 end
1004             keys = reorder_array(h.keys, h["key_order"] || ordered)
1005                 n = 0
1006                 keys.each_with_index { |kk, i|
1007                   v = h[kk]
1008                   if n == 0
1009                     fp.printf " $%-6s", k
1010                   elsif n % 3 == 0
1011                     fp.print "\n        "
1012                   end
1013                   if v == nil || v == ""
1014                     #  No value
1015                         fp.print " " + kk
1016                   else
1017                     fp.printf " %s=%s", kk, h[kk].to_s
1018                   end
1019                   n += 1
1020                 }
1021                 if n > 0
1022                   fp.print " $END\n"
1023                 end
1024           }
1025           fp.print " $DATA\n#{basename}\nC1 0\n"
1026           secondary = []
1027           each_atom { |ap|
1028             next if ap.atomic_number == 0
1029                 fp.printf "%-6s %4d %10.6f %10.6f %10.6f\n", ap.name, ap.atomic_number, ap.r.x, ap.r.y, ap.r.z
1030                 if use_2nd && element2.include?(ap.element)
1031                   secondary[ap.index] = true
1032                 end
1033             if !gbasis
1034                   #  Basis specification followed by a blank line
1035                   bas = (secondary[ap.index] ? basis2 : basis)
1036                   if bas.is_a?(Array)
1037                     bas = bas[ap.atomic_number]
1038                   end
1039                   if bas
1040                     fp.print bas
1041                     fp.print "\n"
1042                   else
1043                     puts "Warning: basis set is not defined for atom #{ap.index}, element #{ap.element}"
1044                   end
1045                 end
1046           }
1047           fp.print " $END\n"
1048           ecp_ary = []
1049           if ecp || ecp2
1050             fp.print " $ECP\n"
1051                 each_atom { |ap|
1052                   an = ap.atomic_number
1053                   next if an == 0
1054                   ecpp = (secondary[ap.index] ? ecp2 : ecp)
1055                   e = ecp_ary[an] || (ecpp && ecpp[an])
1056                   if e
1057                     #  Cache the PNAME of the $ECP entry and re-use it
1058                     ecp_ary[an] ||= (e.split)[0] + "\n"
1059                   else
1060                     e = ap.element.upcase + "-ECP NONE\n"
1061                   end
1062                   fp.print e
1063                 }
1064             fp.print " $END\n"
1065           end
1066         end
1067         if fname == nil
1068           s = fp.buffer
1069       fp.empty
1070           return s
1071         else
1072           fp.close
1073           return fname
1074         end
1075   end
1076   
1077   def cmd_edit_gamess_input(s)
1078     h = Dialog.run("Edit GAMESS Input", "OK", "Cancel", :resizable=>true) {
1079           layout(1,
1080             item(:textview, :value=>s, :tag=>"edit", :width=>400, :height=>400, :flex=>[0,0,0,0,1,1]),
1081             :flex=>[0,0,0,0,1,1]
1082           )
1083           set_min_size(300, 300)
1084         }
1085         if h[:status] == 0
1086           return h["edit"]
1087         else
1088           return nil
1089         end
1090   end
1091   
1092   def cmd_create_gamess_input
1093
1094     mol = self
1095         
1096     if natoms == 0
1097       raise MolbyError, "cannot create GAMESS input; the molecule is empty"
1098     end
1099
1100         #  Descriptive text and internal string for popup menus
1101 #    bset_desc = ["PM3", "STO-3G", "3-21G", "6-31G", "6-31G(d)", "6-31G(d,p)", "6-311G", "6-311G(d,p)", "LanL2DZ"]
1102 #       bset_internal = ["PM3", "STO3G", "321G", "631G", "631Gd", "631Gdp", "6311G", "6311Gdp", "LanL2DZ"]
1103     bset_desc = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
1104         dft_desc = ["B3LYP"]
1105         dft_internal = ["B3LYP"]
1106
1107         defaults = {"scftype"=>0, "runtype"=>0, "use_internal"=>1, "eliminate_freedom"=>1, "charge"=>"0", "mult"=>"1",
1108           "basis"=>4, "use_secondary_basis"=>0, "secondary_elements"=>"",
1109           "secondary_basis"=>8, "esp"=>0, "ncpus"=>"1"}
1110
1111         gamess_input_direct = nil
1112         
1113     user_input = Hash.new
1114         ["CONTRL", "SCF", "STATPT", "SYSTEM", "GUESS", "BASIS"].each { |k|
1115           user_input[k] = Hash.new
1116         }
1117     if ".inp".casecmp(self.name[-4, 4]) == 0
1118           #  Read input and analyze commands
1119           fp = open(self.path, "r")
1120           key = hh = nil
1121           if fp
1122             while ln = fp.gets
1123                   ln.strip!
1124                   break if "$DATA".casecmp(ln[0, 5]) == 0
1125                   ln.split.each { |s|
1126                     if s[0] == "$"
1127                           #  New key
1128                           key = s[1..-1].upcase
1129                           hh = user_input[key] = Hash.new
1130                           (user_input["key_order"] ||= []).push(key)
1131                         else
1132                           k, v = s.split("=")
1133                           if key && hh
1134                             k.upcase!
1135                             hh[k] = v
1136                                 (hh["key_order"] ||= []).push(k)
1137                           end
1138                         end
1139                   }
1140                 end  #  end while
1141                 fp.close
1142                 user_input["charge"] = user_input["CONTRL"]["ICHARG"]
1143                 user_input["mult"] = user_input["CONTRL"]["MULT"]
1144                 user_input["runtype"] = ((i = ["ENERGY", "PROP", "OPTIMIZE"].find_index(user_input["CONTRL"]["RUNTYP"])) ? i.to_s : nil)
1145                 user_input["scftype"] = ((i = ["RHF", "ROHF", "UHF"].find_index(user_input["CONTRL"]["SCFTYP"])) ? i.to_s : nil)
1146                 dft_type = dft_internal.find_index(user_input["CONTRL"]["DFTTYP"])
1147                 if dft_type
1148                   user_input["dfttype"] = dft_type.to_s
1149                   user_input["dft"] = 1
1150                 end
1151                 bssname = nil
1152                 user_input["basis"] = "-1"
1153                 case user_input["BASIS"]["GBASIS"]
1154                 when "PM3"
1155                   bssname = "PM3"
1156                 when "STO"
1157                   bssname = "STO3G"
1158                 when "N21"
1159                   bssname = "321G"
1160                 when "N31"
1161                   if user_input["NDFUNC"] == "1"
1162                     if user_input["NPFUNC"] == "1"
1163                           bssname = "631Gdp"
1164                         else
1165                           bssname = "631Gd"
1166                         end
1167                   else
1168                     bssname = "631G"
1169                   end
1170                 when "N311"
1171                   if user_input["NDFUNC"] == "1" && user_input["NPFUNC"] == "1"
1172                     bssname = "6311Gdp"
1173                   else
1174                     bssname = "6311G"
1175                   end
1176                 end
1177                 if bssname
1178                   user_input["basis"] = $gamess_basis_keys.find_index(bssname).to_s
1179                 end
1180           #  puts user_input.inspect
1181           end
1182         end
1183         
1184     hash = Dialog.run("GAMESS Export") {
1185       def load_basis_set_sub(item)
1186             fname = Dialog.open_panel("Select a file containing GAMESS basis set:")
1187                 if fname
1188                   Molecule.read_gamess_basis_sets(fname)
1189                   bset_desc_new = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
1190                   sel1 = attr("basis", :value)
1191                   sel2 = attr("secondary_basis", :value)
1192                   set_attr("basis", :subitems=>bset_desc_new)
1193                   set_attr("basis", :value=>sel1)
1194                   set_attr("secondary_basis", :subitems=>bset_desc_new)
1195                   set_attr("secondary_basis", :value=>sel2)
1196                 end
1197       end
1198           def select_gamess_path(item)
1199             while 1
1200               fname = Dialog.open_panel("Locate GAMESS executable:")
1201                   return if fname == nil
1202                   bname = File.basename(fname)
1203                   if bname =~ /gamess\.(.*)\.(exe|x)$/i
1204                     set_attr("executable_path", :value=>fname)
1205                     return
1206                   else
1207                     error_message_box("\"#{bname}\" does not look like a GAMESS executable!  Please try again.")
1208                   end
1209                 end
1210           end
1211           def set_optional_scripts(item)
1212             h = Dialog.run("GAMESS Optional Scripts") {
1213                   s_pre = get_global_settings("gamess.prefix_script")
1214                   s_post = get_global_settings("gamess.postfix_script")
1215                   layout(1,
1216                     item(:text, :title=>"Script to run before GAMESS execution:"),
1217                         item(:textview, :width=>400, :height=>200, :value=>s_pre, :tag=>"prefix"),
1218                     item(:text, :title=>"Script to run after GAMESS execution:"),
1219                         item(:textview, :width=>400, :height=>200, :value=>s_post, :tag=>"postfix"))
1220                 }
1221                 if h[:status] == 0
1222                   set_global_settings("gamess.prefix_script", h["prefix"])
1223                   set_global_settings("gamess.postfix_script", h["postfix"])
1224                 end
1225           end
1226       nbos = ["nao", "nbo", "nho", "nlmo", "pnao", "pnbo", "pnho", "pnlmo"]
1227           layout(4,
1228                 item(:text, :title=>"SCF type"),
1229                 item(:popup, :subitems=>["RHF", "ROHF", "UHF"], :tag=>"scftype"),
1230             item(:text, :title=>"Run type"),
1231                 item(:popup, :subitems=>["Energy", "Property", "Optimize"], :tag=>"runtype",
1232                   :action=>lambda { |it| set_attr("use_internal", :enabled=>(it[:value] == 2)) } ),
1233         item(:checkbox, :title=>"Use internal coordinates for structure optimization", :tag=>"use_internal"),
1234         -1, -1, -1,
1235                 item(:checkbox, :title=>"Eliminate translation and rotational degrees of freedom", :tag=>"eliminate_freedom"),
1236                 -1, -1, -1,
1237
1238                 item(:text, :title=>"Charge"),
1239                 item(:textfield, :width=>80, :tag=>"charge"),
1240                 item(:text, :title=>"Multiplicity"),
1241                 item(:textfield, :width=>80, :tag=>"mult"),
1242
1243                 item(:checkbox, :title=>"Use DFT", :tag=>"dft",
1244                   :action=>lambda { |it| set_attr("dfttype", :enabled=>(it[:value] != 0)) } ),
1245                 -1,
1246                 item(:text, :title=>"DFT type"),
1247                 item(:popup, :subitems=>dft_desc, :tag=>"dfttype"),
1248                 
1249                 item(:line),
1250                 -1, -1, -1,
1251
1252                 item(:text, :title=>"Basis set"),
1253                 item(:popup, :subitems=>bset_desc + ["(no select)"], :tag=>"basis"),
1254                 -1,
1255                 -1,
1256
1257                 item(:button, :title=>"Load Basis Set...", :action=>:load_basis_set_sub),
1258                 -1, -1, -1,
1259                 
1260                 item(:checkbox, :title=>"Use secondary basis set", :tag=>"use_secondary_basis",
1261                   :action=>lambda { |it|
1262                     flag = (it[:value] != 0)
1263                         set_attr("secondary_elements", :enabled=>flag)
1264                         set_attr("secondary_basis", :enabled=>flag)
1265                   }),
1266                 -1, -1, -1,
1267
1268                 item(:text, :title=>"   Elements"),
1269                 item(:textfield, :width=>80, :tag=>"secondary_elements"),
1270                 item(:text, :title=>"Basis set"),
1271                 item(:popup, :subitems=>bset_desc, :tag=>"secondary_basis"),
1272                 
1273                 item(:line),
1274                 -1, -1, -1,
1275                 
1276                 item(:checkbox, :title=>"Calculate electrostatic potential (ESP)", :tag=>"esp"),
1277                 -1, -1, -1,
1278         
1279         item(:line),
1280         -1, -1, -1,
1281
1282         item(:checkbox, :title=>"Include NBO instructions", :tag=>"include_nbo",
1283              :action=>lambda { |it|
1284                flag = (it[:value] != 0)
1285                nbos.each { |nbo| set_attr(nbo, :enabled=>flag) }
1286              }),
1287         -1, -1, -1,
1288         item(:checkbox, :title=>"NAO", :tag=>"nao"),
1289         item(:checkbox, :title=>"NBO", :tag=>"nbo"),
1290         item(:checkbox, :title=>"NHO", :tag=>"nho"),
1291         item(:checkbox, :title=>"NLMO", :tag=>"nlmo"),
1292         item(:checkbox, :title=>"PNAO", :tag=>"pnao"),
1293         item(:checkbox, :title=>"PNBO", :tag=>"pnbo"),
1294         item(:checkbox, :title=>"PNHO", :tag=>"pnho"),
1295         item(:checkbox, :title=>"PNLMO", :tag=>"pnlmo"),
1296              
1297         item(:line),
1298                 -1, -1, -1,
1299                 
1300                 item(:checkbox, :title=>"Execute GAMESS on this machine", :tag=>"execute_local",
1301                   :action=>lambda { |it|
1302                     flag = (it[:value] != 0)
1303                         set_attr("executable_path", :enabled=>flag)
1304                         set_attr("select_path", :enabled=>flag)
1305                         set_attr("ncpus", :enabled=>flag)
1306                   }),
1307                 -1, -1, -1,
1308
1309                 item(:text, :title=>"   Path"),
1310                 item(:textfield, :width=>300, :tag=>"executable_path"),
1311                 -1, -1,
1312                 
1313                 -1,
1314                 item(:button, :title=>"Select Path...", :tag=>"select_path", :action=>:select_gamess_path),
1315                 -1,
1316                 item(:button, :title=>"Optional Scripts...", :action=>:set_optional_scripts),
1317                 
1318                 item(:text, :title=>"   N of CPUs"),
1319                 item(:textfield, :width=>80, :tag=>"ncpus"),
1320                 -1, -1,
1321                 
1322                 item(:line),
1323                 -1, -1, -1,
1324
1325                 item(:button, :title=>"Edit GAMESS Input and Go", :action=>lambda { |it|
1326                   h = Hash.new
1327                   each_item { |it2|
1328                     if (tag = it2[:tag]) != nil
1329                           h[tag] = it2[:value]
1330                         end
1331                   }
1332                   h["basis"] = $gamess_basis_keys[h["basis"]]
1333                   h["secondary_basis"] = $gamess_basis_keys[h["secondary_basis"]]
1334                   h["dfttype"] = dft_internal[h["dfttype"]]
1335                   gamess_input_direct = mol.cmd_edit_gamess_input(mol.export_gamess(nil, h))
1336                   if gamess_input_direct
1337                         end_modal(0)
1338                   end
1339                 }),
1340                 -1, -1, -1
1341           )
1342           values = Hash.new
1343           each_item { |it|
1344             tag = it[:tag]
1345                 if tag
1346                   values[tag] = (user_input[tag] || get_global_settings("gamess.#{tag}") || defaults[tag])
1347                   if tag == "basis" && values[tag] == "-1"
1348                     values[tag] = (bset_desc.count).to_s
1349                   end
1350                   it[:value] = values[tag]
1351                 end
1352           }
1353           set_attr("secondary_elements", :enabled=>(values["use_secondary_basis"] == 1))
1354           set_attr("secondary_basis", :enabled=>(values["use_secondary_basis"] == 1))
1355           set_attr("dfttype", :enabled=>(values["dft"] == 1))
1356           set_attr("use_internal", :enabled=>(values["runtype"] == 2))
1357           set_attr("executable_path", :enabled=>(values["execute_local"] == 1))
1358           set_attr("select_path", :enabled=>(values["execute_local"] == 1))
1359           set_attr("ncpus", :enabled=>(values["execute_local"] == 1))
1360       nbos.each { |nao|
1361         set_attr(nao, :enabled=>(values["include_nbo"] == 1))
1362       }
1363         }
1364         hash.each_pair { |key, value|
1365           next if key == :status
1366           set_global_settings("gamess.#{key}", value)
1367         }
1368         if hash[:status] == 0
1369           #  Specify basis by internal keys
1370           hash["basis"] = $gamess_basis_keys[hash["basis"]]
1371           hash["secondary_basis"] = $gamess_basis_keys[hash["secondary_basis"]]
1372           hash["dfttype"] = dft_internal[hash["dfttype"]]
1373           basename = (self.path ? File.basename(self.path, ".*") : self.name)
1374           fname = Dialog.save_panel("Export GAMESS input file:", self.dir, basename + ".inp", "GAMESS input file (*.inp)|*.inp|All files|*.*")
1375           return nil if !fname
1376           if gamess_input_direct
1377           #  puts "gamess_input_direct = \"#{gamess_input_direct}\""
1378             File.open(fname, "w") { |fp| fp.print(gamess_input_direct) }
1379           else
1380             export_gamess(fname, hash)
1381           end
1382           if hash["execute_local"] == 1
1383             Molecule.execute_gamess(fname, self)
1384           end
1385         else
1386           nil
1387         end
1388         
1389   end
1390   
1391   def cmd_create_cube
1392     grid = default_MO_grid
1393         if grid == nil
1394           Dialog.run {
1395             layout(1,
1396                   item(:text, :title=>"This molecule does not contain MO information."))
1397           }
1398           return
1399         end
1400
1401     mos = selected_MO
1402         if mos == nil || mos.length == 0
1403       Dialog.run {
1404             layout(1,
1405                   item(:text, :title=>"Please select MO(s) in the MO Info table."))
1406       }
1407           return
1408         end
1409         hash = Dialog.run {
1410           layout(1,
1411             item(:text, :title=>"Please specify cube dimensions (in angstrom units):"),
1412             layout(4,
1413                   item(:text, :title=>"Origin"),
1414                   item(:textfield, :width=>100, :height=>20, :tag=>"originx", :value=>sprintf("%.6f", grid[0].x)),
1415                   item(:textfield, :width=>100, :height=>20, :tag=>"originy", :value=>sprintf("%.6f", grid[0].y)),
1416                   item(:textfield, :width=>100, :height=>20, :tag=>"originz", :value=>sprintf("%.6f", grid[0].z)),
1417                   item(:text, :title=>"Delta"),
1418                   item(:textfield, :width=>100, :height=>20, :tag=>"deltax", :value=>sprintf("%.6f", grid[1])),
1419                   item(:textfield, :width=>100, :height=>20, :tag=>"deltay", :value=>sprintf("%.6f", grid[2])),
1420                   item(:textfield, :width=>100, :height=>20, :tag=>"deltaz", :value=>sprintf("%.6f", grid[3])),
1421                   item(:text, :title=>"Step"),
1422                   item(:textfield, :width=>100, :height=>20, :tag=>"stepx", :value=>grid[4].to_s),
1423                   item(:textfield, :width=>100, :height=>20, :tag=>"stepy", :value=>grid[5].to_s),
1424                   item(:textfield, :width=>100, :height=>20, :tag=>"stepz", :value=>grid[6].to_s)))
1425         }
1426         if hash[:status] == 0
1427           path = self.path || self.name
1428           dir = self.dir || Dir.pwd
1429           origin = Vector3D[hash["originx"], hash["originy"], hash["originz"]]
1430           dx = hash["deltax"]
1431           dy = hash["deltay"]
1432           dz = hash["deltaz"]
1433           nx = hash["stepx"]
1434           ny = hash["stepy"]
1435           nz = hash["stepz"]
1436           basename = File.basename(path, ".*")
1437           filenames = []
1438           mo_type = self.mo_type
1439           mos.each { |n|
1440             fname1 = fname2 = nil
1441             alpha = (mo_type != "UHF" ? "" : "alpha ")
1442                 a = (mo_type != "UHF" ? "" : "a")
1443             fname1 = Dialog.save_panel("Cube file name for #{alpha}MO #{n}", dir, basename + "_#{n}#{a}.cube", "Gaussian cube file (*.cube)|*.cube")
1444                 if (mo_type == "UHF")
1445                   fname2 = Dialog.save_panel("Cube file name for beta MO #{n}", dir, basename + "_#{n}b.cube", "Gaussian cube file (*.cube)|*.cube")
1446                 end
1447                 filenames.push([n, fname1, fname2])
1448           }
1449           filenames.each { |pair|
1450             n = pair[0]
1451                 alpha = (mo_type != "UHF" ? "" : "alpha ")
1452             show_progress_panel("Creating cube file for #{alpha}MO #{n}...")
1453                 if pair[1]
1454                   cubegen(pair[1], n, origin, dx, dy, dz, nx, ny, nz, true)
1455                 end
1456                 if pair[2] && mo_type == "UHF"
1457                   set_progress_message("Creating cube file for beta MO #{n}...")
1458                   cubegen(pair[2], n, origin, dx, dy, dz, nx, ny, nz, true, true)
1459                 end
1460             hide_progress_panel
1461           }
1462         end
1463   end
1464
1465 end
1466
1467 $gamess_basis = {
1468   "PM3"   => " PM3 0\n",
1469   "STO3G" => " STO 3\n",
1470   "321G"  => " N21 3\n",
1471   "631G"  => " N31 6\n" }
1472 $gamess_basis_desc = {
1473   "PM3"   => "PM3",
1474   "STO3G" => "STO-3G",
1475   "321G"  => "3-21G",
1476   "631G"  => "6-31G" }
1477 $gamess_basis_keys = ["PM3", "STO3G", "321G", "631G"]
1478
1479 ["631Gd", "631Gdp", "631+Gd", "631++Gdp", "6311Gdp", "6311+Gd", "6311++Gdp", "6311++G2d2p", "6311++G3df3pd", "LanL2DZ"].each { |n|
1480   Molecule.read_gamess_basis_sets("basis_sets/#{n}.txt")
1481 }
1482
1483 register_menu("QChem\tCreate GAMESS Input...",
1484   :cmd_create_gamess_input, :non_empty)
1485 register_menu("QChem\tCreate MOPAC6 Input...",
1486   :cmd_create_mopac_input, :non_empty)    # mopac6.rb
1487 register_menu("QChem\tCreate MO Cube...",
1488   :cmd_create_cube, lambda { |m| m && m.mo_type } )