+
+ # Execute GAMESS (inferior copy of rungms script)
+ # inpname is the input file
+ # mol (optional) is the molecule from which the GAMESS input was built.
+ # If mol is specified and RUNTYP=OPTIMIZE, then the intermediate structures are
+ # displayed real-time.
+ def Molecule.execute_gamess(inpname, mol = nil)
+ gmsname = get_global_settings("gamess.executable_path")
+ gmsdir = nil
+ gmsvers = nil
+
+ cygwin_version = false # For windows: old cygwin version
+
+ while 1
+ if gmsname == nil || !File.exist?(gmsname)
+ gmsname = Dialog.open_panel("Please locate the GAMESS executable")
+ exit if gmsname == nil
+ end
+ gmsbase = File.basename(gmsname)
+ gmsdir = File.dirname(gmsname)
+ if gmsbase =~ /gamess\.(.*)\.(exe|x)$/i
+ gmsvers = $1
+ break
+ else
+ gmsname = nil
+ error_message_box(gmsbase + " does not look like a GAMESS executable!")
+ end
+ end
+
+# if mol == nil
+# mol = Molecule.open(inpname)
+# if mol == nil
+# error_message_box("Cannot open #{inpname} as GAMESS input")
+# return
+# end
+# end
+
+ inpbase = File.basename(inpname)
+ inpdir = File.dirname(inpname)
+ inpbody = inpbase.sub(/\.inp$/, "")
+ logbase = inpbody + ".log"
+
+ set_global_settings("gamess.executable_path", gmsname)
+
+ ncpus = get_global_settings("gamess.ncpus").to_i
+ if ncpus == 0
+ ncpus = 1
+ end
+
+ # Prepare the scratch directory
+ begin
+ scrdir = create_temp_dir("gamess", inpbody)
+ rescue
+ error_message_box($!.to_s)
+ return
+ end
+# scrdir = $home_directory + "/Molby/gamess"
+# begin
+# mkdir_recursive(scrdir)
+# rescue
+# error_message_box("Cannot create directory #{scrdir}: " + $!.to_s)
+# return
+# end
+
+# scrdir = scrdir + "/" + inpbody + "." + $$.to_s + ".0"
+# n = 0
+# while File.exist?(scrdir)
+# scrdir = scrdir.sub(".#{n}", ".#{n + 1}")
+# n += 1
+# end
+# Dir.mkdir(scrdir)
+
+ if $platform == "win"
+ sep = "\\"
+ scrdir.gsub!("/", sep)
+ gmsdir.gsub!("/", sep)
+ else
+ sep = "/"
+ end
+
+ # Old (obsolete) cygwin version, using ddikick
+ if $platform == "win"
+ if gmsvers == "11"
+ cygwin_version = true
+ end
+ end
+
+ # Get the host name etc.
+ hostname = backquote("hostname").chomp
+ if $platform == "win"
+ s = backquote("cmd.exe /c dir \"#{scrdir}\"")
+ freebytes = s.split("\n").pop.match(/([0-9,]+)[^0-9]*$/).to_a[1]
+ if freebytes
+ freebytes = (freebytes.gsub(",","").to_i / 1024).to_s + " Kbytes"
+ else
+ freebytes = "(unknown)"
+ end
+ uname = backquote("cmd.exe /c ver").to_s.gsub("\n", "")
+ else
+ freebytes = `df -k "#{scrdir}"`
+ uname = `uname`.chomp
+ end
+
+ # Redirect standard output to the log file
+ logname = scrdir + sep + logbase
+ fpout = File.open(logname, "w")
+ if cygwin_version
+ # The cygwin version uses LF as the eol character
+ fpout.binmode
+ end
+ fpout.print "----- GAMESS execution script -----\n"
+ fpout.print "This job is running on host #{hostname}\n"
+ fpout.print "under operating system #{uname} at #{Time.now.to_s}\n"
+ fpout.print "Available scratch disk space (Kbyte units) at beginning of the job is\n"
+ fpout.print freebytes + "\n"
+
+ # Copy the input file
+ scrprefix = scrdir + sep + inpbody
+ if $platform == "win"
+ scrbody = inpbody
+ else
+ scrbody = scrprefix
+ end
+ filecopy(inpname, scrprefix + ".F05")
+ File.open("#{scrdir}/.in_use", "w") { |fp| }
+
+ # Prepare environmental variables
+ auxdir = "#{gmsdir}#{sep}auxdata"
+ ENV["ERICFMT"] = "#{auxdir}#{sep}ericfmt.dat"
+ ENV["MCPPATH"] = "#{auxdir}#{sep}MCP"
+ ENV["BASPATH"] = "#{auxdir}#{sep}BASES"
+ ENV["QUANPOL"] = "#{auxdir}#{sep}QUANPOL"
+ ENV["EXTBAS"] = "/dev/null"
+ ENV["IRCDATA"] = "#{scrbody}.irc"
+ ENV["RESTART"] = "#{scrbody}.rst"
+ ENV["TRAJECT"] = "#{scrbody}.trj"
+ ENV["PUNCH"] = "#{scrbody}.dat"
+ ENV["INPUT"] = "#{scrbody}.F05"
+ ENV["AOINTS"] = "#{scrbody}.F08"
+ ENV["MOINTS"] = "#{scrbody}.F09"
+ ENV["DICTNRY"] = "#{scrbody}.F10"
+ ENV["DRTFILE"] = "#{scrbody}.F11"
+ ENV["CIVECTR"] = "#{scrbody}.F12"
+ ENV["CASINTS"] = "#{scrbody}.F13"
+ ENV["CIINTS"] = "#{scrbody}.F14"
+ ENV["WORK15"] = "#{scrbody}.F15"
+ ENV["WORK16"] = "#{scrbody}.F16"
+ ENV["CSFSAVE"] = "#{scrbody}.F17"
+ ENV["FOCKDER"] = "#{scrbody}.F18"
+ ENV["WORK19"] = "#{scrbody}.F19"
+ ENV["DASORT"] = "#{scrbody}.F20"
+ ENV["DFTINTS"] = "#{scrbody}.F21"
+ ENV["DFTGRID"] = "#{scrbody}.F22"
+ ENV["JKFILE"] = "#{scrbody}.F23"
+ ENV["ORDINT"] = "#{scrbody}.F24"
+ ENV["EFPIND"] = "#{scrbody}.F25"
+ ENV["PCMDATA"] = "#{scrbody}.F26"
+ ENV["PCMINTS"] = "#{scrbody}.F27"
+ ENV["MLTPL"] = "#{scrbody}.F28"
+ ENV["MLTPLT"] = "#{scrbody}.F29"
+ ENV["DAFL30"] = "#{scrbody}.F30"
+ ENV["SOINTX"] = "#{scrbody}.F31"
+ ENV["SOINTY"] = "#{scrbody}.F32"
+ ENV["SOINTZ"] = "#{scrbody}.F33"
+ ENV["SORESC"] = "#{scrbody}.F34"
+ ENV["SIMEN"] = "#{scrbody}.simen"
+ ENV["SIMCOR"] = "#{scrbody}.simcor"
+ ENV["GCILIST"] = "#{scrbody}.F37"
+ ENV["HESSIAN"] = "#{scrbody}.F38"
+ ENV["SOCCDAT"] = "#{scrbody}.F40"
+ ENV["AABB41"] = "#{scrbody}.F41"
+ ENV["BBAA42"] = "#{scrbody}.F42"
+ ENV["BBBB43"] = "#{scrbody}.F43"
+ ENV["MCQD50"] = "#{scrbody}.F50"
+ ENV["MCQD51"] = "#{scrbody}.F51"
+ ENV["MCQD52"] = "#{scrbody}.F52"
+ ENV["MCQD53"] = "#{scrbody}.F53"
+ ENV["MCQD54"] = "#{scrbody}.F54"
+ ENV["MCQD55"] = "#{scrbody}.F55"
+ ENV["MCQD56"] = "#{scrbody}.F56"
+ ENV["MCQD57"] = "#{scrbody}.F57"
+ ENV["MCQD58"] = "#{scrbody}.F58"
+ ENV["MCQD59"] = "#{scrbody}.F59"
+ ENV["MCQD60"] = "#{scrbody}.F60"
+ ENV["MCQD61"] = "#{scrbody}.F61"
+ ENV["MCQD62"] = "#{scrbody}.F62"
+ ENV["MCQD63"] = "#{scrbody}.F63"
+ ENV["MCQD64"] = "#{scrbody}.F64"
+ ENV["NMRINT1"] = "#{scrbody}.F61"
+ ENV["NMRINT2"] = "#{scrbody}.F62"
+ ENV["NMRINT3"] = "#{scrbody}.F63"
+ ENV["NMRINT4"] = "#{scrbody}.F64"
+ ENV["NMRINT5"] = "#{scrbody}.F65"
+ ENV["NMRINT6"] = "#{scrbody}.F66"
+ ENV["DCPHFH2"] = "#{scrbody}.F67"
+ ENV["DCPHF21"] = "#{scrbody}.F68"
+ ENV["GVVPT"] = "#{scrbody}.F69"
+
+ # next files are used only during coupled cluster runs, so let's
+ # display the numerous definitions only if they are to be used.
+ # Don't set these variables on windows, where the memory for environmental variables
+ # is limited.
+ if $platform != "win"
+ ENV["CCREST"] = "#{scrbody}.F70"
+ ENV["CCDIIS"] = "#{scrbody}.F71"
+ ENV["CCINTS"] = "#{scrbody}.F72"
+ ENV["CCT1AMP"] = "#{scrbody}.F73"
+ ENV["CCT2AMP"] = "#{scrbody}.F74"
+ ENV["CCT3AMP"] = "#{scrbody}.F75"
+ ENV["CCVM"] = "#{scrbody}.F76"
+ ENV["CCVE"] = "#{scrbody}.F77"
+ ENV["EOMSTAR"] = "#{scrbody}.F80"
+ ENV["EOMVEC1"] = "#{scrbody}.F81"
+ ENV["EOMVEC2"] = "#{scrbody}.F82"
+ ENV["EOMHC1"] = "#{scrbody}.F83"
+ ENV["EOMHC2"] = "#{scrbody}.F84"
+ ENV["EOMHHHH"] = "#{scrbody}.F85"
+ ENV["EOMPPPP"] = "#{scrbody}.F86"
+ ENV["EOMRAMP"] = "#{scrbody}.F87"
+ ENV["EOMRTMP"] = "#{scrbody}.F88"
+ ENV["EOMDG12"] = "#{scrbody}.F89"
+ ENV["MMPP"] = "#{scrbody}.F90"
+ ENV["MMHPP"] = "#{scrbody}.F91"
+ ENV["MMCIVEC"] = "#{scrbody}.F92"
+ ENV["MMCIVC1"] = "#{scrbody}.F93"
+ ENV["MMCIITR"] = "#{scrbody}.F94"
+ ENV["MMNEXM"] = "#{scrbody}.F95"
+ ENV["MMNEXE"] = "#{scrbody}.F96"
+ ENV["MMNREXM"] = "#{scrbody}.F97"
+ ENV["MMNREXE"] = "#{scrbody}.F98"
+ end
+ #
+ # next are for TDHFX code, not used by current GAMESS
+ #
+ if false
+ ENV["OLI201"] = "#{scrbody}.F201"
+ ENV["OLI202"] = "#{scrbody}.F202"
+ ENV["OLI203"] = "#{scrbody}.F203"
+ ENV["OLI204"] = "#{scrbody}.F204"
+ ENV["OLI205"] = "#{scrbody}.F205"
+ ENV["OLI206"] = "#{scrbody}.F206"
+ ENV["OLI207"] = "#{scrbody}.F207"
+ ENV["OLI208"] = "#{scrbody}.F208"
+ ENV["OLI209"] = "#{scrbody}.F209"
+ ENV["OLI210"] = "#{scrbody}.F210"
+ ENV["OLI211"] = "#{scrbody}.F211"
+ ENV["OLI212"] = "#{scrbody}.F212"
+ ENV["OLI213"] = "#{scrbody}.F213"
+ ENV["OLI214"] = "#{scrbody}.F214"
+ ENV["OLI215"] = "#{scrbody}.F215"
+ ENV["OLI216"] = "#{scrbody}.F216"
+ ENV["OLI217"] = "#{scrbody}.F217"
+ ENV["OLI218"] = "#{scrbody}.F218"
+ ENV["OLI219"] = "#{scrbody}.F219"
+ ENV["OLI220"] = "#{scrbody}.F220"
+ ENV["OLI221"] = "#{scrbody}.F221"
+ ENV["OLI222"] = "#{scrbody}.F222"
+ ENV["OLI223"] = "#{scrbody}.F223"
+ ENV["OLI224"] = "#{scrbody}.F224"
+ ENV["OLI225"] = "#{scrbody}.F225"
+ ENV["OLI226"] = "#{scrbody}.F226"
+ ENV["OLI227"] = "#{scrbody}.F227"
+ ENV["OLI228"] = "#{scrbody}.F228"
+ ENV["OLI229"] = "#{scrbody}.F229"
+ ENV["OLI230"] = "#{scrbody}.F230"
+ ENV["OLI231"] = "#{scrbody}.F231"
+ ENV["OLI232"] = "#{scrbody}.F232"
+ ENV["OLI233"] = "#{scrbody}.F233"
+ ENV["OLI234"] = "#{scrbody}.F234"
+ ENV["OLI235"] = "#{scrbody}.F235"
+ ENV["OLI236"] = "#{scrbody}.F236"
+ ENV["OLI237"] = "#{scrbody}.F237"
+ ENV["OLI238"] = "#{scrbody}.F238"
+ ENV["OLI239"] = "#{scrbody}.F239"
+ end
+
+ if $platform == "win"
+ # if ncpus < 2
+ # ncpus = 2
+ # end
+ if cygwin_version
+ # Old (obsolete) cygwin version, using ddikick
+ fpout.print "ddikick will run #{ncpus} compute process\n"
+ ENV["CYGWIN"] = "nodosfilewarning"
+ else
+ fpout.print "Microsoft MPI will be running GAMESS on 1 node.\n"
+ fpout.print "The binary kicked off by 'mpiexec' is gamess.#{gmsvers}.exe\n"
+ fpout.print "MS-MPI will run #{ncpus*2} compute process\n"
+ # File containing environmental variables
+ envfil = "#{scrprefix}.GMS.ENV"
+ fp = File.open(envfil, "w")
+ ENV.each { |k, v| fp.print "#{k}=#{v}\n" }
+ fp.close
+ # File containing arguments to mpiexec
+ procfil = "#{scrprefix}.processes.mpd"
+ fp = File.open(procfil, "w")
+ fp.print "-env ENVFIL \"#{envfil}\" -wdir \"#{scrdir}\" -n #{ncpus*2} \"#{gmsdir}#{sep}gamess.#{gmsvers}.exe\"\n"
+ fp.close
+ end
+ end
+
+ fpout.close
+ fplog = File.open(logname, "r")
+ size = 0
+ lines = []
+ lineno = 0
+ last_line = ""
+ search_mode = 0
+ nserch = -1
+ rflag = 0
+ ne_alpha = ne_beta = 0
+ mo_count = 0
+ ncomps = 0
+
+ # Callback procs
+ term_callback = lambda { |m, n|
+ msg = "GAMESS execution on #{inpbase} "
+ hmsg = "GAMESS "
+ if n == 0
+ msg += "succeeded."
+ hmsg += "Completed"
+ icon = :info
+ else
+ msg += "failed with status #{n}."
+ hmsg += "Failed"
+ icon = :error
+ end
+ msg += "\n(In directory #{inpdir})"
+
+ File.delete("#{scrdir}/.in_use")
+
+ ext_to_keep = [".dat", ".rst", ".trj", ".efp", ".gamma", ".log"]
+ ext_to_keep.each { |ex|
+ if File.exists?("#{scrprefix}#{ex}")
+ filecopy("#{scrprefix}#{ex}", "#{inpdir}#{sep}#{inpbody}#{ex}")
+ end
+ }
+ Dir.foreach(scrdir) { |file|
+ if file != "." && file != ".." && !ext_to_keep.include?(File.extname(file))
+ File.delete("#{scrdir}#{sep}#{file}")
+ end
+ }
+
+ begin
+ erase_old_logs(scrdir, "latest", 5)
+ rescue
+ error_message_box($!.to_s)
+ return
+ end
+
+ if (script = get_global_settings("gamess.postfix_script")) != nil && script != ""
+ eval(script)
+ end
+
+ if mol != nil
+ message_box(msg, hmsg, :ok, icon)
+ end
+ }
+
+ timer_callback = lambda { |m, n|
+ fplog.seek(0, IO::SEEK_END)
+ sizec = fplog.tell
+ if sizec > size
+ # Read new lines
+ fplog.seek(size, IO::SEEK_SET)
+ fplog.each_line { |line|
+ if line[-1, 1] == "\n"
+ lines.push(last_line + line)
+ last_line = ""
+ else
+ last_line += line
+ break
+ end
+ }
+ size = fplog.tell
+ last_i = nil
+ i = 0
+ while i < lines.count
+ line = lines[i]
+ if line =~ /GEOMETRY SEARCH POINT NSERCH= *(\d+)/
+ nserch = $1.to_i
+ last_i = i
+ search_mode = 1
+ energy = nil
+ elsif line =~ /START OF DRC CALCULATION/
+ search_mode = 3
+ nserch = 1
+ energy = nil
+ elsif line =~ /CONSTRAINED OPTIMIZATION POINT/
+ search_mode = 2
+ energy = nil
+ elsif line =~ /POINT *([0-9]+) *ON THE REACTION PATH/
+ nserch = $1.to_i
+ last_i = i
+ elsif line =~ /ATOMIC BASIS SET/
+ j = i
+ while j < lines.count
+ line = lines[j]
+ break if line =~ /TOTAL NUMBER OF BASIS SET/
+ j += 1
+ end
+ if j < lines.count
+ # Found
+ bs_lines = []
+ ii = i
+ while ii <= j
+ bs_lines.push(lines[ii].chomp)
+ ii += 1
+ end
+ begin
+ if mol
+ ncomps = mol.sub_load_gamess_log_basis_set(bs_lines, lineno + i)
+ end
+ rescue
+ $stderr.write($!.to_s + "\n")
+ $stderr.write($!.backtrace.inspect + "\n")
+ end
+ last_i = j
+ else
+ break # Wait until all basis set lines are read
+ end
+ elsif line =~ /NUMBER OF OCCUPIED ORBITALS/
+ line =~ /=\s*(\d+)/
+ n = Integer($1)
+ if line =~ /ALPHA/
+ ne_alpha = n
+ else
+ ne_beta = n
+ end
+ elsif line =~ /SCFTYP=(\w+)/
+ scftyp = $1
+ if ne_alpha > 0 || ne_beta > 0
+ rflag = 0
+ case scftyp
+ when "RHF"
+ rflag = 1
+ when "ROHF"
+ rflag = 2
+ end
+ end
+ elsif line =~ /^\s*(EIGENVECTORS|MOLECULAR ORBITALS)\s*$/
+ if mo_count == 0 && mol
+ mol.clear_mo_coefficients
+ mol.set_mo_info(:type=>["UHF", "RHF", "ROHF"][rflag], :alpha=>ne_alpha, :beta=>ne_beta)
+ end
+ i += 2
+ j = i
+ mo_count += 1
+ while j < lines.count
+ line = lines[j]
+ break if line =~ /\.\.\.\.\.\./ || line =~ /----------------/
+ j += 1
+ end
+ if j == lines.count
+ break # Wait until complete MO info are read
+ end
+ ii = i
+ mo_lines = []
+ while ii < j
+ mo_lines.push(lines[ii].chomp)
+ ii += 1
+ end
+ begin
+ if mol
+ mol.sub_load_gamess_log_mo_coefficients(mo_lines, lineno + i, ncomps)
+ end
+ rescue
+ $stderr.write($!.to_s + "\n")
+ $stderr.write($!.backtrace.inspect + "\n")
+ end
+ last_i = j
+ elsif line =~ /NSERCH: *([0-9]+)/
+ # print line
+ if mol
+ n = $1
+ line =~ /E= +([-.0-9]+)/
+ energy = $1.to_f
+ line =~ /GRAD\. MAX= +([-.0-9]+)/
+ grad = $1
+ mol.show_text("Search: #{n}\nGradient: #{grad}")
+ # mol.set_property("energy", energy)
+ end
+ last_i = i
+ elsif line =~ /TOTAL ENERGY += *([-.0-9]+)/
+ energy = $1
+ if mol && search_mode == 2
+ mol.show_text("Point: #{nserch}\nEnergy: #{energy}")
+ end
+ energy = energy.to_f
+ elsif line =~ /FINAL .* ENERGY IS +([-.0-9]+) *AFTER/
+ energy = $1.to_f
+ if mol && search_mode == 0
+ mol.set_property("energy", energy)
+ end
+ elsif nserch > 0 && line =~ /ddikick\.x/
+ last_i = -1
+ break
+ elsif mol && nserch > 0 && (line =~ /COORDINATES OF ALL ATOMS/ || line =~ /COORDINATES \(IN ANGSTROM\) FOR \$DATA GROUP ARE/)
+ # There should be (natoms) lines
+ if line =~ /COORDINATES OF ALL ATOMS/
+ # Skip header lines
+ i += 2
+ end
+ if i + mol.natoms + 1 <= lines.count
+ coords = []
+ (i + 1...i + 1 + mol.natoms).each { |j|
+ name, charge, x, y, z = lines[j].split
+ coords.push(Vector3D[x.to_f, y.to_f, z.to_f])
+ }
+ mol.create_frame([coords])
+ if search_mode == 1 && energy
+ mol.set_property("energy", energy)
+ end
+ mol.display
+ last_i = i + mol.natoms
+ i = last_i # Skip the processed lines
+ end
+ 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/
+ # NBO output
+ j = i + 1
+ while j < lines.count
+ break if lines[j] =~ /done with NBO analysis/
+ j += 1
+ end
+ if j < lines.count
+ nbo_lines = lines[i..j]
+ mol.import_nbo_log(nbo_lines) rescue puts "Error: #{$!}, #{$!.backtrace.inspect}"
+ last_i = j
+ i = last_i # Skip the processed lines
+ else
+ break # Wait until NBO is done
+ end
+ end
+ i += 1
+ end
+ if last_i == -1
+ lines.clear
+ break
+ elsif last_i
+ lines[0..last_i] = nil
+ lineno += last_i + 1
+ end
+ end
+ true
+ }
+
+ if (script = get_global_settings("gamess.prefix_script")) != nil && script != ""
+ eval(script)
+ end
+
+ if $platform == "win"
+ if gmsvers == "11"
+ hosts = "localhost " * ncpus
+ cmdline = "cmd.exe /c \"#{gmsdir}/ddikick.exe #{gmsdir}/gamess.#{gmsvers}.exe #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < NUL >>#{logname}"
+ else
+ cmdline = "cmd.exe /c \"mpiexec -configfile #{procfil} >>#{logname}"
+ end
+ else
+ hosts = "localhost " * ncpus
+ cmdline = "/bin/sh -c '#{gmsdir}/ddikick.x #{gmsdir}/gamess.#{gmsvers}.x #{inpbody} -ddi #{ncpus} #{ncpus} #{hosts} -scr #{scrdir} < /dev/null >>#{logname}'"
+ end
+
+ if mol
+ pid = mol.call_subprocess_async(cmdline, term_callback, timer_callback)
+ if pid < 0
+ error_message_box("GAMESS failed to start. Please examine GAMESS installation.")
+ return
+ end
+ else
+ pid = call_subprocess(cmdline, "Running GAMESS")
+ term_callback.call(nil, pid)
+ return pid
+ end
+
+ end
+