OSDN Git Service

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