4 # Created by Toshi Nagata on 2009/11/22.
5 # Copyright 2009 Toshi Nagata. All rights reserved.
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation version 2 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
33 # Import nbo log. The argument is either an array of Strings
35 def import_nbo_log(lines)
37 getline = lambda { lines.gets }
39 getline = lambda { lines.shift }
42 while (ln = getline.call) != nil
43 if ln =~ /done with NBO analysis/
46 if ln =~ /NATURAL POPULATIONS: Natural atomic orbital occupancies/
52 while (ln = getline.call) != nil
57 # Double blank lines indicates the end of the table
62 next unless ln =~ /^ *(\d+) *([A-Za-z]+) *(\d+) *([a-z]+) +([A-Za-z]+)\( *(\d+)([a-z]+)\)/
65 atom_label = $2 + $3.to_s
69 vals = $~.post_match.split.map { |e| e.to_f }
70 # atom_index, type, pn+label, occupancy[, energy]
71 nbo["nao"].push([atom_label, type, pn + label] + vals)
73 elsif ln =~ / NATURAL BOND ORBITALS \(Summary\):/
76 while (ln = getline.call) != nil
77 break if ln =~ /Total Lewis/
82 # Double blank lines indicates the end of the table
86 if ln =~ /^\s*(\d+)\. *([A-Za-z]+\*?) *\( *(\d+)\) *([A-Za-z]+) *(\d+)(- *([A-Za-z]+) *(\d+))? *(\d\.\d+)/
90 atom_label = $4 + ($5.to_i - 1).to_s
92 atom_label += "-" + $7 + ($8.to_i - 1).to_s
95 nbo["nbo"].push([orb_kind + "_" + orb_idx, atom_label, occ])
98 elsif ln =~ /([A-Z]+)s in the ([A-Z]+) basis:/ || ln =~ /([A-Z]+) Fock matrix:/
105 key = src + "/" + dst
113 while (ln = getline.call) != nil
115 # Blank line: end of one block
118 # Double blank lines indicates the end of the table
130 lab = $~.pre_match.strip
131 a = ([$~[0]] + $~.post_match.split).map { |e| e.to_f }
133 lab =~ /^[0-9]+\. *(.*)$/
136 (elements[idx] ||= []).concat(a)
139 nbo[key] = LAMatrix.new(elements).transpose!
140 key2 = (src == "F" ? dst : src) + "_L"
148 # Convert NAO based matrix into AO based matrix
149 @nbo.keys.each { |key|
150 if key[0..3] == "NAO/"
151 key2 = "AO/" + key[4..-1]
152 @nbo[key2] = @nbo["AO/NAO"] * @nbo[key]
159 def Molecule.read_gamess_basis_sets(fname)
160 # $gamess_basis = Hash.new unless $gamess_basis
161 $gamess_ecp = Hash.new unless $gamess_ecp
162 # $gamess_basis_desc = Hash.new unless $gamess_basis_desc
163 # $gamess_basis_keys = [] unless $gamess_basis_keys
164 basename = File.basename(fname, ".*")
167 File.open(fname, "r") { |fp|
169 if s =~ /^\s*!\s*/ && descname == nil
170 # Get the descriptive name from the first comment line
171 s = Regexp.last_match.post_match
173 descname = Regexp.last_match.pre_match
175 descname = (s.split)[0]
177 $gamess_basis_desc[basename] = descname
180 ss, bas = (s.split)[0..1] # Tokens delimited by whitespaces
181 next if ss == nil || ss == ""
183 # Read the ECP section
184 ecp = $gamess_ecp[basename]
187 $gamess_ecp[basename] = ecp
189 keys << basename unless keys.include?(basename)
192 ary = s.split # (PNAME, PTYPE, IZCORE, LMAX+1)
193 elem = ary[0].match(/\w{1,2}/).to_a[0] # ary[0] should begin with an element name
194 ap = Parameter.builtin.elements.find { |p| p.name.casecmp(elem) == 0 }
195 raise MolbyError, "the ECP definition does not begin with an element name: #{s}" if !ap
198 (0..Integer(ary[3])).each {
200 raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
202 ary = s.split # (NGPOT, comment)
204 (1..Integer(ary[0])).each {
206 raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
211 ecp[ap.index] = ecpdef
214 # Comments or other unrecognizable lines
216 elsif (ap = Parameter.builtin.elements.find { |p| p.name.casecmp(ss) == 0 || p.fullname.casecmp(ss) == 0 })
217 # Valid basis definition
218 if bas == nil || bas =~ /\W/
221 basis = $gamess_basis[bas]
224 $gamess_basis[bas] = basis
226 keys << bas unless keys.include?(bas)
228 while (s = fp.gets) && s =~ /\S/
231 basis[ap.index] = basdef
233 raise MolbyError, "ss is not a valid element symbol or name: #{s}"
237 unless $gamess_basis_keys.include?(basename)
238 $gamess_basis_keys.push(basename)
242 # Execute GAMESS (inferior copy of rungms script)
243 # inpname is the input file
244 # mol (optional) is the molecule from which the GAMESS input was built.
245 # If mol is specified and RUNTYP=OPTIMIZE, then the intermediate structures are
246 # displayed real-time.
247 def Molecule.execute_gamess(inpname, mol = nil)
248 gmsname = get_global_settings("gamess.executable_path")
252 cygwin_version = false # For windows: old cygwin version
255 if gmsname == nil || !File.exist?(gmsname)
256 gmsname = Dialog.open_panel("Please locate the GAMESS executable")
257 exit if gmsname == nil
259 gmsbase = File.basename(gmsname)
260 gmsdir = File.dirname(gmsname)
261 if gmsbase =~ /gamess\.(.*)\.(exe|x)$/i
266 error_message_box(gmsbase + " does not look like a GAMESS executable!")
271 # mol = Molecule.open(inpname)
273 # error_message_box("Cannot open #{inpname} as GAMESS input")
278 inpbase = File.basename(inpname)
279 inpdir = File.dirname(inpname)
280 inpbody = inpbase.sub(/\.inp$/, "")
281 logbase = inpbody + ".log"
283 set_global_settings("gamess.executable_path", gmsname)
285 ncpus = get_global_settings("gamess.ncpus").to_i
290 # Prepare the scratch directory
292 scrdir = create_temp_dir("gamess", inpbody)
294 error_message_box($!.to_s)
297 # scrdir = $home_directory + "/Molby/gamess"
299 # mkdir_recursive(scrdir)
301 # error_message_box("Cannot create directory #{scrdir}: " + $!.to_s)
305 # scrdir = scrdir + "/" + inpbody + "." + $$.to_s + ".0"
307 # while File.exist?(scrdir)
308 # scrdir = scrdir.sub(".#{n}", ".#{n + 1}")
313 if $platform == "win"
315 scrdir.gsub!("/", sep)
316 gmsdir.gsub!("/", sep)
321 # Old (obsolete) cygwin version, using ddikick
322 if $platform == "win"
324 cygwin_version = true
328 # Get the host name etc.
329 hostname = backquote("hostname").chomp
330 if $platform == "win"
331 s = backquote("cmd.exe /c dir \"#{scrdir}\"")
332 freebytes = s.split("\n").pop.match(/([0-9,]+)[^0-9]*$/).to_a[1]
334 freebytes = (freebytes.gsub(",","").to_i / 1024).to_s + " Kbytes"
336 freebytes = "(unknown)"
338 uname = backquote("cmd.exe /c ver").to_s.gsub("\n", "")
340 freebytes = `df -k "#{scrdir}"`
341 uname = `uname`.chomp
344 # Redirect standard output to the log file
345 logname = scrdir + sep + logbase
346 fpout = File.open(logname, "w")
348 # The cygwin version uses LF as the eol character
351 fpout.print "----- GAMESS execution script -----\n"
352 fpout.print "This job is running on host #{hostname}\n"
353 fpout.print "under operating system #{uname} at #{Time.now.to_s}\n"
354 fpout.print "Available scratch disk space (Kbyte units) at beginning of the job is\n"
355 fpout.print freebytes + "\n"
357 # Copy the input file
358 scrprefix = scrdir + sep + inpbody
359 if $platform == "win"
364 filecopy(inpname, scrprefix + ".F05")
365 File.open("#{scrdir}/.in_use", "w") { |fp| }
367 # Prepare environmental variables
368 auxdir = "#{gmsdir}#{sep}auxdata"
369 ENV["ERICFMT"] = "#{auxdir}#{sep}ericfmt.dat"
370 ENV["MCPPATH"] = "#{auxdir}#{sep}MCP"
371 ENV["BASPATH"] = "#{auxdir}#{sep}BASES"
372 ENV["QUANPOL"] = "#{auxdir}#{sep}QUANPOL"
373 ENV["EXTBAS"] = "/dev/null"
374 ENV["IRCDATA"] = "#{scrbody}.irc"
375 ENV["RESTART"] = "#{scrbody}.rst"
376 ENV["TRAJECT"] = "#{scrbody}.trj"
377 ENV["PUNCH"] = "#{scrbody}.dat"
378 ENV["INPUT"] = "#{scrbody}.F05"
379 ENV["AOINTS"] = "#{scrbody}.F08"
380 ENV["MOINTS"] = "#{scrbody}.F09"
381 ENV["DICTNRY"] = "#{scrbody}.F10"
382 ENV["DRTFILE"] = "#{scrbody}.F11"
383 ENV["CIVECTR"] = "#{scrbody}.F12"
384 ENV["CASINTS"] = "#{scrbody}.F13"
385 ENV["CIINTS"] = "#{scrbody}.F14"
386 ENV["WORK15"] = "#{scrbody}.F15"
387 ENV["WORK16"] = "#{scrbody}.F16"
388 ENV["CSFSAVE"] = "#{scrbody}.F17"
389 ENV["FOCKDER"] = "#{scrbody}.F18"
390 ENV["WORK19"] = "#{scrbody}.F19"
391 ENV["DASORT"] = "#{scrbody}.F20"
392 ENV["DFTINTS"] = "#{scrbody}.F21"
393 ENV["DFTGRID"] = "#{scrbody}.F22"
394 ENV["JKFILE"] = "#{scrbody}.F23"
395 ENV["ORDINT"] = "#{scrbody}.F24"
396 ENV["EFPIND"] = "#{scrbody}.F25"
397 ENV["PCMDATA"] = "#{scrbody}.F26"
398 ENV["PCMINTS"] = "#{scrbody}.F27"
399 ENV["MLTPL"] = "#{scrbody}.F28"
400 ENV["MLTPLT"] = "#{scrbody}.F29"
401 ENV["DAFL30"] = "#{scrbody}.F30"
402 ENV["SOINTX"] = "#{scrbody}.F31"
403 ENV["SOINTY"] = "#{scrbody}.F32"
404 ENV["SOINTZ"] = "#{scrbody}.F33"
405 ENV["SORESC"] = "#{scrbody}.F34"
406 ENV["SIMEN"] = "#{scrbody}.simen"
407 ENV["SIMCOR"] = "#{scrbody}.simcor"
408 ENV["GCILIST"] = "#{scrbody}.F37"
409 ENV["HESSIAN"] = "#{scrbody}.F38"
410 ENV["SOCCDAT"] = "#{scrbody}.F40"
411 ENV["AABB41"] = "#{scrbody}.F41"
412 ENV["BBAA42"] = "#{scrbody}.F42"
413 ENV["BBBB43"] = "#{scrbody}.F43"
414 ENV["MCQD50"] = "#{scrbody}.F50"
415 ENV["MCQD51"] = "#{scrbody}.F51"
416 ENV["MCQD52"] = "#{scrbody}.F52"
417 ENV["MCQD53"] = "#{scrbody}.F53"
418 ENV["MCQD54"] = "#{scrbody}.F54"
419 ENV["MCQD55"] = "#{scrbody}.F55"
420 ENV["MCQD56"] = "#{scrbody}.F56"
421 ENV["MCQD57"] = "#{scrbody}.F57"
422 ENV["MCQD58"] = "#{scrbody}.F58"
423 ENV["MCQD59"] = "#{scrbody}.F59"
424 ENV["MCQD60"] = "#{scrbody}.F60"
425 ENV["MCQD61"] = "#{scrbody}.F61"
426 ENV["MCQD62"] = "#{scrbody}.F62"
427 ENV["MCQD63"] = "#{scrbody}.F63"
428 ENV["MCQD64"] = "#{scrbody}.F64"
429 ENV["NMRINT1"] = "#{scrbody}.F61"
430 ENV["NMRINT2"] = "#{scrbody}.F62"
431 ENV["NMRINT3"] = "#{scrbody}.F63"
432 ENV["NMRINT4"] = "#{scrbody}.F64"
433 ENV["NMRINT5"] = "#{scrbody}.F65"
434 ENV["NMRINT6"] = "#{scrbody}.F66"
435 ENV["DCPHFH2"] = "#{scrbody}.F67"
436 ENV["DCPHF21"] = "#{scrbody}.F68"
437 ENV["GVVPT"] = "#{scrbody}.F69"
439 # next files are used only during coupled cluster runs, so let's
440 # display the numerous definitions only if they are to be used.
441 # Don't set these variables on windows, where the memory for environmental variables
443 if $platform != "win"
444 ENV["CCREST"] = "#{scrbody}.F70"
445 ENV["CCDIIS"] = "#{scrbody}.F71"
446 ENV["CCINTS"] = "#{scrbody}.F72"
447 ENV["CCT1AMP"] = "#{scrbody}.F73"
448 ENV["CCT2AMP"] = "#{scrbody}.F74"
449 ENV["CCT3AMP"] = "#{scrbody}.F75"
450 ENV["CCVM"] = "#{scrbody}.F76"
451 ENV["CCVE"] = "#{scrbody}.F77"
452 ENV["EOMSTAR"] = "#{scrbody}.F80"
453 ENV["EOMVEC1"] = "#{scrbody}.F81"
454 ENV["EOMVEC2"] = "#{scrbody}.F82"
455 ENV["EOMHC1"] = "#{scrbody}.F83"
456 ENV["EOMHC2"] = "#{scrbody}.F84"
457 ENV["EOMHHHH"] = "#{scrbody}.F85"
458 ENV["EOMPPPP"] = "#{scrbody}.F86"
459 ENV["EOMRAMP"] = "#{scrbody}.F87"
460 ENV["EOMRTMP"] = "#{scrbody}.F88"
461 ENV["EOMDG12"] = "#{scrbody}.F89"
462 ENV["MMPP"] = "#{scrbody}.F90"
463 ENV["MMHPP"] = "#{scrbody}.F91"
464 ENV["MMCIVEC"] = "#{scrbody}.F92"
465 ENV["MMCIVC1"] = "#{scrbody}.F93"
466 ENV["MMCIITR"] = "#{scrbody}.F94"
467 ENV["MMNEXM"] = "#{scrbody}.F95"
468 ENV["MMNEXE"] = "#{scrbody}.F96"
469 ENV["MMNREXM"] = "#{scrbody}.F97"
470 ENV["MMNREXE"] = "#{scrbody}.F98"
473 # next are for TDHFX code, not used by current GAMESS
476 ENV["OLI201"] = "#{scrbody}.F201"
477 ENV["OLI202"] = "#{scrbody}.F202"
478 ENV["OLI203"] = "#{scrbody}.F203"
479 ENV["OLI204"] = "#{scrbody}.F204"
480 ENV["OLI205"] = "#{scrbody}.F205"
481 ENV["OLI206"] = "#{scrbody}.F206"
482 ENV["OLI207"] = "#{scrbody}.F207"
483 ENV["OLI208"] = "#{scrbody}.F208"
484 ENV["OLI209"] = "#{scrbody}.F209"
485 ENV["OLI210"] = "#{scrbody}.F210"
486 ENV["OLI211"] = "#{scrbody}.F211"
487 ENV["OLI212"] = "#{scrbody}.F212"
488 ENV["OLI213"] = "#{scrbody}.F213"
489 ENV["OLI214"] = "#{scrbody}.F214"
490 ENV["OLI215"] = "#{scrbody}.F215"
491 ENV["OLI216"] = "#{scrbody}.F216"
492 ENV["OLI217"] = "#{scrbody}.F217"
493 ENV["OLI218"] = "#{scrbody}.F218"
494 ENV["OLI219"] = "#{scrbody}.F219"
495 ENV["OLI220"] = "#{scrbody}.F220"
496 ENV["OLI221"] = "#{scrbody}.F221"
497 ENV["OLI222"] = "#{scrbody}.F222"
498 ENV["OLI223"] = "#{scrbody}.F223"
499 ENV["OLI224"] = "#{scrbody}.F224"
500 ENV["OLI225"] = "#{scrbody}.F225"
501 ENV["OLI226"] = "#{scrbody}.F226"
502 ENV["OLI227"] = "#{scrbody}.F227"
503 ENV["OLI228"] = "#{scrbody}.F228"
504 ENV["OLI229"] = "#{scrbody}.F229"
505 ENV["OLI230"] = "#{scrbody}.F230"
506 ENV["OLI231"] = "#{scrbody}.F231"
507 ENV["OLI232"] = "#{scrbody}.F232"
508 ENV["OLI233"] = "#{scrbody}.F233"
509 ENV["OLI234"] = "#{scrbody}.F234"
510 ENV["OLI235"] = "#{scrbody}.F235"
511 ENV["OLI236"] = "#{scrbody}.F236"
512 ENV["OLI237"] = "#{scrbody}.F237"
513 ENV["OLI238"] = "#{scrbody}.F238"
514 ENV["OLI239"] = "#{scrbody}.F239"
517 if $platform == "win"
522 # Old (obsolete) cygwin version, using ddikick
523 fpout.print "ddikick will run #{ncpus} compute process\n"
524 ENV["CYGWIN"] = "nodosfilewarning"
526 fpout.print "Microsoft MPI will be running GAMESS on 1 node.\n"
527 fpout.print "The binary kicked off by 'mpiexec' is gamess.#{gmsvers}.exe\n"
528 fpout.print "MS-MPI will run #{ncpus*2} compute process\n"
529 # File containing environmental variables
530 envfil = "#{scrprefix}.GMS.ENV"
531 fp = File.open(envfil, "w")
532 ENV.each { |k, v| fp.print "#{k}=#{v}\n" }
534 # File containing arguments to mpiexec
535 procfil = "#{scrprefix}.processes.mpd"
536 fp = File.open(procfil, "w")
537 fp.print "-env ENVFIL \"#{envfil}\" -wdir \"#{scrdir}\" -n #{ncpus*2} \"#{gmsdir}#{sep}gamess.#{gmsvers}.exe\"\n"
543 fplog = File.open(logname, "r")
551 ne_alpha = ne_beta = 0
556 term_callback = lambda { |m, n|
557 msg = "GAMESS execution on #{inpbase} "
564 msg += "failed with status #{n}."
568 msg += "\n(In directory #{inpdir})"
570 File.delete("#{scrdir}/.in_use")
572 ext_to_keep = [".dat", ".rst", ".trj", ".efp", ".gamma", ".log"]
573 ext_to_keep.each { |ex|
574 if File.exists?("#{scrprefix}#{ex}")
575 filecopy("#{scrprefix}#{ex}", "#{inpdir}#{sep}#{inpbody}#{ex}")
578 Dir.foreach(scrdir) { |file|
579 if file != "." && file != ".." && !ext_to_keep.include?(File.extname(file))
580 File.delete("#{scrdir}#{sep}#{file}")
585 erase_old_logs(scrdir, "latest", 5)
587 error_message_box($!.to_s)
591 if (script = get_global_settings("gamess.postfix_script")) != nil && script != ""
596 message_box(msg, hmsg, :ok, icon)
600 timer_callback = lambda { |m, n|
601 fplog.seek(0, IO::SEEK_END)
605 fplog.seek(size, IO::SEEK_SET)
606 fplog.each_line { |line|
607 if line[-1, 1] == "\n"
608 lines.push(last_line + line)
618 while i < lines.count
620 if line =~ /GEOMETRY SEARCH POINT NSERCH= *(\d+)/
625 elsif line =~ /START OF DRC CALCULATION/
629 elsif line =~ /CONSTRAINED OPTIMIZATION POINT/
632 elsif line =~ /POINT *([0-9]+) *ON THE REACTION PATH/
635 elsif line =~ /ATOMIC BASIS SET/
637 while j < lines.count
639 break if line =~ /TOTAL NUMBER OF BASIS SET/
647 bs_lines.push(lines[ii].chomp)
652 ncomps = mol.sub_load_gamess_log_basis_set(bs_lines, lineno + i)
656 puts $!.backtrace.inspect
660 break # Wait until all basis set lines are read
662 elsif line =~ /NUMBER OF OCCUPIED ORBITALS/
670 elsif line =~ /SCFTYP=(\w+)/
672 if ne_alpha > 0 || ne_beta > 0
681 elsif line =~ /^\s*(EIGENVECTORS|MOLECULAR ORBITALS)\s*$/
682 if mo_count == 0 && mol
683 mol.clear_mo_coefficients
684 mol.set_mo_info(:type=>["UHF", "RHF", "ROHF"][rflag], :alpha=>ne_alpha, :beta=>ne_beta)
689 while j < lines.count
691 break if line =~ /\.\.\.\.\.\./ || line =~ /----------------/
695 break # Wait until complete MO info are read
700 mo_lines.push(lines[ii].chomp)
705 mol.sub_load_gamess_log_mo_coefficients(mo_lines, lineno + i, ncomps)
709 puts $!.backtrace.inspect
712 elsif line =~ /NSERCH: *([0-9]+)/
716 line =~ /E= +([-.0-9]+)/
718 line =~ /GRAD\. MAX= +([-.0-9]+)/
720 mol.show_text("Search: #{n}\nGradient: #{grad}")
721 # mol.set_property("energy", energy)
724 elsif line =~ /TOTAL ENERGY += *([-.0-9]+)/
726 if mol && search_mode == 2
727 mol.show_text("Point: #{nserch}\nEnergy: #{energy}")
730 elsif line =~ /FINAL .* ENERGY IS +([-.0-9]+) *AFTER/
732 if mol && search_mode == 0
733 mol.set_property("energy", energy)
735 elsif nserch > 0 && line =~ /ddikick\.x/
738 elsif mol && nserch > 0 && (line =~ /COORDINATES OF ALL ATOMS/ || line =~ /COORDINATES \(IN ANGSTROM\) FOR \$DATA GROUP ARE/)
739 # There should be (natoms) lines
740 if line =~ /COORDINATES OF ALL ATOMS/
744 if i + mol.natoms + 1 <= lines.count
746 (i + 1...i + 1 + mol.natoms).each { |j|
747 name, charge, x, y, z = lines[j].split
748 coords.push(Vector3D[x.to_f, y.to_f, z.to_f])
750 mol.create_frame([coords])
751 if search_mode == 1 && energy
752 mol.set_property("energy", energy)
755 last_i = i + mol.natoms
756 i = last_i # Skip the processed lines
758 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/
761 while j < lines.count
762 break if lines[j] =~ /done with NBO analysis/
766 nbo_lines = lines[i..j]
767 mol.import_nbo_log(nbo_lines) rescue puts "Error: #{$!}, #{$!.backtrace.inspect}"
769 i = last_i # Skip the processed lines
771 break # Wait until NBO is done
780 lines[0..last_i] = nil
787 if (script = get_global_settings("gamess.prefix_script")) != nil && script != ""
791 if $platform == "win"
793 hosts = "localhost " * ncpus
794 cmdline = "cmd.exe /c \"#{gmsdir}/ddikick.exe #{gmsdir}/gamess.#{gmsvers}.exe #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < NUL >>#{logname}"
796 cmdline = "cmd.exe /c \"mpiexec -configfile #{procfil} >>#{logname}"
799 hosts = "localhost " * ncpus
800 cmdline = "/bin/sh -c '#{gmsdir}/ddikick.x #{gmsdir}/gamess.#{gmsvers}.x #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < /dev/null >>#{logname}'"
804 pid = mol.call_subprocess_async(cmdline, term_callback, timer_callback)
806 error_message_box("GAMESS failed to start. Please examine GAMESS installation.")
810 pid = call_subprocess(cmdline, "Running GAMESS")
811 term_callback.call(nil, pid)
817 def export_gamess(fname, hash)
819 def reorder_array(ary, ordered_sub_ary)
820 return (ordered_sub_ary & ary) + (ary - ordered_sub_ary)
825 basename = File.basename(fname, ".*")
827 basename = File.basename(self.name, ".*")
831 icharg = hash["charge"]
833 runtyp = ["ENERGY", "PROP", "OPTIMIZE"][hash["runtype"].to_i]
834 scftyp = ["RHF", "ROHF", "UHF"][hash["scftype"].to_i]
835 bssname = hash["basis"]
836 bssname2 = hash["secondary_basis"]
837 if hash["use_secondary_basis"].to_i != 0 && bssname2 != bssname
839 element2 = hash["secondary_elements"].split(/[\s,]+/).map { |name| name.capitalize }
844 basis = $gamess_basis[bssname]
845 basis2 = $gamess_basis[bssname2]
847 # Use effective core potentials?
848 ecp = $gamess_ecp[bssname]
849 ecp2 = $gamess_ecp[bssname2]
850 ecp_read = (ecp || ecp2 ? "ECP=READ " : "")
852 # Use only one built-in basis set?
857 gbasis = "PM3 NGAUSS=3"
859 gbasis = "STO NGAUSS=3"
861 gbasis = "N21 NGAUSS=3"
863 gbasis = "N31 NGAUSS=6"
865 gbasis = "N31 NGAUSS=6 NDFUNC=1"
867 gbasis = "N31 NGAUSS=6 NDFUNC=1 NPFUNC=1"
869 gbasis = "N311 NGAUSS=6"
871 gbasis = "N311 NGAUSS=6 NDFUNC=1 NPFUNC=1"
875 # Count non-dummy atoms
878 natoms += 1 if ap.atomic_number != 0
881 # Fill hash with default values
882 h = (hash["CONTRL"] ||= Hash.new)
883 h["COORD"] ||= "UNIQUE"
884 h["EXETYP"] ||= "RUN"
885 h["ICHARG"] ||= (icharg || 0).to_s
887 h["INTTYP"] ||= "HONDO"
890 h["MOLPLT"] ||= ".T."
892 h["MULT"] ||= mult.to_s
893 h["QMTTOL"] ||= "1e-08"
894 h["RUNTYP"] ||= runtyp
895 if (hash["dft"] || 0) != 0 && hash["dfttype"]
896 h["DFTTYP"] ||= hash["dfttype"]
898 if (hash["use_internal"] || 0) != 0 && (hash["runtype"] == 2 || h["RUNTYP"] == "OPTIMIZE")
899 nzvar = natoms * 3 - 6 # TODO: 3N-5 for linear molecules
900 h["NZVAR"] ||= nzvar.to_s
904 h["SCFTYP"] ||= scftyp
908 h["UNITS"] ||= "ANGS"
910 h = (hash["SCF"] ||= Hash.new)
911 h["CONV"] ||= "1.0E-06"
912 h["DIRSCF"] ||= ".T."
916 h = (hash["STATPT"] ||= Hash.new)
918 h["OPTTOL"] ||= "1.0E-06"
920 h = (hash["SYSTEM"] ||= Hash.new)
923 h["TIMLIM"] ||= "50000"
925 h = (hash["GUESS"] ||= Hash.new)
926 h["GUESS"] ||= "HUCKEL"
929 h = (hash["BASIS"] ||= Hash.new)
930 h["GBASIS"] ||= gbasis
934 h = (hash["ZMAT"] ||= Hash.new)
939 if (hash["esp"] || 0) != 0
940 h = (hash["ELPOT"] ||= Hash.new)
942 h["OUTPUT"] ||= "PUNCH"
944 h = (hash["PDC"] ||= Hash.new)
945 h["CONSTR"] ||= "NONE"
946 h["PTSEL"] ||= "CONNOLLY"
950 fp = File.open(fname, "wb")
955 fp.print "! GAMESS input\n"
956 fp.print "! Generated by Molby at #{now}\n"
957 fp.print "! Basis set: " + ($gamess_basis_desc[bssname] || "(not specified)") + "\n"
959 fp.print "! [" + element2.join(", ") + "]: " + ($gamess_basis_desc[bssname2] || "(not specified)") + "\n"
961 ordered = ["CONTRL", "SCF", "STATPT", "SYSTEM", "GUESS", "BASIS", "ZMAT", "ELPOT", "PDC"]
962 controls = reorder_array(hash.keys.select { |k| k != "key_order" && hash[k].is_a?(Hash) },
963 hash["key_order"] || ordered)
966 next if h == nil || h.size == 0 || (h["key_order"] && h.size == 1)
968 ordered = ["COORD", "EXETYP", "ICHARG", "ICUT", "INTTYP", "ITOL", "MAXIT", "MOLPLT", "MPLEVL",
969 "MULT", "QMTTOL", "RUNTYP", "SCFTYP", "ECP", "UNITS", "DFTTYP", "NZVAR"]
971 ordered = ["CONV", "DIRSCF", "FDIFF", "DAMP"]
973 ordered = ["NSTEP", "OPTTOL"]
975 ordered = ["MEMDDI", "MWORDS", "TIMLIM"]
981 ordered = ["DLC", "AUTO"]
983 ordered = ["IEPOT", "OUTPUT", "WHERE"]
985 ordered = ["CONSTR", "PTSEL"]
989 keys = reorder_array(h.keys, h["key_order"] || ordered)
991 keys.each_with_index { |kk, i|
994 fp.printf " $%-6s", k
998 if v == nil || v == ""
1002 fp.printf " %s=%s", kk, h[kk].to_s
1010 fp.print " $DATA\n#{basename}\nC1 0\n"
1013 next if ap.atomic_number == 0
1014 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
1015 if use_2nd && element2.include?(ap.element)
1016 secondary[ap.index] = true
1019 # Basis specification followed by a blank line
1020 bas = (secondary[ap.index] ? basis2 : basis)
1022 bas = bas[ap.atomic_number]
1028 puts "Warning: basis set is not defined for atom #{ap.index}, element #{ap.element}"
1037 an = ap.atomic_number
1039 ecpp = (secondary[ap.index] ? ecp2 : ecp)
1040 e = ecp_ary[an] || (ecpp && ecpp[an])
1042 # Cache the PNAME of the $ECP entry and re-use it
1043 ecp_ary[an] ||= (e.split)[0] + "\n"
1045 e = ap.element.upcase + "-ECP NONE\n"
1062 def cmd_edit_gamess_input(s)
1063 h = Dialog.run("Edit GAMESS Input", "OK", "Cancel", :resizable=>true) {
1065 item(:textview, :value=>s, :tag=>"edit", :width=>400, :height=>400, :flex=>[0,0,0,0,1,1]),
1066 :flex=>[0,0,0,0,1,1]
1068 set_min_size(300, 300)
1077 def cmd_create_gamess_input
1082 raise MolbyError, "cannot create GAMESS input; the molecule is empty"
1085 # Descriptive text and internal string for popup menus
1086 # bset_desc = ["PM3", "STO-3G", "3-21G", "6-31G", "6-31G(d)", "6-31G(d,p)", "6-311G", "6-311G(d,p)", "LanL2DZ"]
1087 # bset_internal = ["PM3", "STO3G", "321G", "631G", "631Gd", "631Gdp", "6311G", "6311Gdp", "LanL2DZ"]
1088 bset_desc = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
1089 dft_desc = ["B3LYP"]
1090 dft_internal = ["B3LYP"]
1092 defaults = {"scftype"=>0, "runtype"=>0, "charge"=>"0", "mult"=>"1",
1093 "basis"=>4, "use_secondary_basis"=>0, "secondary_elements"=>"",
1094 "secondary_basis"=>8, "esp"=>0, "ncpus"=>"1"}
1096 gamess_input_direct = nil
1098 user_input = Hash.new
1099 ["CONTRL", "SCF", "STATPT", "SYSTEM", "GUESS", "BASIS"].each { |k|
1100 user_input[k] = Hash.new
1102 if ".inp".casecmp(self.name[-4, 4]) == 0
1103 # Read input and analyze commands
1104 fp = open(self.path, "r")
1109 break if "$DATA".casecmp(ln[0, 5]) == 0
1113 key = s[1..-1].upcase
1114 hh = user_input[key] = Hash.new
1115 (user_input["key_order"] ||= []).push(key)
1121 (hh["key_order"] ||= []).push(k)
1127 user_input["charge"] = user_input["CONTRL"]["ICHARG"]
1128 user_input["mult"] = user_input["CONTRL"]["MULT"]
1129 user_input["runtype"] = ((i = ["ENERGY", "PROP", "OPTIMIZE"].find_index(user_input["CONTRL"]["RUNTYP"])) ? i.to_s : nil)
1130 user_input["scftype"] = ((i = ["RHF", "ROHF", "UHF"].find_index(user_input["CONTRL"]["SCFTYP"])) ? i.to_s : nil)
1131 dft_type = dft_internal.find_index(user_input["CONTRL"]["DFTTYP"])
1133 user_input["dfttype"] = dft_type.to_s
1134 user_input["dft"] = 1
1137 user_input["basis"] = "-1"
1138 case user_input["BASIS"]["GBASIS"]
1146 if user_input["NDFUNC"] == "1"
1147 if user_input["NPFUNC"] == "1"
1156 if user_input["NDFUNC"] == "1" && user_input["NPFUNC"] == "1"
1163 user_input["basis"] = $gamess_basis_keys.find_index(bssname).to_s
1165 # puts user_input.inspect
1169 hash = Dialog.run("GAMESS Export") {
1170 def load_basis_set_sub(item)
1171 fname = Dialog.open_panel("Select a file containing GAMESS basis set:")
1173 Molecule.read_gamess_basis_sets(fname)
1174 bset_desc_new = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
1175 sel1 = attr("basis", :value)
1176 sel2 = attr("secondary_basis", :value)
1177 set_attr("basis", :subitems=>bset_desc_new)
1178 set_attr("basis", :value=>sel1)
1179 set_attr("secondary_basis", :subitems=>bset_desc_new)
1180 set_attr("secondary_basis", :value=>sel2)
1183 def select_gamess_path(item)
1185 fname = Dialog.open_panel("Locate GAMESS executable:")
1186 return if fname == nil
1187 bname = File.basename(fname)
1188 if bname =~ /gamess\.(.*)\.(exe|x)$/i
1189 set_attr("executable_path", :value=>fname)
1192 error_message_box("\"#{bname}\" does not look like a GAMESS executable! Please try again.")
1196 def set_optional_scripts(item)
1197 h = Dialog.run("GAMESS Optional Scripts") {
1198 s_pre = get_global_settings("gamess.prefix_script")
1199 s_post = get_global_settings("gamess.postfix_script")
1201 item(:text, :title=>"Script to run before GAMESS execution:"),
1202 item(:textview, :width=>400, :height=>200, :value=>s_pre, :tag=>"prefix"),
1203 item(:text, :title=>"Script to run after GAMESS execution:"),
1204 item(:textview, :width=>400, :height=>200, :value=>s_pre, :tag=>"postfix"))
1207 set_global_settings("gamess.prefix_script", h["prefix"])
1208 set_global_settings("gamess.postfix_script", h["postfix"])
1212 item(:text, :title=>"SCF type"),
1213 item(:popup, :subitems=>["RHF", "ROHF", "UHF"], :tag=>"scftype"),
1214 item(:text, :title=>"Run type"),
1215 item(:popup, :subitems=>["Energy", "Property", "Optimize"], :tag=>"runtype",
1216 :action=>lambda { |it| set_attr("use_internal", :enabled=>(it[:value] == 2)) } ),
1218 item(:checkbox, :title=>"Use internal coordinates for structure optimization", :tag=>"use_internal"),
1221 item(:text, :title=>"Charge"),
1222 item(:textfield, :width=>80, :tag=>"charge"),
1223 item(:text, :title=>"Multiplicity"),
1224 item(:textfield, :width=>80, :tag=>"mult"),
1226 item(:checkbox, :title=>"Use DFT", :tag=>"dft",
1227 :action=>lambda { |it| set_attr("dfttype", :enabled=>(it[:value] != 0)) } ),
1229 item(:text, :title=>"DFT type"),
1230 item(:popup, :subitems=>dft_desc, :tag=>"dfttype"),
1235 item(:text, :title=>"Basis set"),
1236 item(:popup, :subitems=>bset_desc + ["(no select)"], :tag=>"basis"),
1240 item(:button, :title=>"Load Basis Set...", :action=>:load_basis_set_sub),
1243 item(:checkbox, :title=>"Use secondary basis set", :tag=>"use_secondary_basis",
1244 :action=>lambda { |it|
1245 flag = (it[:value] != 0)
1246 set_attr("secondary_elements", :enabled=>flag)
1247 set_attr("secondary_basis", :enabled=>flag)
1251 item(:text, :title=>" Elements"),
1252 item(:textfield, :width=>80, :tag=>"secondary_elements"),
1253 item(:text, :title=>"Basis set"),
1254 item(:popup, :subitems=>bset_desc, :tag=>"secondary_basis"),
1259 item(:checkbox, :title=>"Calculate electrostatic potential (ESP)", :tag=>"esp"),
1265 item(:checkbox, :title=>"Execute GAMESS on this machine", :tag=>"execute_local",
1266 :action=>lambda { |it|
1267 flag = (it[:value] != 0)
1268 set_attr("executable_path", :enabled=>flag)
1269 set_attr("select_path", :enabled=>flag)
1270 set_attr("ncpus", :enabled=>flag)
1274 item(:text, :title=>" Path"),
1275 item(:textfield, :width=>300, :tag=>"executable_path"),
1279 item(:button, :title=>"Select Path...", :tag=>"select_path", :action=>:select_gamess_path),
1281 item(:button, :title=>"Optional Scripts...", :action=>:set_optional_scripts),
1283 item(:text, :title=>" N of CPUs"),
1284 item(:textfield, :width=>80, :tag=>"ncpus"),
1290 item(:button, :title=>"Edit GAMESS Input and Go", :action=>lambda { |it|
1293 if (tag = it2[:tag]) != nil
1294 h[tag] = it2[:value]
1297 h["basis"] = $gamess_basis_keys[h["basis"]]
1298 h["secondary_basis"] = $gamess_basis_keys[h["secondary_basis"]]
1299 h["dfttype"] = dft_internal[h["dfttype"]]
1300 gamess_input_direct = mol.cmd_edit_gamess_input(mol.export_gamess(nil, h))
1301 if gamess_input_direct
1311 values[tag] = (user_input[tag] || get_global_settings("gamess.#{tag}") || defaults[tag])
1312 if tag == "basis" && values[tag] == "-1"
1313 values[tag] = (bset_desc.count).to_s
1315 it[:value] = values[tag]
1318 set_attr("secondary_elements", :enabled=>(values["use_secondary_basis"] == 1))
1319 set_attr("secondary_basis", :enabled=>(values["use_secondary_basis"] == 1))
1320 set_attr("dfttype", :enabled=>(values["dft"] == 1))
1321 set_attr("use_internal", :enabled=>(values["runtype"] == 2))
1322 set_attr("executable_path", :enabled=>(values["execute_local"] == 1))
1323 set_attr("select_path", :enabled=>(values["execute_local"] == 1))
1324 set_attr("ncpus", :enabled=>(values["execute_local"] == 1))
1326 hash.each_pair { |key, value|
1327 next if key == :status
1328 set_global_settings("gamess.#{key}", value)
1330 if hash[:status] == 0
1331 # Specify basis by internal keys
1332 hash["basis"] = $gamess_basis_keys[hash["basis"]]
1333 hash["secondary_basis"] = $gamess_basis_keys[hash["secondary_basis"]]
1334 hash["dfttype"] = dft_internal[hash["dfttype"]]
1335 basename = (self.path ? File.basename(self.path, ".*") : self.name)
1336 fname = Dialog.save_panel("Export GAMESS input file:", self.dir, basename + ".inp", "GAMESS input file (*.inp)|*.inp|All files|*.*")
1337 return nil if !fname
1338 if gamess_input_direct
1339 # puts "gamess_input_direct = \"#{gamess_input_direct}\""
1340 File.open(fname, "w") { |fp| fp.print(gamess_input_direct) }
1342 export_gamess(fname, hash)
1344 if hash["execute_local"] == 1
1345 Molecule.execute_gamess(fname, self)
1354 grid = default_MO_grid
1358 item(:text, :title=>"This molecule does not contain MO information."))
1364 if mos == nil || mos.length == 0
1367 item(:text, :title=>"Please select MO(s) in the MO Info table."))
1373 item(:text, :title=>"Please specify cube dimensions (in angstrom units):"),
1375 item(:text, :title=>"Origin"),
1376 item(:textfield, :width=>100, :height=>20, :tag=>"originx", :value=>sprintf("%.6f", grid[0].x)),
1377 item(:textfield, :width=>100, :height=>20, :tag=>"originy", :value=>sprintf("%.6f", grid[0].y)),
1378 item(:textfield, :width=>100, :height=>20, :tag=>"originz", :value=>sprintf("%.6f", grid[0].z)),
1379 item(:text, :title=>"Delta"),
1380 item(:textfield, :width=>100, :height=>20, :tag=>"deltax", :value=>sprintf("%.6f", grid[1])),
1381 item(:textfield, :width=>100, :height=>20, :tag=>"deltay", :value=>sprintf("%.6f", grid[2])),
1382 item(:textfield, :width=>100, :height=>20, :tag=>"deltaz", :value=>sprintf("%.6f", grid[3])),
1383 item(:text, :title=>"Step"),
1384 item(:textfield, :width=>100, :height=>20, :tag=>"stepx", :value=>grid[4].to_s),
1385 item(:textfield, :width=>100, :height=>20, :tag=>"stepy", :value=>grid[5].to_s),
1386 item(:textfield, :width=>100, :height=>20, :tag=>"stepz", :value=>grid[6].to_s)))
1388 if hash[:status] == 0
1389 path = self.path || self.name
1390 dir = self.dir || Dir.pwd
1391 origin = Vector3D[hash["originx"], hash["originy"], hash["originz"]]
1398 basename = File.basename(path, ".*")
1400 mo_type = self.mo_type
1402 fname1 = fname2 = nil
1403 alpha = (mo_type != "UHF" ? "" : "alpha ")
1404 a = (mo_type != "UHF" ? "" : "a")
1405 fname1 = Dialog.save_panel("Cube file name for #{alpha}MO #{n}", dir, basename + "_#{n}#{a}.cube", "Gaussian cube file (*.cube)|*.cube")
1406 if (mo_type == "UHF")
1407 fname2 = Dialog.save_panel("Cube file name for beta MO #{n}", dir, basename + "_#{n}b.cube", "Gaussian cube file (*.cube)|*.cube")
1409 filenames.push([n, fname1, fname2])
1411 filenames.each { |pair|
1413 alpha = (mo_type != "UHF" ? "" : "alpha ")
1414 show_progress_panel("Creating cube file for #{alpha}MO #{n}...")
1416 cubegen(pair[1], n, origin, dx, dy, dz, nx, ny, nz, true)
1418 if pair[2] && mo_type == "UHF"
1419 set_progress_message("Creating cube file for beta MO #{n}...")
1420 cubegen(pair[2], n, origin, dx, dy, dz, nx, ny, nz, true, true)
1430 "PM3" => " PM3 0\n",
1431 "STO3G" => " STO 3\n",
1432 "321G" => " N21 3\n",
1433 "631G" => " N31 6\n" }
1434 $gamess_basis_desc = {
1436 "STO3G" => "STO-3G",
1439 $gamess_basis_keys = ["PM3", "STO3G", "321G", "631G"]
1441 ["631Gd", "631Gdp", "631+Gd", "631++Gdp", "6311Gdp", "6311+Gd", "6311++Gdp", "6311++G2d2p", "6311++G3df3pd", "LanL2DZ"].each { |n|
1442 Molecule.read_gamess_basis_sets("basis_sets/#{n}.txt")
1445 register_menu("QChem\tCreate GAMESS Input...",
1446 :cmd_create_gamess_input, :non_empty)
1447 register_menu("QChem\tCreate MOPAC6 Input...",
1448 :cmd_create_mopac_input, :non_empty) # mopac6.rb
1449 register_menu("QChem\tCreate MO Cube...",
1450 :cmd_create_cube, lambda { |m| m && m.mo_type } )