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.
18 def Molecule.read_gamess_basis_sets(fname)
19 # $gamess_basis = Hash.new unless $gamess_basis
20 $gamess_ecp = Hash.new unless $gamess_ecp
21 # $gamess_basis_desc = Hash.new unless $gamess_basis_desc
22 # $gamess_basis_keys = [] unless $gamess_basis_keys
23 basename = File.basename(fname, ".*")
26 File.open(fname, "r") { |fp|
28 if s =~ /^\s*!\s*/ && descname == nil
29 # Get the descriptive name from the first comment line
30 s = Regexp.last_match.post_match
32 descname = Regexp.last_match.pre_match
34 descname = (s.split)[0]
36 $gamess_basis_desc[basename] = descname
39 ss, bas = (s.split)[0..1] # Tokens delimited by whitespaces
40 next if ss == nil || ss == ""
42 # Read the ECP section
43 ecp = $gamess_ecp[basename]
46 $gamess_ecp[basename] = ecp
48 keys << basename unless keys.include?(basename)
51 ary = s.split # (PNAME, PTYPE, IZCORE, LMAX+1)
52 elem = ary[0].match(/\w{1,2}/).to_a[0] # ary[0] should begin with an element name
53 ap = Parameter.builtin.elements.find { |p| p.name.casecmp(elem) == 0 }
54 raise MolbyError, "the ECP definition does not begin with an element name: #{s}" if !ap
57 (0..Integer(ary[3])).each {
59 raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
61 ary = s.split # (NGPOT, comment)
63 (1..Integer(ary[0])).each {
65 raise MolbyError, "the ECP definition ends unexpectedly at line #{ln} for: #{s}" if !s
70 ecp[ap.index] = ecpdef
73 # Comments or other unrecognizable lines
75 elsif (ap = Parameter.builtin.elements.find { |p| p.name.casecmp(ss) == 0 || p.fullname.casecmp(ss) == 0 })
76 # Valid basis definition
77 if bas == nil || bas =~ /\W/
80 basis = $gamess_basis[bas]
83 $gamess_basis[bas] = basis
85 keys << bas unless keys.include?(bas)
87 while (s = fp.gets) && s =~ /\S/
90 basis[ap.index] = basdef
92 raise MolbyError, "ss is not a valid element symbol or name: #{s}"
96 unless $gamess_basis_keys.include?(basename)
97 $gamess_basis_keys.push(basename)
101 def export_gamess(fname, hash)
104 basename = File.basename(fname, ".*")
107 icharg = hash["charge"]
109 runtyp = ["ENERGY", "PROP", "OPTIMIZE"][Integer(hash["runtype"])]
110 scftyp = ["RHF", "ROHF", "UHF"][Integer(hash["scftype"])]
111 bssname = hash["basis"]
112 bssname2 = hash["secondary_basis"]
113 if hash["use_secondary_basis"] != 0 && bssname2 != bssname
115 element2 = hash["secondary_elements"].split(/[\s,]+/).map { |name| name.capitalize }
120 basis = $gamess_basis[bssname]
121 basis2 = $gamess_basis[bssname2]
123 raise MolbyError, "Unknown basis set name??? \"#{bssname}\" or \"#{bssname2}\""
126 # Use effective core potentials?
127 ecp = $gamess_ecp[bssname]
128 ecp2 = $gamess_ecp[bssname2]
129 ecp_read = (ecp || ecp2 ? "ECP=READ " : "")
131 # Use only one built-in basis set?
138 gbasis = "STO NGAUSS=3"
140 gbasis = "N21 NGAUSS=3"
142 gbasis = "N31 NGAUSS=6"
144 gbasis = "N31 NGAUSS=6 NDFUNC=1"
146 gbasis = "N31 NGAUSS=6 NDFUNC=1 NPFUNC=1"
148 gbasis = "N311 NGAUSS=6"
150 gbasis = "N311 NGAUSS=6 NDFUNC=1 NPFUNC=1"
154 # Count non-dummy atoms
157 natoms += 1 if ap.atomic_number != 0
160 File.open(fname, "wb") { |fp|
161 fp.print "! GAMESS input\n"
162 fp.print "! Generated by Molby at #{now}\n"
163 fp.print " $CONTRL COORD=UNIQUE EXETYP=RUN ICHARG=#{icharg}\n"
164 fp.print " ICUT=20 INTTYP=HONDO ITOL=30\n"
165 fp.print " MAXIT=200 MOLPLT=.T. MPLEVL=0\n"
166 fp.print " MULT=#{mult} QMTTOL=1e-08 RUNTYP=#{runtyp}\n"
168 dfttyp = hash["dfttype"]
169 fp.print " DFTTYP=#{dfttyp}\n"
171 if hash["use_internal"] != 0 && hash["runtype"] == 2
172 nzvar = natoms * 3 - 6 # TODO: 3N-5 for linear molecules
173 fp.print " NZVAR=#{nzvar}\n"
177 fp.print " SCFTYP=#{scftyp} #{ecp_read}UNITS=ANGS $END\n"
178 fp.print " $SCF CONV=1.0E-06 DIRSCF=.T. FDIFF=.T. DAMP=.T. $END\n"
179 fp.print " $STATPT NSTEP=400 OPTTOL=1.0E-06 $END\n"
180 fp.print " $SYSTEM MEMDDI=0 MWORDS=16 TIMLIM=50000 $END\n"
181 fp.print " $GUESS GUESS=HUCKEL $END\n"
183 fp.print " $BASIS GBASIS=#{gbasis} $END\n"
186 fp.print " $ZMAT DLC=.T. AUTO=.T. $END\n"
189 fp.print " $ELPOT IEPOT=1 OUTPUT=PUNCH WHERE=PDC $END\n"
190 fp.print " $PDC CONSTR=NONE PTSEL=CONNOLLY $END\n"
192 fp.print " $DATA\n#{basename}\nC1 0\n"
195 next if ap.atomic_number == 0
196 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
197 if use_2nd && element2.include?(ap.element)
198 secondary[ap.index] = true
201 # Basis specification followed by a blank line
202 bas = (secondary[ap.index] ? basis2 : basis)
204 bas = bas[ap.atomic_number]
207 raise MolbyError, "Basis set is not defined for atom #{ap.index}, element #{ap.element}"
218 an = ap.atomic_number
220 ecpp = (secondary[ap.index] ? ecp2 : ecp)
221 e = ecp_ary[an] || (ecpp && ecpp[an])
223 # Cache the PNAME of the $ECP entry and re-use it
224 ecp_ary[an] ||= (e.split)[0] + "\n"
226 e = ap.element.upcase + "-ECP NONE\n"
236 def cmd_create_gamess_input
238 raise MolbyError, "cannot create GAMESS input; the molecule is empty"
241 # Descriptive text and internal string for popup menus
242 # bset_desc = ["PM3", "STO-3G", "3-21G", "6-31G", "6-31G(d)", "6-31G(d,p)", "6-311G", "6-311G(d,p)", "LanL2DZ"]
243 # bset_internal = ["PM3", "STO3G", "321G", "631G", "631Gd", "631Gdp", "6311G", "6311Gdp", "LanL2DZ"]
244 bset_desc = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
246 dft_internal = ["B3LYP"]
248 defaults = {"scftype"=>0, "runtype"=>0, "charge"=>"0", "mult"=>"1",
249 "basis"=>4, "use_secondary_basis"=>0, "secondary_elements"=>"",
250 "secondary_basis"=>8, "esp"=>0}
252 hash = Dialog.run("GAMESS Export") {
253 def load_basis_set_sub(item)
254 fname = Dialog.open_panel("Select a file containing GAMESS basis set:")
256 Molecule.read_gamess_basis_sets(fname)
257 bset_desc_new = $gamess_basis_keys.map { |key| $gamess_basis_desc[key] }
258 sel1 = attr("basis", :value)
259 sel2 = attr("secondary_basis", :value)
260 set_attr("basis", :subitems=>bset_desc_new)
261 set_attr("basis", :value=>sel1)
262 set_attr("secondary_basis", :subitems=>bset_desc_new)
263 set_attr("secondary_basis", :value=>sel2)
267 item(:text, :title=>"SCF type"),
268 item(:popup, :subitems=>["RHF", "ROHF", "UHF"], :tag=>"scftype"),
269 item(:text, :title=>"Run type"),
270 item(:popup, :subitems=>["Energy", "Property", "Optimize"], :tag=>"runtype",
271 :action=>proc { |it| set_attr("use_internal", :enabled=>(it[:value] == 2)) } ),
273 item(:checkbox, :title=>"Use internal coordinates for structure optimization", :tag=>"use_internal"),
276 item(:text, :title=>"Charge"),
277 item(:textfield, :width=>80, :tag=>"charge"),
278 item(:text, :title=>"Multiplicity"),
279 item(:textfield, :width=>80, :tag=>"mult"),
281 item(:checkbox, :title=>"Use DFT", :tag=>"dft",
282 :action=>proc { |it| set_attr("dfttype", :enabled=>(it[:value] != 0)) } ),
284 item(:text, :title=>"DFT type"),
285 item(:popup, :subitems=>dft_desc, :tag=>"dfttype"),
290 item(:text, :title=>"Basis set"),
291 item(:popup, :subitems=>bset_desc, :tag=>"basis"),
295 item(:button, :title=>"Load Basis Set...", :action=>:load_basis_set_sub),
298 item(:checkbox, :title=>"Use secondary basis set", :tag=>"use_secondary_basis",
300 flag = (it[:value] != 0)
301 set_attr("secondary_elements", :enabled=>flag)
302 set_attr("secondary_basis", :enabled=>flag)
306 item(:text, :title=>" Elements"),
307 item(:textfield, :width=>80, :tag=>"secondary_elements"),
308 item(:text, :title=>"Basis set"),
309 item(:popup, :subitems=>bset_desc, :tag=>"secondary_basis"),
314 item(:checkbox, :title=>"Calculate electrostatic potential (ESP)", :tag=>"esp"),
324 values[tag] = (get_global_settings("gamess.#{tag}") || defaults[tag])
325 it[:value] = values[tag]
328 set_attr("secondary_elements", :enabled=>(values["use_secondary_basis"] == 1))
329 set_attr("secondary_basis", :enabled=>(values["use_secondary_basis"] == 1))
330 set_attr("dfttype", :enabled=>(values["dft"] == 1))
331 set_attr("use_internal", :enabled=>(values["runtype"] == 2))
333 hash.each_pair { |key, value|
334 next if key == :status
335 set_global_settings("gamess.#{key}", value)
337 if hash[:status] == 0
338 # Specify basis by internal keys
339 hash["basis"] = $gamess_basis_keys[hash["basis"]]
340 hash["secondary_basis"] = $gamess_basis_keys[hash["secondary_basis"]]
341 hash["dfttype"] = dft_internal[hash["dfttype"]]
342 basename = (self.path ? File.basename(self.path, ".*") : self.name)
343 fname = Dialog.save_panel("GAMESS input file name", self.dir, basename + ".inp", "GAMESS input file (*.inp)|*.inp|All files|*.*")
345 export_gamess(fname, hash)
355 "STO3G" => " STO 3\n",
356 "321G" => " N21 3\n",
357 "631G" => " N31 6\n" }
358 $gamess_basis_desc = {
363 $gamess_basis_keys = ["PM3", "STO3G", "321G", "631G"]
365 ["631Gd", "631Gdp", "631+Gd", "631++Gdp", "6311Gdp", "6311+Gd", "6311++Gdp", "6311++G2d2p", "6311++G3df3pd", "LanL2DZ"].each { |n|
366 Molecule.read_gamess_basis_sets("basis_sets/#{n}.txt")