OSDN Git Service

'Create MO Cube' does not work when the molecule has no associated file. Fixed.
[molby/Molby.git] / Scripts / commands.rb
1 #
2 #  commands.rb
3 #
4 #  Created by Toshi Nagata on 2008/06/28.
5 #  Copyright 2008 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   def cmd_assign_residue
19     sel = self.selection
20         if sel.length == 0
21           sel = self.atom_group
22         end
23         atoms = sel.inspect.sub!("IntGroup[", "").sub!("]", "")
24     hash = Dialog.run {
25           layout(2,
26                 item(:text, :title=>"New residue name/number\n(like \"RES.1\")\nfor atoms #{atoms}"),
27             item(:textfield, :width=>120, :tag=>"residue"))
28     }
29     if hash[:status] == 0
30           residue = hash["residue"]
31           assign_residue(sel, residue)
32         end
33   end
34
35   def cmd_offset_residue
36     sel = self.selection
37         if sel.length == 0
38           sel = self.atom_group
39         end
40         atoms = sel.inspect.sub!("IntGroup[", "").sub!("]", "")
41     hash = Dialog.run {
42           layout(2,
43                 item(:text, :title=>"Offset residue number:\nfor atoms #{atoms}"),
44             item(:textfield, :width=>120, :tag=>"offset"))
45     }
46         if hash[:status] == 0
47           offset = hash["offset"].to_i
48           offset_residue(sel, offset)
49         end
50   end
51    
52   def cmd_sort_by_residue
53     sel = self.selection
54         if sel.length == 0
55           sel = self.atom_group
56         end
57         sorted = sel.sort_by { |i| [self.atoms[i].res_seq, i] }
58         ary = []
59         j = 0
60         (0...natoms).each { |i|
61           if sel.include?(i)
62             ary << sorted[j]
63                 j += 1
64                 break if j >= sorted.length
65           else
66             ary << i
67           end
68         }
69         self.renumber_atoms(ary)
70   end
71
72   def save_gamess_with_ecp(filename)
73     if natoms == 0
74       raise MolbyError, "cannot save GAMESS input; the molecule is empty"
75     end
76     fp = open(filename, "wb")
77         now = Time.now.to_s
78         fp.print <<end_of_header
79 !  GAMESS input
80 !  Generated by Molby at #{now}
81  $CONTRL COORD=UNIQUE EXETYP=RUN ICHARG=0
82          ICUT=20 INTTYP=HONDO ITOL=30
83          MAXIT=200 MOLPLT=.T. MPLEVL=0
84          MULT=1 QMTTOL=1e-08 RUNTYP=OPTIMIZE
85                  ECP=READ 
86          SCFTYP=RHF UNITS=ANGS                  $END
87  $SCF    CONV=1.0E-06 DIRSCF=.T. FDIFF=.T. DAMP=.T. $END
88  $STATPT NSTEP=400 OPTTOL=1.0E-06               $END
89  $SYSTEM MEMDDI=0 MWORDS=16 TIMLIM=50000        $END
90  $BASIS  EXTFIL=.T. GBASIS=321LAN               $END
91  $GUESS  GUESS=HUCKEL                           $END
92 !
93  $DATA
94  #{name}
95  C1
96 end_of_header
97         ecp = Hash.new
98         each_atom { |ap|
99                 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
100                 if ap.atomic_number >= 11
101                         ecp[ap.element.upcase] = 1
102                 end
103         }
104         fp.print " $END\n"
105         #  Read ECP from file
106         efp = open($startup_dir + "/gamess_ecp.txt", "rb")
107         elem = ""
108         ecplines = nil
109         while 1
110                 line = efp.gets
111                 if line == nil || line =~ /(\w\w)-ECP /
112                         if ecplines != nil
113                                 print "#{line}"
114                                 ecp[elem] = ecplines
115                         end
116                         break if line == nil
117                         elem = $1.upcase
118                         if ecp.member?(elem)
119                                 ecplines = ""
120                         else
121                                 ecplines = nil
122                         end
123                         print "#{line}: #{'->ignore' if ecplines == nil}\n"
124                 end
125                 if ecplines != nil
126                         ecplines += line
127                 end
128         end
129         efp.close
130         #  Create ECP section
131         fp.print " $ECP\n"
132         each_atom { |ap|
133                 elem = ap.element.upcase
134                 if ecp.member?(elem)
135                         fp.print ecp[elem]
136                         ecp[elem] = "#{elem}-ECP\n"
137                 else
138                         fp.print "#{elem}-ECP NONE\n"
139                 end
140         }
141         fp.print " $END\n"      
142         fp.close
143   end
144   
145   def cmd_create_gamess
146     hash = Dialog.run {
147           layout(1,
148             item(:text, :title=>"Create GAMESS input with LANL2DZ effective core potentials"))
149     }
150     if hash[:status] == 0
151       fname = File.basename(self.path, ".*") + ".inp"
152           fname = Dialog.save_panel(nil, self.dir, fname)
153           if fname
154                 save_gamess_with_ecp(fname)
155           end
156         end
157   end
158
159   def cmd_create_cube
160     grid = default_MO_grid
161         if grid == nil
162           Dialog.run {
163             layout(1,
164                   item(:text, :title=>"This molecule does not contain MO information."))
165           }
166           return
167         end
168     mos = selected_MO
169         if mos == nil || mos.length == 0
170       Dialog.run {
171             layout(1,
172                   item(:text, :title=>"Please select MO(s) in the MO Info table."))
173       }
174           return
175         end
176         hash = Dialog.run {
177           layout(1,
178             item(:text, :title=>"Please specify cube dimensions (in bohr unit):"),
179             layout(4,
180                   item(:text, :title=>"Origin"),
181                   item(:textfield, :width=>100, :height=>20, :tag=>"originx", :value=>sprintf("%.6f", grid[0].x)),
182                   item(:textfield, :width=>100, :height=>20, :tag=>"originy", :value=>sprintf("%.6f", grid[0].y)),
183                   item(:textfield, :width=>100, :height=>20, :tag=>"originz", :value=>sprintf("%.6f", grid[0].z)),
184                   item(:text, :title=>"Delta"),
185                   item(:textfield, :width=>100, :height=>20, :tag=>"deltax", :value=>sprintf("%.6f", grid[1])),
186                   item(:textfield, :width=>100, :height=>20, :tag=>"deltay", :value=>sprintf("%.6f", grid[2])),
187                   item(:textfield, :width=>100, :height=>20, :tag=>"deltaz", :value=>sprintf("%.6f", grid[3])),
188                   item(:text, :title=>"Step"),
189                   item(:textfield, :width=>100, :height=>20, :tag=>"stepx", :value=>grid[4].to_s),
190                   item(:textfield, :width=>100, :height=>20, :tag=>"stepy", :value=>grid[5].to_s),
191                   item(:textfield, :width=>100, :height=>20, :tag=>"stepz", :value=>grid[6].to_s)))
192         }
193         if hash[:status] == 0
194           path = self.path || self.name
195           dir = self.dir || Dir.pwd
196           origin = Vector3D[hash["originx"], hash["originy"], hash["originz"]]
197           dx = hash["deltax"]
198           dy = hash["deltay"]
199           dz = hash["deltaz"]
200           nx = hash["stepx"]
201           ny = hash["stepy"]
202           nz = hash["stepz"]
203           basename = File.basename(path, ".*")
204           filenames = []
205           mo_type = self.mo_type
206           mos.each { |n|
207             fname1 = fname2 = nil
208             alpha = (mo_type != "UHF" ? "" : "alpha ")
209                 a = (mo_type != "UHF" ? "" : "a")
210             fname1 = Dialog.save_panel("Cube file name for #{alpha}MO #{n}", dir, basename + "_#{n}#{a}.cube", "Gaussian cube file (*.cube)|*.cube")
211                 if (mo_type == "UHF")
212                   fname2 = Dialog.save_panel("Cube file name for beta MO #{n}", dir, basename + "_#{n}b.cube", "Gaussian cube file (*.cube)|*.cube")
213                 end
214                 filenames.push([n, fname1, fname2])
215           }
216           filenames.each { |pair|
217             n = pair[0]
218                 alpha = (mo_type != "UHF" ? "" : "alpha ")
219             show_progress_panel("Creating cube file for #{alpha}MO #{n}...")
220                 if pair[1]
221                   cubegen(pair[1], n, origin, dx, dy, dz, nx, ny, nz, true)
222                 end
223                 if pair[2] && mo_type == "UHF"
224                   set_progress_message("Creating cube file for beta MO #{n}...")
225                   cubegen(pair[2], n, origin, dx, dy, dz, nx, ny, nz, true, true)
226                 end
227             hide_progress_panel
228           }
229         end
230   end
231
232   def Dialog.list_remote_files(host, directory)
233 #    list = `ssh #{host} "env COLUMNS=40 ls -C #{directory}"`
234     list = `ssh #{host} "ls #{directory}"`
235   end
236   
237   def Molecule.cmd_load_remote(mol)  #  mol is not used
238     hash = Dialog.run {
239           def button_action(it)   #  Action for OK and Cancel buttons
240                 if it[:index] == 0  #  OK
241                   local = File.expand_path(value("local"))
242                   if value("local") != ""
243                     #  Check whether the local file already exists
244                         exist = []
245                         sfile = value("sfile")
246                         cfile = value("cfile")
247                         if sfile != "" && FileTest.exist?("#{local}/#{sfile}")
248                           exist.push(sfile)
249                         end
250                         if cfile != "" && FileTest.exist?("#{local}/#{cfile}")
251                           exist.push(cfile)
252                         end
253                         if exist.length > 0
254                           if exist.length == 1
255                             msg = "The file #{exist[0]} already exists"
256                           else
257                             msg = "The files " + exist.join(", ") + " already exist"
258                           end
259                           msg += " in directory #{local}. Overwrite?"
260                           hash = Dialog.run {
261                             layout(1, item(:text, :title=>msg, :width=>240, :height=>60))
262                           }
263                           return if hash[:status] != 0  #  No call of super -> dialog is not dismissed
264                         end
265                   end
266             end
267                 end_modal(it)
268           end
269           def text_action(it)
270                 if value("host") != "" && value("directory") != "" && value("sfile") != ""
271                   set_attr(0, :enabled=>true)
272                 else
273                   set_attr(0, :enabled=>false)
274                 end       
275           end
276           layout(2,
277                 item(:text, :title=>"Remote host"),
278                 item(:textfield, :width=>280, :height=>20, :tag=>"host", :action=>:text_action),
279                 item(:text, :title=>"Directory"),
280                 item(:textfield, :width=>280, :height=>20, :tag=>"directory", :action=>:text_action),
281                 item(:text, :title=>"Structure File"),
282                 item(:textfield, :width=>280, :height=>20, :tag=>"sfile", :action=>:text_action),
283                 item(:text, :title=>"Coordinate File"),
284                 item(:textfield, :width=>280, :height=>20, :tag=>"cfile"),
285                 item(:text, :title=>"File List"),
286                 item(:textview, :width=>280, :height=>80, :tag=>"list", :editable=>false),
287                 nil,
288                 [ item(:button, :title=>"Update",
289                         :action=>lambda { |it| 
290                           list = Dialog.list_remote_files(value("host"), value("directory"))
291                           set_value("list", list)
292                         }
293                   ), {:align=>:right} ],
294         #       item(:checkbox, :title=>"Copy files to a local directory"),
295         #       nil,
296                 item(:text, :title=>"Local directory"),
297                 item(:textfield, :width=>280, :height=>20, :tag=>"local"),
298                 nil,
299                 [ item(:button, :title=>"Choose...",
300                     :action=>lambda { |it|
301                           dir = Dialog.open_panel(nil, nil, nil, true)
302                           if dir
303                             set_value("local", dir)
304                           end
305                     }
306                   ), {:align=>:right} ]
307         #       layout(1, 2, 1, 0)
308           )
309           set_attr(0, :action=>:button_action)
310           set_attr(1, :action=>:button_action)
311           set_attr(0, :enabled=>false)
312           self.each_item { |it|
313                 tag = it[:tag]
314             if (type = it[:type]) == :textfield || type == :textview
315                   val = get_global_settings("load_remote.#{tag}")
316                   if (val != nil)
317                         set_value(tag, val)
318                   end
319                 end
320           }
321     }
322         hash.each_pair { |key, value|
323           next if key == :status
324           set_global_settings("load_remote.#{key}", value)
325         }
326         if hash[:status] == 0
327           sfile = hash["sfile"]
328           cfile = hash["cfile"]
329           host = hash["host"]
330           directory = hash["directory"]
331           local = hash["local"]
332           if local == ""
333             local = `mktemp -d /tmp/MolbyRemoteLoad.XXXXXX`.chomp
334                 if $? != 0
335                   raise "Cannot create a temporary directory"
336                 end
337           end
338           local = File.expand_path(local)
339           if cfile == "" && sfile =~ /\.psf$/
340             cfile = sfile.sub(/\.psf$/, ".pdb")
341           end
342           if cfile == ""
343             files = sfile
344           else
345             files = "{#{sfile},#{cfile}}"
346           end
347           show_progress_panel("Fetching remote file(s)...")
348           if !system("scp '#{host}:#{directory}/#{files}' '#{local}'")
349             raise "Cannot copy remote files"
350           end
351           hide_progress_panel()
352           mol = Molecule.open("#{local}/#{sfile}")
353           if cfile != "" && FileTest.exist?("#{local}/#{cfile}")
354             mol.undo_enabled = false
355             mol.molload("#{local}/#{cfile}")
356                 mol.undo_enabled = true
357           end
358         end
359   end
360
361   def cmd_delete_frames
362     n = nframes
363     return if n == 0
364         hash = Dialog.run {
365           layout(2,
366             item(:text, :title=>"Start"),
367             item(:textfield, :width=>120, :tag=>"start", :value=>"0"),
368                 item(:text, :title=>"End"),
369                 item(:textfield, :width=>120, :tag=>"end", :value=>(n - 1).to_s),
370                 item(:text, :title=>"Keeping frames every..."),
371                 -1,
372                 item(:text, :title=>"Step"),
373                 item(:textfield, :width=>120, :tag=>"step", :value=>"0"))
374         }
375         if hash[:status] == 0
376           sframe = Integer(hash["start"])
377           eframe = Integer(hash["end"])
378           step = Integer(hash["step"])
379           return if sframe > eframe
380           eframe = n - 1 if eframe >= n
381           fgroup = IntGroup[sframe..eframe]
382           if step > 0
383             while sframe <= eframe
384                   fgroup.delete(sframe)
385                   sframe += step
386                 end
387           end
388           remove_frames(fgroup)
389         end
390   end
391
392   def cmd_solvate
393     #  Find molecule with unit cell defined
394     solv = []
395         solvnames = []
396         Molecule.list.each { |m|
397           if m.cell != nil
398             solv.push m
399                 solvnames.push m.name
400           end
401     }
402         if solvnames.length == 0
403           Dialog.run {
404             layout(1,
405                   item(:text, :title=>"Please open a molecule file containing a solvent box."))
406           }
407           return
408         end
409         hash = Dialog.run {
410           layout(1,
411             item(:text, :title=>"Choose solvent box:"),
412             item(:popup, :subitems=>solvnames, :tag=>"solvent"),
413                 item(:text, :title=>"Box offset\n(Negative numbers for absolute sizes)"),
414                 layout(2,
415                   item(:text, :title=>"x"),
416                   item(:textfield, :width=>"120", :tag=>"x", :value=>"10.0"),
417                   item(:text, :title=>"y"),
418                   item(:textfield, :width=>"120", :tag=>"y", :value=>"10.0"),
419                   item(:text, :title=>"z"),
420                   item(:textfield, :width=>"120", :tag=>"z", :value=>"10.0")),
421                 item(:text, :title=>"Exclusion limit distance:"),
422                 item(:textfield, :width=>"120", :tag=>"limit", :value=>"3.0"))
423         }
424         if hash[:status] == 0
425           solvate(solv[hash["solvent"]], [hash["x"], hash["y"], hash["z"]], hash["limit"])
426         end
427   end
428      
429   def cmd_show_graphite
430     n = self.show_graphite
431         flag = self.show_graphite?
432         hash = Dialog.run("Show Graphite") {
433       layout(1,
434             item(:checkbox, :title=>"Show graphite", :tag=>"show_graphite", :value=>(flag ? 1 : 0),
435                   :action=>lambda { |it| set_attr("graphite", :enabled=>(it[:value] == 1)) } ),
436             item(:text, :title=>"Number of graphite rings for each direction:"),
437             item(:textfield, :width=>120, :tag=>"graphite", :value=>n.to_s, :enabled=>flag))
438         }
439         if hash[:status] == 0
440           self.show_graphite(hash["graphite"])
441           self.show_graphite(hash["show_graphite"] == 1 ? true : false)
442         end
443   end
444   
445   #  DEBUG
446   def cmd_test
447     $test_dialog = Dialog.new("Test") { item(:text, :title=>"test"); show }
448   end
449   
450 end
451
452 register_menu("Assign residue...", :cmd_assign_residue)
453 register_menu("Offset residue...", :cmd_offset_residue)
454 register_menu("Sort by residue", :cmd_sort_by_residue)
455 register_menu("", "")
456 register_menu("Load remote...", :cmd_load_remote)
457 #register_menu("Create GAMESS input...", :cmd_create_gamess)
458 #register_menu("Create Cube file...", :cmd_create_cube)
459 register_menu("", "")
460 register_menu("Delete Frames...", :cmd_delete_frames)
461 register_menu("Solvate...", :cmd_solvate)
462 #register_menu("cmd test", :cmd_test)