coderunner 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/README.rdoc +19 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/coderunner.rb +419 -0
- data/lib/coderunner/class_methods.rb +727 -0
- data/lib/coderunner/fortran_namelist.rb +1281 -0
- data/lib/coderunner/graphs_and_films.rb +744 -0
- data/lib/coderunner/heuristic_run_methods.rb +202 -0
- data/lib/coderunner/instance_methods.rb +1741 -0
- data/lib/coderunner/interactive_methods.rb +776 -0
- data/lib/coderunner/long_regexen.rb +201 -0
- data/lib/coderunner/merged_code_runner.rb +40 -0
- data/lib/coderunner/run.rb +1000 -0
- data/test/helper.rb +18 -0
- data/test/test_coderunner.rb +7 -0
- metadata +139 -0
@@ -0,0 +1,727 @@
|
|
1
|
+
class CodeRunner
|
2
|
+
|
3
|
+
# In the next section are the implementations of all the standard Code Runner commands and some helper functions.
|
4
|
+
|
5
|
+
def self.set_runner_defaults(copts = {})
|
6
|
+
(DEFAULT_RUNNER_OPTIONS.keys - [:sys, :script_folder]).each do |var|
|
7
|
+
DEFAULT_RUNNER_OPTIONS[var] = copts[LONG_TO_SHORT[var]]
|
8
|
+
end
|
9
|
+
set_class_defaults(copts)
|
10
|
+
# ep DEFAULT_RUNNER_OPTIONS
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.set_class_defaults(copts={})
|
14
|
+
(CLASS_OPTIONS.keys - []).each do |var|
|
15
|
+
CLASS_OPTIONS[var] = copts[LONG_TO_SHORT[var]]
|
16
|
+
set(var, CLASS_OPTIONS[var])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# List the available modlets for the given code (copts[:C] or -C on the command line).
|
21
|
+
|
22
|
+
def self.available_modlets(copts={})
|
23
|
+
process_command_options(copts)
|
24
|
+
puts "\nAvailable modlets for #{copts[:C]}:"
|
25
|
+
entries = []
|
26
|
+
begin
|
27
|
+
entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/my_modlets")
|
28
|
+
rescue
|
29
|
+
end
|
30
|
+
begin
|
31
|
+
entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/default_modlets")
|
32
|
+
rescue
|
33
|
+
end
|
34
|
+
entries.each do |modlet|
|
35
|
+
puts "\t" + File.basename(modlet, '.rb') unless ['.', '..', '.svn', '.directory'].include? modlet or modlet=~ /defaults/
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# List the available defaults files for the given code (copts[:C] or -C on the command line).
|
40
|
+
|
41
|
+
def self.available_defaults_files(copts={})
|
42
|
+
process_command_options(copts)
|
43
|
+
puts "\nAvailable defaults files for #{copts[:C]}:"
|
44
|
+
entries = []
|
45
|
+
begin
|
46
|
+
entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/my_defaults_files")
|
47
|
+
rescue
|
48
|
+
end
|
49
|
+
begin
|
50
|
+
entries += Dir.entries(SCRIPT_FOLDER + "/code_modules/#{copts[:C]}/defaults_files")
|
51
|
+
rescue
|
52
|
+
end
|
53
|
+
entries.each do |defaults_file|
|
54
|
+
puts "\t" + File.basename(defaults_file, '.rb').sub(/_defaults/, '') unless ['.', '..', '.svn', '.directory'].include? defaults_file
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Cancel the job with the given id. The user is asked interactively for confirmation and whether they would like to delete the folder for that job as well.
|
59
|
+
|
60
|
+
def self.cancel(id, copts={})
|
61
|
+
runner = fetch_runner(copts)
|
62
|
+
runner.cancel_job(id.to_i)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.continue_in_new_folder(folder, copts={})
|
66
|
+
runner=fetch_runner(copts)
|
67
|
+
options = {}
|
68
|
+
if copts[:f] or copts[:j]
|
69
|
+
options[:copy_ids] = runner.filtered_ids
|
70
|
+
end
|
71
|
+
|
72
|
+
runner.continue_in_new_folder(folder, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.delete(copts={})
|
76
|
+
runner = fetch_runner(copts)
|
77
|
+
runner.destroy
|
78
|
+
end
|
79
|
+
|
80
|
+
# def self.executable_name # :nodoc:
|
81
|
+
# ""
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# def self.rcp # :nodoc:
|
85
|
+
# @rcp ||= KitHash.new
|
86
|
+
# end
|
87
|
+
def self.netcdf_plot(netcdf_file, vars, indices, copts={})
|
88
|
+
process_command_options(copts)
|
89
|
+
begin
|
90
|
+
require "numru/netcdf"
|
91
|
+
rescue LoadError
|
92
|
+
eputs "Error: No Ruby NetCDF library (was it installed correctly?): data analysis for netcdf files not possible."
|
93
|
+
return
|
94
|
+
end
|
95
|
+
start_indices = indices.split(',').map{|idx| idx = idx.split(':')[0] if idx =~ /:/ ; eval(idx) || 0}
|
96
|
+
end_indices = indices.split(',').map{|idx| idx = idx.split(':')[1] if idx =~ /:/ ; eval(idx) || -1}
|
97
|
+
|
98
|
+
ep 'start_indices', start_indices, 'end_indices', end_indices
|
99
|
+
file = NumRu::NetCDF.open(netcdf_file)
|
100
|
+
to_plot = vars.split(',').map do |var|
|
101
|
+
ep 'var', var
|
102
|
+
[file.var(var).get('start'=> start_indices, 'end'=> end_indices).to_a.flatten]
|
103
|
+
end
|
104
|
+
ep 'to_plot', to_plot
|
105
|
+
kit = GraphKit.quick_create(*to_plot)
|
106
|
+
ep 'copts', copts
|
107
|
+
kit.instance_eval(copts[:w]) if copts[:w]
|
108
|
+
kit.gnuplot
|
109
|
+
STDIN.gets
|
110
|
+
kit.close
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
def self.print_queue_status(copts={})
|
116
|
+
begin
|
117
|
+
eputs queue_status
|
118
|
+
rescue => err
|
119
|
+
eputs "General queue status doesn't work on this system; showing queue status for this folder"
|
120
|
+
# p err
|
121
|
+
runner = fetch_runner(copts)
|
122
|
+
eputs runner.queue_status
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
def self.reference(class_or_method, copts={})
|
131
|
+
code_folders = Dir.recursive_entries(SCRIPT_FOLDER + '/code_modules').grep(/\/ri$/).map{|fold| ['-d', fold]}.flatten
|
132
|
+
# ep code_folders
|
133
|
+
|
134
|
+
# require 'rdoc/ri/driver'
|
135
|
+
|
136
|
+
# "
|
137
|
+
# op = @ri_count ? [] : (@ri_count = true; ['--no-use-cache'])
|
138
|
+
# trap(1){puts 'No help available'}
|
139
|
+
# at_exit{raise ""}
|
140
|
+
# p op
|
141
|
+
begin
|
142
|
+
eputs "Looking up #{class_or_method}"
|
143
|
+
RDoc::RI::Driver.run ['-d', SCRIPT_FOLDER + '/ri', class_or_method.to_s] + code_folders
|
144
|
+
rescue => err
|
145
|
+
eputs "Unknown class or method or no help available: #{err}"
|
146
|
+
end
|
147
|
+
# trap(1){}
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
def self.directory(id, copts={})
|
152
|
+
runner = fetch_runner(copts)
|
153
|
+
puts runner.run_list[id.to_i].directory
|
154
|
+
end
|
155
|
+
def self.film(copts={})
|
156
|
+
runner = fetch_runner(copts)
|
157
|
+
copts[:F][:graphkit_modify] = copts[:w]
|
158
|
+
runner.make_film_from_lists(copts[:G], copts[:g], copts[:F])
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.generate_documentation(username = nil, copts = {})
|
162
|
+
ep 'username', username||=ENV['USER']
|
163
|
+
|
164
|
+
####### Here we use the command line documentation to generate a fake ruby file that rdoc will understand.
|
165
|
+
File.open("class_methods_rdoc.rb", 'w') do |file|
|
166
|
+
file.puts <<EOF
|
167
|
+
class CodeRunner
|
168
|
+
|
169
|
+
|
170
|
+
#{COMMANDS_WITH_HELP.inject("") do |str, (long, short, nargs, comhelp, argnames, options)|
|
171
|
+
(puts "Please run this command in the coderunner trunk directory"; exit) unless Dir.pwd =~ /coderunner\/trunk$/
|
172
|
+
str << <<EOF2
|
173
|
+
# #{comhelp.gsub(/\n/, "\n # ")}
|
174
|
+
#
|
175
|
+
# Possible options:
|
176
|
+
#
|
177
|
+
#{options.inject("") do |str, opt|
|
178
|
+
longop, shortop, req, ophelp = COMMAND_LINE_FLAGS_WITH_HELP.find{|arr| arr[1] == "-" + opt.to_s}
|
179
|
+
str << " # :#{opt} --- #{ophelp.gsub(/\n/, "\n # ")}\n #\n"
|
180
|
+
end}
|
181
|
+
|
182
|
+
def self.#{long}(#{(argnames+[""]).join(",")}command_options={})
|
183
|
+
end
|
184
|
+
|
185
|
+
EOF2
|
186
|
+
end
|
187
|
+
}
|
188
|
+
end
|
189
|
+
EOF
|
190
|
+
end
|
191
|
+
# exit
|
192
|
+
|
193
|
+
system "rm -rf doc/"
|
194
|
+
system "rm -rf ri/"
|
195
|
+
raise 'Please set RDOC_COMMAND' unless ENV['RDOC_COMMAND']
|
196
|
+
system "#{ENV['RDOC_COMMAND']} --format=html -t 'CodeRunner Documentation' -m INDEX.rb INDEX.rb code_runner_version.rb gnuplot.rb graphkit_gnuplot.rb graphkit.rb gsl_tools.rb run_backwards_compatibility.rb feedback.rb run.rb fortran_namelist.rb graphs_and_films.rb class_methods_rdoc.rb instance_methods.rb"
|
197
|
+
system "#{ENV['RDOC_COMMAND']} -r --op ri INDEX.rb code_runner_version.rb gnuplot.rb graphkit_gnuplot.rb graphkit.rb gsl_tools.rb run_backwards_compatibility.rb feedback.rb run.rb fortran_namelist.rb graphs_and_films.rb class_methods_rdoc.rb instance_methods.rb"
|
198
|
+
|
199
|
+
exit if username == ""
|
200
|
+
|
201
|
+
string = "rsync -av --delete doc/ #{username},coderunner@web.sourceforge.net:htdocs/api_documentation/"
|
202
|
+
|
203
|
+
puts string
|
204
|
+
exec string
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.start_launcher(refresh, max_queue, copts={})
|
209
|
+
raise "Raise refresh is #{refresh}: it must be >= 1" if refresh.to_i < 1
|
210
|
+
raise "Raise max_queue is #{max_queue}: it must be >= 5" if max_queue.to_i < 5
|
211
|
+
#raise "Launcher already running" if %x[ps -e -o cmd].split("\n").grep(/coderunner\s+launch/).size > 0
|
212
|
+
require 'thread'
|
213
|
+
tl = ENV['HOME'] + "/.coderunner_to_launch_#{ENV['CODE_RUNNER_LAUNCHER']}" #SCRIPT_FOLDER + '/to_launch'
|
214
|
+
exit unless Feedback.get_boolean( "Launch directory #{tl} already exists: it is suggested that you change the prefix by changing the environment variable CODE_RUNNER_LAUNCHER. Do you wish to continue (don't select yes unless you know what you are doing)?") if FileTest.exist? tl
|
215
|
+
# FileUtils.rm_r tl if FileTest.exist? tl
|
216
|
+
eputs "Starting launcher\n"
|
217
|
+
at_exit{FileUtils.rm_r tl}
|
218
|
+
FileUtils.makedirs tl
|
219
|
+
Thread.new{loop{`cp #{tl}/queue_status.txt #{tl}/queue_status2.txt; ps > #{tl}/queue_status.txt`; sleep 1}}
|
220
|
+
|
221
|
+
mutex = Mutex.new
|
222
|
+
processes= []
|
223
|
+
|
224
|
+
Thread.new do
|
225
|
+
loop do
|
226
|
+
Dir.entries(tl).each do |file|
|
227
|
+
next unless file =~ (/(^.*)\.stop/)
|
228
|
+
pid = $1
|
229
|
+
mutex.synchronize{Process.kill(pid); processes.delete pid}
|
230
|
+
end
|
231
|
+
sleep refresh.to_i
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
Dir.chdir(tl) do
|
236
|
+
ppid = $$
|
237
|
+
loop do
|
238
|
+
sleep refresh.to_i while processes.size >= max_queue.to_i
|
239
|
+
# processes = []
|
240
|
+
Dir.entries(tl).grep(/(^.*)\.start/).each do |file|
|
241
|
+
file =~ (/(^.*)\.start/)
|
242
|
+
id = $1
|
243
|
+
command = File.read file
|
244
|
+
pid = fork do
|
245
|
+
processes.each do |wpid|
|
246
|
+
sleep refresh.to_i while %x[ps -e -o pid,ppid].split("\n").grep(Regexp.new("^\\s*#{wpid}\\s+#{ppid}")).size > 0
|
247
|
+
end
|
248
|
+
exec(command)
|
249
|
+
end
|
250
|
+
`cp #{tl}/queue_status.txt #{tl}/queue_status2.txt; ps > #{tl}/queue_status.txt`
|
251
|
+
mutex.synchronize{processes.push pid}
|
252
|
+
|
253
|
+
File.open(id + '.pid', 'w'){|file| file.puts pid}
|
254
|
+
FileUtils.rm(file)
|
255
|
+
|
256
|
+
Thread.new{Process.wait pid; mutex.synchronize{processes.delete pid}}
|
257
|
+
end
|
258
|
+
# processes.each{|pid| Process.wait pid}
|
259
|
+
sleep refresh.to_i
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
def self.code_runner_execute(ruby_fragment, copts={})
|
266
|
+
#eval(ruby_fragment, GLOBAL_BINDING)
|
267
|
+
eval(ruby_fragment)
|
268
|
+
end
|
269
|
+
def self.execute(ruby_fragment, copts={})
|
270
|
+
eval(ruby_fragment, GLOBAL_BINDING)
|
271
|
+
#eval(ruby_fragment)
|
272
|
+
end
|
273
|
+
def self.load_file(files, copts={})
|
274
|
+
process_command_options(copts)
|
275
|
+
# begin
|
276
|
+
files.split(/\s*,\s*/).each do |file|
|
277
|
+
# p file
|
278
|
+
raise ArgumentError.new("#{file} is not a file.") unless File.file? file
|
279
|
+
load file
|
280
|
+
end
|
281
|
+
# rescue
|
282
|
+
# eval(files)
|
283
|
+
# end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.parameter_scan(parameter_scan_array_file, copts={})
|
288
|
+
parameter_scan_array = eval(File.read(parameter_scan_array_file))
|
289
|
+
# process_copts(copts)
|
290
|
+
runner = fetch_runner(copts)
|
291
|
+
skip = true unless copts[:k] == false
|
292
|
+
folder = Dir.pwd
|
293
|
+
Log.logf("self.parameter_scan")
|
294
|
+
# @@runners = {}
|
295
|
+
@@mutex = Mutex.new
|
296
|
+
# @runner = new(folder, code: copts[:C], modlet: copts[:m], version: copts[:v], executable: copts[:X])
|
297
|
+
@@psppipe = PPipe.new(parameter_scan_array.size + 2, true, controller_refresh: 0.5, redirect: false)
|
298
|
+
parameter_scan_array.each do |parameter_scan|
|
299
|
+
@@psppipe.fork do
|
300
|
+
runner.parameter_scan(parameter_scan, copts[:p][0], skip: skip, nprocs: copts[:n])
|
301
|
+
end
|
302
|
+
end
|
303
|
+
@@psppipe.finish
|
304
|
+
@@psppipe = nil
|
305
|
+
end
|
306
|
+
def self.plot_graph(copts = {})
|
307
|
+
# process_copts(copts)
|
308
|
+
runner = fetch_runner(copts)
|
309
|
+
string_to_eval = copts[:w]
|
310
|
+
#options = (options and options =~ /\S/) ? eval(options): {}
|
311
|
+
eputs 'Starting Graph'
|
312
|
+
kit = runner.graphkit_from_lists(copts[:G], copts[:g])
|
313
|
+
kit.gnuplot(eval: string_to_eval)
|
314
|
+
gets
|
315
|
+
kit.close
|
316
|
+
end
|
317
|
+
def self.readout(copts={})
|
318
|
+
# process_copts(copts)
|
319
|
+
runner = fetch_runner(copts)
|
320
|
+
puts runner.readout
|
321
|
+
end
|
322
|
+
def self.recheck(id, copts={})
|
323
|
+
# process_copts(copts)
|
324
|
+
runner = fetch_runner(copts)
|
325
|
+
runner.run_list[copts[:R]].recheck
|
326
|
+
runner.respond_to_requests
|
327
|
+
end
|
328
|
+
def self.code_command(string, copts = {})
|
329
|
+
process_command_options(copts)
|
330
|
+
copts[:no_update] = true
|
331
|
+
unless copts[:C]
|
332
|
+
if FileTest.exist? file=Dir.pwd + '/.code_runner_script_defaults.rb'
|
333
|
+
copts[:C] = eval(File.read(file))[:code]
|
334
|
+
elsif self.runner
|
335
|
+
copts[:C] = self.runner.code
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
run_class = setup_run_class(copts[:C], modlet: copts[:m])
|
340
|
+
run_class.class_eval(string)
|
341
|
+
|
342
|
+
# runner = fetch_runner(copts)
|
343
|
+
# runner.run_class.class_eval(string)
|
344
|
+
end
|
345
|
+
def self.run_command(string, copts={})
|
346
|
+
# process_copts(copts)
|
347
|
+
runner = fetch_runner(copts)
|
348
|
+
|
349
|
+
eputs "Calling run_commmand..."
|
350
|
+
# puts "Warning: Use large cache is on (-U or -u) -- no results will be saved" if runner.use_large_cache
|
351
|
+
ppipe = PPipe.new(runner.filtered_ids.size + 1, false) if copts[:M]
|
352
|
+
no_save = (runner.class == RemoteCodeRunner or copts[:y] =~ /no-save/)
|
353
|
+
# runner.generate_combined_ids
|
354
|
+
# ep runner.filtered_ids
|
355
|
+
runner.filtered_ids.each do |id|
|
356
|
+
run = runner.combined_run_list[id]
|
357
|
+
|
358
|
+
if no_save or run.is_phantom
|
359
|
+
if copts[:M]
|
360
|
+
fork{run.instance_eval(string)}
|
361
|
+
else
|
362
|
+
run.instance_eval(string)
|
363
|
+
end
|
364
|
+
else
|
365
|
+
if copts[:M]
|
366
|
+
pn = ppipe.fork do
|
367
|
+
Dir.chdir(run.directory) do
|
368
|
+
run.instance_eval(string);
|
369
|
+
run.save
|
370
|
+
run.write_results
|
371
|
+
end
|
372
|
+
ppipe.i_send(id, Marshal.dump(run), tp: 0)
|
373
|
+
end
|
374
|
+
else
|
375
|
+
Dir.chdir(run.directory){run.instance_eval(string); run.save; run.write_results}
|
376
|
+
end
|
377
|
+
|
378
|
+
end
|
379
|
+
end
|
380
|
+
unless no_save
|
381
|
+
(runner.filtered_ids.each{|id| runner.run_list[id] = Marshal.load(ppipe.w_recv(id).contents)};ppipe.finish) if copts[:M]
|
382
|
+
runner.save_large_cache
|
383
|
+
end
|
384
|
+
|
385
|
+
# Process.waitall
|
386
|
+
runner.respond_to_requests
|
387
|
+
end
|
388
|
+
def self.runner_eval(string, copts = {})
|
389
|
+
# process_copts(copts)
|
390
|
+
runner = fetch_runner(copts)
|
391
|
+
|
392
|
+
return_val = runner.instance_eval(string)
|
393
|
+
|
394
|
+
if copts[:Z]
|
395
|
+
Kernel.puts(server_dump(return_val))
|
396
|
+
else
|
397
|
+
return return_val
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
def self.scan(scan_string, copts={})
|
402
|
+
# process_copts(copts)
|
403
|
+
runner = fetch_runner(copts)
|
404
|
+
runner.simple_scan(scan_string, nprocs: copts[:n], version: copts[:v], skip: copts[:k], parameters: copts[:p][0])
|
405
|
+
end
|
406
|
+
def self.submit(copts = {})
|
407
|
+
# process_copts(copts)
|
408
|
+
runner = fetch_runner(copts)
|
409
|
+
# raise "something is already submitting" if FileTest.exist? "submitting"
|
410
|
+
runs = []
|
411
|
+
raise "Parameters must be an array of inspected hashes" unless copts[:p].kind_of? Array
|
412
|
+
Dir.chdir(copts[:Y]) do
|
413
|
+
|
414
|
+
copts[:p].push nil if copts[:p] == []
|
415
|
+
# ep copts[:p]; exit
|
416
|
+
copts[:p].each do |pars|
|
417
|
+
run = runner.run_class.new(runner)
|
418
|
+
# p pars
|
419
|
+
run.update_submission_parameters(pars)
|
420
|
+
runs.push run
|
421
|
+
end
|
422
|
+
# exit
|
423
|
+
end
|
424
|
+
runner.submit(runs, nprocs: copts[:n], version: copts[:v], skip: copts[:k], job_chain: copts[:J], no_update_before_submit: copts[:no_update_before_submit])
|
425
|
+
end
|
426
|
+
def self.resubmit(copts = {})
|
427
|
+
# process_copts(copts)
|
428
|
+
runner = fetch_runner(copts)
|
429
|
+
# raise "something is already submitting" if FileTest.exist? "submitting"
|
430
|
+
runs = []
|
431
|
+
raise "Parameters must be an array of inspected hashes" unless copts[:p].kind_of? Array
|
432
|
+
Dir.chdir(copts[:Y]) do
|
433
|
+
runs = runner.filtered_ids.map do |id|
|
434
|
+
eputs id
|
435
|
+
run = runner.run_list[id].dup
|
436
|
+
if copts[:smart_resubmit_name]
|
437
|
+
eputs "Smart name"
|
438
|
+
run.set(:naming_pars, [:resubmit_id])
|
439
|
+
run.resubmit_id = run.id
|
440
|
+
end
|
441
|
+
run.update_submission_parameters(copts[:p][0], false)
|
442
|
+
run.run_name = nil unless copts[:rerun]
|
443
|
+
run
|
444
|
+
end
|
445
|
+
end
|
446
|
+
#throw(:here)
|
447
|
+
|
448
|
+
runner.submit(runs, nprocs: copts[:n], version: copts[:v], skip: copts[:k], job_chain: copts[:J], no_update_before_submit: copts[:no_update_before_submit], replace_existing: copts[:replace_existing], smart_resubmit_name: copts[:smart_resubmit_name], rerun: copts[:rerun])
|
449
|
+
end
|
450
|
+
|
451
|
+
# This method allows the straightforward submission of a single command using the batch queue on any system.
|
452
|
+
def self.submit_command(jid, comm, copts={})
|
453
|
+
process_command_options(copts)
|
454
|
+
submitter = Object.new
|
455
|
+
submitter.instance_variable_set(:@command, comm)
|
456
|
+
submitter.instance_variable_set(:@jid, jid)
|
457
|
+
submitter.instance_variable_set(:@nprocs, copts[:n])
|
458
|
+
submitter.instance_variable_set(:@wall_mins, copts[:W])
|
459
|
+
submitter.instance_variable_set(:@project, copts[:P])
|
460
|
+
class << submitter
|
461
|
+
include CodeRunner::SYSTEM_MODULE
|
462
|
+
def executable_name
|
463
|
+
'custom'
|
464
|
+
end
|
465
|
+
def job_identifier
|
466
|
+
@jid
|
467
|
+
end
|
468
|
+
def run_command
|
469
|
+
@command
|
470
|
+
end
|
471
|
+
end
|
472
|
+
submitter.execute
|
473
|
+
end
|
474
|
+
|
475
|
+
|
476
|
+
|
477
|
+
def self.readout(copts={})
|
478
|
+
runner = fetch_runner(copts)
|
479
|
+
runner.readout
|
480
|
+
end
|
481
|
+
def self.show_values_of(expression, copts={})
|
482
|
+
runner = fetch_runner(copts)
|
483
|
+
p runner.filtered_ids.map{|id| runner.run_list[id].instance_eval(expression)}.uniq.sort
|
484
|
+
end
|
485
|
+
def self.status_with_comments(copts={})
|
486
|
+
copts[:with_comments] = true
|
487
|
+
status(copts)
|
488
|
+
end
|
489
|
+
def self.status(copts={})
|
490
|
+
# process_copts(copts)
|
491
|
+
runner = fetch_runner(copts)
|
492
|
+
runner.print_out(0, with_comments: copts[:with_comments]) unless copts[:interactive_start] or copts[:Z] or copts[:no_print_out]
|
493
|
+
end
|
494
|
+
def self.status_loop(copts={})
|
495
|
+
# process_copts(copts)
|
496
|
+
runner = fetch_runner(copts)
|
497
|
+
runner.print_out(0, with_comments: copts[:with_comments]) unless copts[:interactive_start] or copts[:Z] or copts[:no_print_out]
|
498
|
+
break_out = false
|
499
|
+
loop do
|
500
|
+
old_trap = trap(2){eputs " Terminating loop, please wait..."; break_out = true}
|
501
|
+
runner.use_large_cache = true
|
502
|
+
runner.update(false)
|
503
|
+
(trap(2, old_trap); break) if break_out
|
504
|
+
runner.recheck_filtered_runs(false)
|
505
|
+
runner.print_out(nil, with_comments: copts[:with_comments])
|
506
|
+
trap(2, old_trap)
|
507
|
+
break if break_out
|
508
|
+
break if not runner.run_list.values.find do |r|
|
509
|
+
not [:Complete, :Failed].include? r.status
|
510
|
+
end
|
511
|
+
#ep "sleep"
|
512
|
+
sleep 3
|
513
|
+
#ep "end sleep"
|
514
|
+
end
|
515
|
+
end
|
516
|
+
def self.write_graph(name, copts={})
|
517
|
+
# process_copts(copts)
|
518
|
+
runner = fetch_runner(copts)
|
519
|
+
eputs 'Starting Graph'
|
520
|
+
kit = runner.graphkit_from_lists(copts[:G], copts[:g])
|
521
|
+
options = copts[:w]
|
522
|
+
options = (options and options =~ /\S/) ? eval(options): {}
|
523
|
+
name = nil unless name =~ /\S/
|
524
|
+
max = 0
|
525
|
+
name.sub!(/^\~/, ENV['HOME']) if name
|
526
|
+
if name and name =~ /%d\./
|
527
|
+
regex = Regexp.new(Regexp.escape(File.basename(name)).sub(/%d/, '(?<number>\d+)'))
|
528
|
+
Dir.entries(File.dirname(name)).join("\n").scan(regex) do
|
529
|
+
max = [max, $~[:number].to_i].max
|
530
|
+
end
|
531
|
+
name = name.sub(/%d/, (max + 1).to_s)
|
532
|
+
end
|
533
|
+
raise "kit doesn't have a file_name and no filename specified; can't write graph" unless name or (kit.file_name.class == String and kit.file_name =~ /\S/)
|
534
|
+
Dir.chdir(COMMAND_FOLDER){kit.gnuplot_write((name or kit.file_name), options)}
|
535
|
+
end
|
536
|
+
def self.read_default_command_options(copts)
|
537
|
+
DEFAULT_COMMAND_OPTIONS.each do |key, value|
|
538
|
+
copts[key] ||= value
|
539
|
+
end
|
540
|
+
end
|
541
|
+
def self.process_command_options(copts)
|
542
|
+
if copts[:true]
|
543
|
+
copts[:true].to_s.split(//).each do |letter|
|
544
|
+
copts[letter.to_sym] = true
|
545
|
+
end
|
546
|
+
end
|
547
|
+
if copts[:false]
|
548
|
+
copts[:false].to_s.split(//).each do |letter|
|
549
|
+
copts[letter.to_sym] = false
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
read_default_command_options(copts)
|
554
|
+
copts.each do |key, value|
|
555
|
+
copts[LONG_TO_SHORT[key]] = value if LONG_TO_SHORT[key]
|
556
|
+
end
|
557
|
+
|
558
|
+
|
559
|
+
if copts[:j] # j can be a number '65' or list of numbers '65,43,382'
|
560
|
+
copts[:f]= "#{eval("[#{copts[:j]}]").inspect}.include? id"
|
561
|
+
end
|
562
|
+
if copts[:z]
|
563
|
+
Log.log_file = Dir.pwd + '/.cr_logfile.txt'
|
564
|
+
Log.clean_up
|
565
|
+
else
|
566
|
+
Log.log_file = nil
|
567
|
+
end
|
568
|
+
copts[:F] = (copts[:F].class == Hash ? copts[:F] : (copts[:F].class == String and copts[:F] =~ /\A\{.*\}\Z/) ? eval(copts[:F]) : {})
|
569
|
+
copts[:G]= [copts[:G]] if copts[:G].kind_of? String
|
570
|
+
copts[:g]= [copts[:g]] if copts[:g].kind_of? String
|
571
|
+
# if copts[:p] and copts[:p].class == String # should be a hash or an inspected hash
|
572
|
+
# copts[:p] = eval(copts[:p])
|
573
|
+
# end
|
574
|
+
copts[:p] = [copts[:p]].compact unless copts[:p].class == Array
|
575
|
+
#for i in 0...copts[:p].size
|
576
|
+
|
577
|
+
copts[:Y] ||= DEFAULT_COMMAND_OPTIONS[:Y] if DEFAULT_COMMAND_OPTIONS[:Y]
|
578
|
+
if copts[:Y] and copts[:Y] =~ /:/
|
579
|
+
set_class_defaults(copts)
|
580
|
+
copts[:running_remotely] = true
|
581
|
+
else
|
582
|
+
copts[:Y].gsub!(/~/, ENV['HOME']) if copts[:Y]
|
583
|
+
Dir.chdir((copts[:Y] or Dir.pwd)) do
|
584
|
+
set_runner_defaults(copts)
|
585
|
+
# ep DEFAULT_RUNNER_OPTIONS
|
586
|
+
end
|
587
|
+
end
|
588
|
+
# ep Log.log_file
|
589
|
+
#copts[:code_copts].each{|k,v| CODE_OPTIONS[k] = v} if copts[:code_copts]
|
590
|
+
copts.keys.map{|k| k.to_s}.grep(/_options$/).map{|k| k.to_sym}.each do |k|
|
591
|
+
CODE_OPTIONS[k.to_s.sub('_options','').to_sym] = copts[k]
|
592
|
+
end
|
593
|
+
|
594
|
+
end
|
595
|
+
|
596
|
+
CODE_OPTIONS={}
|
597
|
+
|
598
|
+
# Retrieve the runner with the folder (and possibly server) given in copts[:Y]. If no runner has been loaded for that folder, load one.
|
599
|
+
|
600
|
+
def self.fetch_runner(copts={})
|
601
|
+
# ep copts
|
602
|
+
# If copts(:Y) is an array of locations, return a merged runner of those locations
|
603
|
+
if copts[:Y].kind_of? Array
|
604
|
+
runners = copts[:Y].map do |location|
|
605
|
+
new_copts = copts.dup.absorb(Y: location)
|
606
|
+
fetch_runner(new_copts)
|
607
|
+
end
|
608
|
+
return Merged.new(*runners)
|
609
|
+
end
|
610
|
+
process_command_options(copts)
|
611
|
+
# ep copts
|
612
|
+
@runners ||= {}
|
613
|
+
runner = nil
|
614
|
+
if copts[:Y] and copts[:Y] =~ /:/
|
615
|
+
copts_r = copts.dup
|
616
|
+
host, folder = copts[:Y].split(':')
|
617
|
+
copts_r[:Y] = nil
|
618
|
+
copts[:Y] = nil
|
619
|
+
unless @runners[[host, folder]]
|
620
|
+
runner = @runners[[host, folder]] = RemoteCodeRunner.new(host, folder, copts)
|
621
|
+
(eputs 'Updating remote...'; runner.update) unless (copts[:g] and (copts[:g].kind_of? String or copts[:g].size > 0)) or copts[:no_update] or copts[:cache]
|
622
|
+
else
|
623
|
+
runner = @runners[[host, folder]]
|
624
|
+
end
|
625
|
+
runner.process_copts(copts)
|
626
|
+
else
|
627
|
+
|
628
|
+
copts[:Y] ||= Dir.pwd
|
629
|
+
Dir.chdir((copts[:Y] or Dir.pwd)) do
|
630
|
+
unless @runners[copts[:Y]]
|
631
|
+
runner = @runners[copts[:Y]] = CodeRunner.new(Dir.pwd, code: copts[:C], modlet: copts[:m], version: copts[:v], executable: copts[:X], defaults_file: copts[:D])
|
632
|
+
runner.update unless copts[:no_update]
|
633
|
+
else
|
634
|
+
runner = @runners[copts[:Y]]
|
635
|
+
end
|
636
|
+
# p 'reading defaults', @r.conditions, DEFAULT_RUNNER_OPTIONS
|
637
|
+
runner.read_defaults
|
638
|
+
# p 'read defaults', @r.conditions
|
639
|
+
|
640
|
+
end #Dir.chdir
|
641
|
+
end
|
642
|
+
# ep copts
|
643
|
+
return runner
|
644
|
+
# @r.read_defaults
|
645
|
+
end
|
646
|
+
def self.update_runners
|
647
|
+
@runners ||= {}
|
648
|
+
@runners.each{|runner| runner.update}
|
649
|
+
end
|
650
|
+
|
651
|
+
|
652
|
+
def self.runner
|
653
|
+
@runners.values[0]
|
654
|
+
end
|
655
|
+
|
656
|
+
|
657
|
+
def self.manual(copts={})
|
658
|
+
help = <<EOF
|
659
|
+
|
660
|
+
|
661
|
+
-------------CodeRunner Manual---------------
|
662
|
+
|
663
|
+
Written by Edmund Highcock (2009)
|
664
|
+
|
665
|
+
NAME
|
666
|
+
|
667
|
+
coderunner
|
668
|
+
|
669
|
+
|
670
|
+
SYNOPSIS
|
671
|
+
|
672
|
+
coderunner <command> [arguments] [options]
|
673
|
+
|
674
|
+
|
675
|
+
DESCRIPTION
|
676
|
+
|
677
|
+
CodeRunner is a framework for the running and analysis of large simulations. It is a Ruby package and can be used to write Ruby scripts. However it also has a powerful command line interface. The aim is to be able to submit simulations, analyse data and plot graphs all using simple commands. This manual is a quick reference. For a more tutorial style introduction to CodeRunner go to
|
678
|
+
http://coderunner.sourceforge.net
|
679
|
+
|
680
|
+
This help page documents the commandline interface. For API documentation see
|
681
|
+
http://coderunner.sourceforge.net/api_documentation
|
682
|
+
|
683
|
+
As is standard, <> indicates a parameter to be supplied, and [] indicates an option, unless otherwise stated.
|
684
|
+
|
685
|
+
EXAMPLES
|
686
|
+
|
687
|
+
$ coderunner sub -p '{height: 34.2, width: 221}' -n 24x4 -W 300
|
688
|
+
|
689
|
+
$ coderunner can 34 -U
|
690
|
+
|
691
|
+
$ coderunner plot -G 'height:width;{};depth==2.4 and status == :Completed;height'
|
692
|
+
|
693
|
+
$ coderunner st -ul
|
694
|
+
|
695
|
+
$ coderunner rc 'p status' -U
|
696
|
+
|
697
|
+
COMMANDS
|
698
|
+
|
699
|
+
Either the long or the short form of the command may be used, except in interactive mode, where only short form can be used.
|
700
|
+
|
701
|
+
Long(Short) <Arguments> (Meaningful Options)
|
702
|
+
---------------------------------------------
|
703
|
+
|
704
|
+
#{(COMMANDS_WITH_HELP.sort_by{|arr| arr[0]}.map do |arr|
|
705
|
+
sprintf(" %s %s(%s) \n %s", "#{arr[0]}(#{arr[1]})", arr[4].map{|arg| "<#{arg}>"}.join(' ').sub(/(.)$/, '\1 '), arr[5].map{|op| op.to_s}.join(','), arr[3], )
|
706
|
+
end).join("\n\n")}
|
707
|
+
|
708
|
+
OPTIONS
|
709
|
+
|
710
|
+
#{((COMMAND_LINE_FLAGS_WITH_HELP + LONG_COMMAND_LINE_OPTIONS).map do |arr|
|
711
|
+
sprintf(" %-15s %-2s\n %s", arr[0], arr[1], arr[3])
|
712
|
+
end).join("\n\n")
|
713
|
+
}
|
714
|
+
|
715
|
+
EOF
|
716
|
+
puts help.gsub(/(.{63,73} |.{73})/){"#$1\\\n "}
|
717
|
+
end
|
718
|
+
|
719
|
+
|
720
|
+
|
721
|
+
|
722
|
+
|
723
|
+
end
|
724
|
+
|
725
|
+
|
726
|
+
|
727
|
+
|