OSDN Git Service

Support load/save of NBO info
[molby/Molby.git] / Scripts / mopac6.rb
1 # coding: utf-8
2 #
3 #  mopac6.rb
4 #
5 #  Created by Toshi Nagata on 2013/11/01.
6 #  Copyright 2013 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 Molecule
18
19   #  Execute mopac6
20   #  inpname is the input file
21   #  mol (optional) is the molecule from which the MOPAC input was built.
22   #  Currently not used (mopac6 is not bundled)
23   def Molecule.execute_mopac(inpname, mol = nil)
24
25     #  MOPAC executable
26     mopexe = "#{ResourcePath}/mopac/mopac606"
27
28         inpname = File.expand_path(inpname)
29     inpbase = File.basename(inpname)
30     inpdir = File.dirname(inpname)
31     inpbody = inpbase.sub(/\.\w*$/, "")
32
33     #  Prepare the scratch directory in the home directory
34     scrdir = document_home.sub(/\/My Documents/, "") + "/mopac"
35     n = 0
36     while File.exist?(scrdir) && !File.directory?(scrdir)
37       if n == 0
38         scrdir += ".1"
39       else
40         scrdir = scrdir.sub(".#{n}", ".#{n + 1}")
41       end
42       n += 1
43     end
44     if !File.exist?(scrdir)
45       Dir.mkdir(scrdir)
46     end
47     scrdir = scrdir + "/" + inpbody + "." + $$.to_s + ".0"
48     n = 0
49     while File.exist?(scrdir)
50       scrdir = scrdir.sub(".#{n}", ".#{n + 1}")
51       n += 1
52     end
53     Dir.mkdir(scrdir)
54
55         #  Copy the input file to the scratch directory
56         cwd = Dir.pwd
57         filecopy(inpname, scrdir + "/FOR005")
58         term_callback = lambda { |m, n|
59             if File.exist?("#{scrdir}/FOR006")
60                   filecopy("#{scrdir}/FOR006", "#{inpdir}/#{inpbody}.out")
61                 end
62             msg = "MOPAC execution on #{inpbase} "
63             hmsg = "MOPAC "
64             if n == 0
65               msg += "succeeded."
66                   hmsg += "Completed"
67                   icon = :info
68             else
69               msg += "failed with status #{n}."
70                   hmsg += "Failed"
71                   icon = :error
72             end
73             msg += "\n(In directory #{inpdir})"
74             message_box(msg, hmsg, :ok, icon)
75                 erase_old_logs(scrdir, "latest", 5)  #  Keep latest 5 logs
76         }
77         timer_callback = nil
78         
79         #  Execute mopac
80         Dir.chdir(scrdir)
81         if mol
82           pid = mol.call_subprocess_async([mopexe], term_callback, timer_callback, "NUL", "NUL")
83         else
84           pid = call_subprocess([mopexe], "Running MOPAC", nil, "NUL", "NUL")
85           term_callback.call(nil, pid)
86         end
87         Dir.chdir(cwd)
88         if pid < 0
89           error_message_box("MOPAC failed to run.")
90           return
91         end
92
93   end
94   
95   def create_mopac
96     if !@mopac_settings || (com = @mopac_settings["commands"]) == nil
97           com = " PM3"
98           (@mopac_settings ||= Hash.new)["commands"] = com
99         end
100         str = com + "\n"
101         str += sprintf("# %-76.76s\n", self.name)
102         str += sprintf("# %-76.76s\n", "Generated by Molby at #{Time.now.to_s}")
103         #  Create geometry input
104         geom = ""
105         if self.natoms <= 3
106           #  Z-matrix
107           if self.natoms >= 1
108             geom += atoms[0].element + "\n"
109         if self.natoms >= 2
110                   r = calc_bond(0, 1)
111                   geom += sprintf("%s %.6f 1\n", atoms[1].element, r)
112                   if self.natoms >= 3
113                         con = atoms[2].connects
114                         if con.include?(0)
115                           r = calc_bond(0, 2)
116                           a = calc_angle(2, 0, 1)
117                           c = "1 2"
118                         else
119                           r = calc_bond(1, 2)
120                           a = calc_angle(2, 1, 0)
121                           c = "2 1"
122                         end
123                         geom += sprintf("%s %.6f 1 %.3f 1 %s\n", atoms[2].element, r, a, c)
124                   end
125                 end
126           end
127         else
128           #  Cartesian
129           atoms.each { |ap|
130             geom += sprintf("%s %.6f 1 %.6f 1 %.6f 1\n", ap.element, ap.x, ap.y, ap.z)
131           }
132         end
133         return str + geom + "\n"
134   end
135   
136   def cmd_create_mopac_input
137
138     mol = self
139     h = Dialog.run("Create MOPAC6 Input") {
140           layout(1,
141             item(:text, :title=>"MOPAC input"),
142             item(:textview, :width=>480, :height=>200, :tag=>"mopac_commands"),
143           )
144           item_with_tag("mopac_commands")[:font] = [:fixed, 10]
145           item_with_tag("mopac_commands")[:value] = mol.create_mopac
146         }
147         #  Record the command lines for next invocation
148         mop = h["mopac_commands"]
149         com = (mop.split(/[\r\n]/))[0..0].join("\n")
150         (@mopac_settings ||= Hash.new)["commands"] = com
151         if h[:status] == 0
152           basename = (self.path ? File.basename(self.path, ".*") : self.name)
153       fname = Dialog.save_panel("Export MOPAC input file:", self.dir, basename + ".mopin", "MOPAC input file (*.mopin)|*.mopin|All files|*.*")    
154           return nil if !fname
155       open(fname, "w") { |fp|
156             fp.write(mop)
157           }
158         end
159         
160   end
161   
162 #  if lookup_menu("Create MOPAC6 Input...") < 0
163 #    register_menu("", "")
164 #    register_menu("Create MOPAC6 Input...", :cmd_create_mopac)
165 #  end
166
167 end