OSDN Git Service

882e8633cfa09fb86e8f18dd98e4fb41d004c7e2
[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("Assign Residue") {
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("Offset Residues") {
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 cmd_delete_frames
73     n = nframes
74     return if n == 0
75         hash = Dialog.run("Delete Frames") {
76           layout(2,
77             item(:text, :title=>"Start"),
78             item(:textfield, :width=>120, :tag=>"start", :value=>"0"),
79                 item(:text, :title=>"End"),
80                 item(:textfield, :width=>120, :tag=>"end", :value=>(n - 1).to_s),
81                 item(:text, :title=>"Keeping frames every..."),
82                 -1,
83                 item(:text, :title=>"Step"),
84                 item(:textfield, :width=>120, :tag=>"step", :value=>"0"))
85         }
86         if hash[:status] == 0
87           sframe = Integer(hash["start"])
88           eframe = Integer(hash["end"])
89           step = Integer(hash["step"])
90           return if sframe > eframe
91           eframe = n - 1 if eframe >= n
92           fgroup = IntGroup[sframe..eframe]
93           if step > 0
94             while sframe <= eframe
95                   fgroup.delete(sframe)
96                   sframe += step
97                 end
98           end
99           remove_frames(fgroup)
100         end
101   end
102
103   def cmd_reverse_frames
104     n = nframes
105     return if n == 0
106         hash = Dialog.run("Reverse Frames") {
107           layout(2,
108             item(:text, :title=>"Start"),
109             item(:textfield, :width=>120, :tag=>"start", :value=>"0"),
110                 item(:text, :title=>"End"),
111                 item(:textfield, :width=>120, :tag=>"end", :value=>(n - 1).to_s))
112         }
113         if hash[:status] == 0
114           sframe = Integer(hash["start"])
115           eframe = Integer(hash["end"])
116           return if sframe > eframe
117           eframe = n - 1 if eframe >= n
118           frames = (0...sframe).to_a + (sframe..eframe).to_a.reverse + ((eframe + 1)...n).to_a
119           reorder_frames(frames)
120         end
121   end
122
123   def cmd_extra_properties
124     mol = self
125         get_count = lambda { |it| mol.nframes }
126         get_value = lambda { |it, row, col|
127           if col == 0
128             row.to_s
129           else
130             sprintf("%.8f", mol.get_property(col - 1, row)) rescue ""
131           end
132     }
133     mol.open_auxiliary_window("Extra Props", nil, nil, :resizable=>true, :has_close_box=>true) {
134           names = nil
135           @on_document_modified = lambda { |m|
136             if (n = m.property_names) != names
137                   names = n
138                   col = [["frame", 40]] + names.map { |nn| [nn, 120] }
139                   item_with_tag("table")[:columns] = col
140                 end
141                 item_with_tag("table")[:refresh] = true
142           }
143           layout(1,
144                 item(:table, :width=>320, :height=>300, :flex=>[0,0,0,0,1,1], :tag=>"table",
145                   :on_count=>get_count,
146                   :on_get_value=>get_value),
147             :flex=>[0,0,0,0,1,1]
148           )
149           set_min_size(320, 200)
150           # listen(mol, "documentModified", on_document_modified)
151           # listen(mol, "documentWillClose", lambda { |m| close } )
152           on_document_modified.call(mol)
153           show
154         }
155   end
156   
157   def cmd_show_energy
158         wave = [0.0, 0.0]
159         cur = 0
160         mol = self
161         d = open_auxiliary_window("Energy", nil, nil, :resizable=>true, :has_close_box=>true) {
162           graph_item = nil   #  Forward declaration
163           target_mol = nil
164           draw_graph = lambda { |it|
165                 clear
166                 f = graph_item[:frame]
167                 draw_rectangle(0, 0, f[2], f[3])
168                 width = f[2] - 25
169                 height = f[3] - 25
170                 draw_line(16, 0, 16, height + 12, width + 20, height + 12)
171                 xx = yy = nil
172                 min = wave.min
173                 h = wave.max - min
174                 h = (h == 0.0 ? 1.0 : height / h)
175                 w = wave.count
176                 w = (w == 0 ? 1.0 : Float(width) / w)
177                 a = []
178                 wave.each_with_index { |d, i|
179                   a.push(i * w + 16)
180                   a.push(height - (d - min) * h + 12)
181                 }
182                 if wave.count == 1
183                   a.push(w + 16)
184                   a.push(height - (wave[0] - min) * h + 12)
185                 end
186                 draw_line(a)
187                 brush(:color=>[0.2, 0.2, 1.0])
188                 y = wave[cur] || 0.0
189                 xx = cur * w + 16
190                 yy = height - (y - min) * h + 12
191                 draw_ellipse(cur * w + 16, height - (y - min) * h + 12, 6)
192           }
193           @on_document_modified = lambda { |m|
194                 cur = mol.frame
195                 wave.clear
196                 if mol.nframes < 2
197                   wave = [mol.get_property("energy", 0)] * 2
198                 else
199                   wave = (0...mol.nframes).map { |i| mol.get_property("energy", i) }
200                 end
201                 f = graph_item[:frame]
202                 item_with_tag("energy")[:title] = sprintf("Energy = %.10f hartree, Frame = %d", mol.get_property("energy", cur), cur)
203                 graph_item.refresh_rect([0, 0, f[2], f[3]])
204           }
205           layout(1,
206                 item(:text, :title=>"Energy =                 ", :tag=>"energy"),
207                 item(:view, :frame=>[0, 0, 320, 240], :tag=>"graph", :on_paint=>draw_graph, :flex=>[0,0,0,0,1,1]),
208         #       item(:button, :title=>"Update", :action=>doc_modified, :align=>:center, :flex=>[1,1,1,0,0,0]),
209         #       item(:button, :title=>"Close", :action=>proc { hide }, :align=>:center, :flex=>[1,1,1,0,0,0]),
210                 :flex=>[0,0,0,0,1,1]
211           )
212           graph_item = item_with_tag("graph")
213           size = self.size
214           set_min_size(size)
215           set_size(500, 300)
216           @on_document_modified.call(mol)
217           show
218         }
219         self
220   end
221   
222   def cmd_create_surface
223     mol = self
224         mol.open_auxiliary_window("MO Surface", nil, nil, :resizable=>true, :has_close_box=>true) {
225           motype = mol.get_mo_info(:type)
226           alpha = mol.get_mo_info(:alpha)
227           beta = mol.get_mo_info(:beta)
228           ncomps = mol.get_mo_info(:ncomps)
229           mo_index = 1
230           mo_ao = nil
231           coltable = [[0,0,1], [1,0,0], [0,1,0], [1,1,0], [0,1,1], [1,0,1], [0,0,0]]
232           if (motype == "RHF")
233             beta = nil
234           end
235           i = (beta ? 2 : 1)
236           mo_menu = ["1000 (-00.00000000)"]  #  Dummy entry; create later
237           tabvals = []
238           coeffs = nil
239           a_idx_old = -1
240           ncomps.times { |i|
241             a_idx, label, nprims = mol.get_gaussian_shell_info(i)
242                 if a_idx_old != a_idx
243                   a_idx_old = a_idx
244                   a = a_idx.to_s
245                   n = mol.atoms[a_idx].name
246                 else
247                   a = n = ""
248                 end
249                 tabvals.push([a, n, label, a_idx])
250           }
251           on_get_value = lambda { |it, row, col|
252             if col < 3
253                   tabvals[row][col]
254                 else
255                   if coeffs == nil
256                     if mo_ao == 0
257                       coeffs = mol.get_mo_coefficients(mo_index)
258                     else
259                       coeffs = (0...ncomps).map { |i| (i == mo_index ? 1.0 : 0.0) }
260                         end
261                   end
262                   sprintf("%.6f", coeffs[row])
263                 end
264           }
265           h = {"mo"=>nil, "color"=>nil, "opacity"=>nil, "threshold"=>nil, "expand"=>nil, "grid"=>nil}
266           should_update = true
267           on_action = lambda { |it|
268             tag = it[:tag]
269                 value = it[:value]
270                 if tag == "color" || tag == "opacity"
271                   opac = value("opacity").to_f
272                   opac = 0.0 if opac < 0.0
273                   opac = 1.0 if opac > 1.0
274                   col = value("color")
275                   color = coltable[col] + [opac]
276                   color0 = [1,1,1,opac]
277                   mol.set_surface_attr(:color=>color, :color0=>color0)
278                   h[tag] = value
279                 elsif tag == "threshold"
280               thres = it[:value].to_f
281                   thres = 0.001 if thres >= 0.0 && thres < 0.001
282                   thres = -0.001 if thres <= 0.0 && thres > -0.001
283                   mol.set_surface_attr(:thres=>thres)
284                   h[tag] = value
285                 else
286               should_update = false
287               h.each_key { |key|
288                     val = value(key)
289                     if val && h[key] != val
290                       should_update = true
291                       break
292                     end
293                   }
294                   item_with_tag("update")[:enabled] = should_update
295                 end
296           }
297           on_mo_action = lambda { |it|
298             mo = it[:value]
299                 if mo_ao == 0
300                   if beta
301                     mo_index = (mo / 2) + (mo % 2 == 1 ? ncomps : 0) + 1
302                   else
303                     mo_index = mo + 1
304                   end
305                 else
306                   mo_index = mo
307                 end
308                 coeffs = nil
309                 item_with_tag("table")[:refresh] = true
310             on_action.call(it)
311           }
312           on_set_action = lambda { |it|
313             if mo_ao != it[:value]
314                   mo_ao = it[:value]
315                   if mo_ao == 0
316                     mo_menu = (1..(ncomps * i)).map { |n|
317                   if beta
318                         i1 = (n - 1) / 2 + 1
319                         i2 = n % 2
320                         c1 = (i2 == 0 ? "B" : "A")
321                         c2 = (i1 > (i2 == 0 ? beta : alpha) ? "*" : "")
322                       else
323                         i1 = n
324                         i2 = 1
325                         c1 = ""
326                         c2 = (i1 > alpha ? "*" : "")
327                       end
328                       en = mol.get_mo_energy(i1 + (i2 == 0 ? ncomps : 0))
329                       sprintf("%d%s%s (%.8f)", i1, c1, c2, en)
330                         }
331                   else
332                     mo_menu = []
333                     ncomps.times { |i|
334                           mo_menu[i] = sprintf("AO%d: %s (%s)", i + 1, tabvals[i][2], mol.atoms[tabvals[i][3]].name)
335                         }
336                   end
337                   it0 = item_with_tag("mo")
338                   it0[:subitems] = mo_menu
339                   it0[:value] = 0
340                   on_mo_action.call(it0)
341                 end
342           }
343           on_update = lambda { |it|
344             h.each_key { |key|
345                   h[key] = value(key)
346                 }
347                 opac = h["opacity"].to_f
348                 opac = 0.0 if opac < 0.0
349                 opac = 1.0 if opac > 1.0
350                 color = coltable[h["color"]] + [opac]
351                 color0 = [1, 1, 1, opac]
352                 thres = h["threshold"].to_f
353                 thres = 0.001 if thres >= 0.0 && thres < 0.001
354                 thres = -0.001 if thres <= 0.0 && thres > -0.001
355                 expand = h["expand"].to_f
356                 expand = 0.01 if expand < 0.01
357                 expand = 10.0 if expand > 10.0
358                 grid = h["grid"].to_i
359                 if grid > 10000000
360                   grid = 10000000
361                 end
362                 if mo_ao == 0
363                   idx = mo_index
364                 else
365                   idx = 0
366                   mol.set_mo_coefficients(0, 0.0, coeffs)
367                 end
368                 mol.create_surface(idx, :npoints=>grid, :color=>color, :thres=>thres, :expand=>expand, :color0=>color0)
369                 on_action.call(it)
370           }
371           layout(1,
372             layout(2,
373                   item(:text, :title=>"Orbital Set"),
374                   item(:popup, :tag=>"mo_ao", :subitems=>["Molecular Orbitals", "Atomic Orbitals"], :action=>on_set_action),
375               item(:text, :title=>"Select"),
376               item(:popup, :tag=>"mo", :subitems=>mo_menu, :action=>on_mo_action)),
377                 layout(4,
378                   item(:text, :title=>"Color"),
379                   item(:popup, :tag=>"color", :subitems=>["blue", "red", "green", "yellow", "cyan", "magenta", "black"], :action=>on_action),
380                   item(:text, :title=>"Opacity"),
381                   item(:textfield, :tag=>"opacity", :width=>80, :value=>"0.6", :action=>on_action),
382                   item(:text, :title=>"Threshold"),
383                   item(:textfield, :tag=>"threshold", :width=>80, :value=>"0.05", :action=>on_action),
384                   item(:text, :title=>"Box Limit"),
385                   item(:textfield, :tag=>"expand", :width=>80, :value=>"1.0", :action=>on_action)),
386                 layout(2,
387                   item(:text, :title=>"Number of Grid Points"),
388                   item(:textfield, :tag=>"grid", :width=>120, :value=>"512000", :action=>on_action)),
389             item(:table, :width=>300, :height=>300, :tag=>"table",
390                   :columns=>[["Atom", 60], ["Name", 60], ["Label", 60], ["Coeff", 120]],
391                   :on_count=> lambda { |it| tabvals.count },
392                   :on_get_value=>on_get_value,
393                   :flex=>[0,0,0,0,1,1]),
394                 item(:button, :tag=>"update", :title=>"Update", :action=>on_update, :flex=>[0,1,0,0,0,0]),
395                 :flex=>[0,0,0,0,1,1]
396           )
397           on_set_action.call(item_with_tag("mo_ao"))
398           size = self.size
399           set_min_size(size[0], 250)
400           item_with_tag("table")[:refresh] = true
401           show
402     }
403   end
404   
405   #  DEBUG
406   def cmd_test
407     $test_dialog = Dialog.new("Test") { item(:text, :title=>"test"); show }
408   end
409   
410 end
411
412 module Kernel
413   def ask_scratch_dir
414     sdir = get_global_settings("global.scratch_dir")
415         while 1
416       p = Dialog.open_panel("Please select scratch directory", sdir, nil, true)
417           if p
418             if p =~ / /
419                   error_message_box("Please avoid path containing a white space.\n" + p.sub(/ /, "<!> <!>"))
420                   sdir = p
421                   next
422                 else
423                   set_global_settings("global.scratch_dir", p)
424                   return p
425             end
426           else
427             return nil
428           end
429         end
430   end
431 end
432
433 register_menu("Assign residue...", :cmd_assign_residue, :non_empty)
434 register_menu("Offset residue...", :cmd_offset_residue, :non_empty)
435 register_menu("Sort by residue", :cmd_sort_by_residue, :non_empty)
436 register_menu("", "")
437 register_menu("Delete Frames...", :cmd_delete_frames, lambda { |m| m && m.nframes > 1 } )
438 register_menu("Reverse Frames...", :cmd_reverse_frames, lambda { |m| m && m.nframes > 1 } )
439 register_menu("", "")
440 register_menu("Show Energy Window...", :cmd_show_energy, lambda { |m| m && m.property_names.include?("energy") } )
441 register_menu("Show MO Surface...", :cmd_create_surface, lambda { |m| m && m.get_mo_info(:type) != nil } )
442 #register_menu("cmd test", :cmd_test)
443