coderunner 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,201 @@
1
+ # $script_folder = File.dirname(File.expand_path(__FILE__))
2
+ require File.dirname(File.expand_path(__FILE__)) + "/box_of_tricks.rb"
3
+
4
+ module LongRegexen
5
+
6
+ FLOAT = /(?<float>\-?(?:(?>\d+\.\d*)|(?>\d*\.\d+))(?:[eE][+-]?\d+)?)/
7
+
8
+ FLOAT_WSP = /(?<float>\-?\s*(?:(?>\d+\.\d*)|(?>\d*\.\d+))(?:[eE][+-]?\d+)?)/ # allows a space between the minus sign and the number
9
+
10
+
11
+ INT = INTEGER = /(?<int>\-?\d++)/
12
+
13
+ NUMBER = Regexp.new("(?<number>#{FLOAT.verbatim}|#{INTEGER.verbatim})")
14
+
15
+ STRING = /(?:"(?<string>(?:[^"]|\\")*)")|(?:'(?<string>(?:[^']|\\")*)')/
16
+
17
+ EQUALITY = /\b #a word boundary
18
+
19
+ (?<name>[A-Za-z_]\w*) # the name, which must be a single word (not beginning
20
+ # with a digit) followed by
21
+
22
+ \s*=\s* # an equals sign (possibly with whitespace either side), then
23
+
24
+ (?<default>(?> # the default answer, which can be either:
25
+
26
+ (?<float>\-?(?:(?>\d+\.\d*)|(?>\d*\.\d+))(?:[eE][+-]?\d+)?) # a floating point number
27
+
28
+ | #or
29
+
30
+ (?<int>\-?\d++) # an integer
31
+
32
+ | #or
33
+
34
+ (?:(?<delim>["'])(?<string>.*?)\k<delim>) # a string in quotes: '' or ""
35
+
36
+ | # or
37
+
38
+ (?:(?<word>\S+)(?=\s|\)|\]|[\n\r]+)) # a single word containing no spaces
39
+ # which must be followed by a space or ) or ] or a new line
40
+
41
+ ))/x
42
+
43
+ KEYVALUE = /<key> # <key> then
44
+
45
+ (?<name>[A-Za-z_]\w*) # the name, which must be a single word (not beginning
46
+ # with a digit) followed by
47
+
48
+ <\/key>\s* # <\/key> (possibly with following whitespace), then
49
+
50
+ <value> # <value>, then
51
+
52
+ (?<default> # the default answer, which can be either:
53
+
54
+
55
+ (?<float>\-?(?:(?>\d+\.\d*)|(?>\d*\.\d+))(?:[eE]\-?\d+)?) # a floating point number
56
+
57
+ | #or
58
+
59
+ (?<int>\-?\d+) # an integer
60
+
61
+ | #or
62
+
63
+ (?<string>[^<]*) # a string (containing no '<'s)
64
+
65
+ )
66
+
67
+ <value> # <\/value>
68
+
69
+ /x
70
+
71
+ TAG = /< # <
72
+
73
+ [^\/\S>]+ # some word (containing no '\/'s or '>'s)
74
+
75
+ \s+ #some whitespace
76
+
77
+ name=
78
+
79
+ (?<delim>["']) # a double or single quote
80
+
81
+ (?<name>[A-Za-z_]\w*) # the name, which must be a single word (not beginning
82
+ # with a digit) followed by
83
+
84
+ \k<delim> #a closing quote
85
+
86
+ \s+ #some whitespace
87
+
88
+ (?<delimnext>["']) # a double or single quote
89
+
90
+ (?<default> # the default answer, which can be either:
91
+
92
+
93
+ (?<float>\-?(?:(?>\d+\.\d*)|(?>\d*\.\d+))(?:[eE]\-?\d+)?) # a floating point number
94
+
95
+ | #or
96
+
97
+ (?<int>\-?\d+) # an integer
98
+
99
+ | #or
100
+
101
+ (?<string>[^"']*) # a string (containing no quotation marks)
102
+
103
+ )
104
+
105
+ \k<delimnext> #a closing quote
106
+
107
+ \s* #some whitespace
108
+
109
+ > # >
110
+
111
+ /x
112
+
113
+ #<comp> : only complete sets of delimiters [], "", '', \/\/ or complete method calls: meth(params) or no delimiters at all: ensures that any following expressions are not inside open square brackets, quotation marks or regexen, or inside method parameter lists
114
+ NAMRSQBQS = NOT_IN_A_METHOD_OR_IN_A_REGEXP_OR_IN_SQUARE_BRACKETS_OR_IN_QUOTES_OR_A_SYMBOL =
115
+
116
+ /(?<comp>
117
+ (?: #a set of three options
118
+ (?: #option 1: complete sets of delimiters
119
+ (?<nest> #sub-expression denoting nested delimiters
120
+ (?: # A: meth(stuff)
121
+ (?:[A-Za-z_]\d*?) #method name ending in numbers or a letter
122
+ \( #begin brackets
123
+ (?:
124
+ [^()\[\]"\/'] #no delimiters
125
+ |
126
+ \g<nest> #complete nested sub-expression
127
+ )*
128
+ \)
129
+ )
130
+ |
131
+ (?: # B: [stuff]
132
+ \[ #begin square brackets
133
+ (?:
134
+ [^()\[\]"\/'] #no delimiters
135
+ |
136
+ \g<nest> #complete nested sub-expression
137
+ )*
138
+ \]
139
+ )
140
+ |
141
+ (?: # C: \/stuff\/ or "stuff" or 'stuff'
142
+ (?<delim>[\/"']) #begin symmetrical delimiters
143
+ (?:
144
+ [^()\[\]"\/'] #no delimiters
145
+ |
146
+ \g<nest> #complete nested sub-expression
147
+ )*
148
+ \k<delim> #end symmetrical delimiters
149
+ )
150
+ ) # end sub-expression denoting correctly nested delimiters
151
+ )
152
+ |
153
+ [^()\[\]"\/'] #option 2: not delimiters
154
+ |
155
+ (?: # option 3: open brackets with no methods call before them
156
+ (?:
157
+ \W\d* # possibly some kind of number but not a name
158
+ |
159
+ ^
160
+ )
161
+ \(
162
+ )
163
+ )*? #as many of the above options as you like
164
+ )
165
+ (?: #Here we specify the immediately preceding letter (it cannot be a dot or a colon)
166
+ [^.:()\[\]"\/'] #Not a dot, a colon or a delimiter
167
+ |
168
+ (?: # not a method call
169
+ \W\d*
170
+ |
171
+ ^
172
+ )
173
+ \( #followed by an open bracket
174
+ |
175
+ ^ #we can match the beginning of the string
176
+ )/x #THE END!
177
+
178
+
179
+ =begin
180
+ Ensures that any following expression is not inside a method(...) pair of brackets, by demanding that any preceding opening bracket '\\(', is
181
+ either
182
+ -followed by a closing bracket '\\)' to form a complete set of correctly nested brackets (the <par> subexpression):
183
+ (?<begin>(?:(?:(?<par>\\((?:[^()]|\\g<par>)*\\))
184
+ or
185
+ -not preceded by a word character (A-Za-z_) (all method brackets are assumed to have a word character before them; other brackets (e.g. in a logical expression) are assumed not to):
186
+ (?:(?:[^A-Za-z_]|^)\\())*?)
187
+ =end
188
+
189
+ end
190
+
191
+
192
+ if $0 == __FILE__
193
+ puts " j(KWE) [0]" =~ Regexp.new("(?<b>#{LongRegexen::NAMRSQBQS})")
194
+ par = "q"
195
+ regex1 = Regexp.new("(?<b>#{LongRegexen::NAMRSQBQS.verbatim})\\#?(?<variable>#{Regexp.escape(par)})(?<end>[^A-Za-z_])", Regexp::EXTENDED)
196
+ puts " (q) " =~ regex1
197
+ puts $~.inspect
198
+ puts "t= 0.2000000000E+03 aky= 1.40 akx= -0.02 om= " =~ LongRegexen::FLOAT
199
+ puts "asd"
200
+ puts " -9.81730399614593e+38; // phi(2,33,43,2)" =~ Regexp.new("^\\s*?#{LongRegexen::FLOAT.verbatim}.*?\\sphi\\(\\d,(?<theta>\\d+),(?<kx>\\d+)")
201
+ end
@@ -0,0 +1,40 @@
1
+ class CodeRunner
2
+
3
+ def merge(*others)
4
+ Merged.new(*others.unshift(self))
5
+ end
6
+
7
+ def merge_method(meth, *args)
8
+ send(meth, *args)
9
+ end
10
+
11
+ class Merged < CodeRunner
12
+ def each
13
+ @runners.each{|r| yield(r)}
14
+ end
15
+ include Enumerable
16
+ def initialize(*runners)
17
+ @runners = []
18
+ r = runners[0]
19
+ r.instance_variables.each do |v|
20
+ instance_variable_set(v, r.instance_variable_get(v))
21
+ end
22
+ @run_list = {}
23
+ runners.each{|runner| add_runner(runner)}
24
+ end
25
+ def add_runner(runner)
26
+ @runners.push runner
27
+ runner.run_list.each do |id, run|
28
+ #raise "Duplicate ids: #{id}" if @run_list[id]
29
+ @run_list[id] = run
30
+ end
31
+ @ids = @run_list.keys
32
+ end
33
+ def merge_method(meth, *args, &block)
34
+ results = @runners.map{|r| r.send(meth, *args)}
35
+ return results.inject{|o,n| yield(o,n)}
36
+ end
37
+
38
+
39
+ end
40
+ end
@@ -0,0 +1,1000 @@
1
+ class CodeRunner
2
+
3
+ # Every code module defines a custom child class of CodeRunner::Run. This class will also include a module which customizes it to work on the current system. The result is a class which knows how to run and analyses the results of the given code on the given system.
4
+ #
5
+ # Every simulation that is carried out has an instance of this custom class created for it, and this object, known as a run, contains both the results and the input parameters pertaining to that simulation. All these runs are then stored in the variable run_list in a runner (an instance of the CodeRunner class). The result is that every run has a runner that it can talk to, and that runner has a set of runs that it can talk to.
6
+ #
7
+ # Every run has its own directory, where all the input and output files from the simulation are stored. CodeRunner data for the run is stored in this folder in the files <tt>code_runner_info.rb</tt> and <tt>code_runner_results.rb</tt>.
8
+ #
9
+ # As soon as the simulation is complete, CodeRunner call Run#process_directory to carry out any anlysis, and the results are stored in <tt>code_runner_results.rb</tt>. For speed CodeRunner also caches the data in the file <tt>.code_runner_run_data</tt> in binary format. This cache will be used after the initial analysis unless CodeRunner is specifically told to reanalyse this run.
10
+ #
11
+ # All input parameters and results are available during run time as instance variables of the run class.
12
+ #
13
+ # The class CodeRunner::Run itself defines a base set of methods which are added to by the code module.
14
+
15
+ class Run
16
+ include Log
17
+ # # include CodeRunner::HeuristicRunMethods
18
+
19
+ # class_vars = [:conditions, :sort, :sys, :debug, :script_folder, :necessary_system_runner_methods, :necessary_code_runner_methods, :recalc_all, :parallel]
20
+
21
+
22
+ # @@ruby_command = "ruby" #redefine if necessary
23
+ # @@input_file_extension = nil
24
+ # @@use_file_name_as_run_name = nil
25
+ # @@successful_trial_system = nil
26
+ #
27
+ # @@readout_real_run_list = true
28
+ # @@print_out_real_run_list = true
29
+ # @@readout_phantom_run_list = false
30
+ # @@print_out_phantom_run_list = false
31
+
32
+
33
+ # class_accessor :readout_real_run_list, :print_out_real_run_list, :readout_phantom_run_list, :print_out_phantom_run_list,
34
+
35
+ class_accessor :current_status, :runner
36
+
37
+ # Use the instance method #queue_status (defined in the system module) to put a list of current jobs obtained from the system into the class variable @@current_status
38
+
39
+ def self.update_status(runner)
40
+ if runner.no_run
41
+ @@current_status = ""
42
+ else
43
+ #eputs 'Getting queue status...'
44
+ @@current_status = new(runner).queue_status
45
+ end
46
+ # puts @@current_status
47
+ end
48
+
49
+
50
+ def gets #No reading from the command line thank you very much!
51
+ $stdin.gets
52
+ end
53
+ def self.gets
54
+ $stdin.gets
55
+ end
56
+
57
+
58
+ (SUBMIT_OPTIONS + [:code, :version, :readout_list, :naming_pars, :other_pars, :all, :ruby_command, :run_sys_name, :modlet, :executable]).each do |variable|
59
+ #define accessors for class options and instance options
60
+ # class_accessor(variable)
61
+ attr_accessor variable
62
+ # set(variable, nil) unless class_variables.include? ("@@" + variable).to_sym
63
+ end
64
+
65
+ class_accessor :run_sys_name
66
+ @@run_sys_name = nil
67
+ # @@necessary_class_variables.keys.each{|v| send(:attr_accessor, v)}
68
+
69
+ # @runnmaxes = {}
70
+
71
+ attr_accessor :maxes, :max_complete, :version, :code, :nprocs, :executable_name, :runner, :sys, :naming_pars, :code_runner_version, :real_id
72
+
73
+ # Purely for testing purposes; see the test suite
74
+
75
+ attr_accessor :run_test_flags
76
+
77
+ # Access to a hash which is stored in the runner (not the run). The hash will persist while the runner is in the object space.
78
+ #
79
+ # E.g.
80
+ # cache[:my_stuff_to_store] = something_to_store
81
+
82
+ def cache
83
+ @runner.cache[:runs] ||= {}
84
+ @runner.cache[:runs][@id] ||= {}
85
+ @runner.cache[:runs][@id]
86
+ end
87
+
88
+ # The hard cache persists after the current program ceases because
89
+ # it is written in the .code_runner_run_data file.
90
+ # It will disappear if the -a or -A flags are specified at any point
91
+ # If you edit the hard cache you ''must'' call <tt>save</tt> afterwards
92
+ # or your changes may not be kept
93
+ def hard_cache
94
+ @hard_cache ||={}
95
+ @hard_cache
96
+ end
97
+ #def save_hard_cache
98
+ #Dir.chdir(@directory)
99
+
100
+
101
+
102
+
103
+ class RunClassPropertyFetcher
104
+ def initialize(the_class)
105
+ @my_class = the_class
106
+ end
107
+ def method_missing(method, value=nil)
108
+ if method.to_s =~ /=$/
109
+ raise 'rcps should not be set outside class methods'
110
+ @my_class.instance_variable_set("@"+method.to_s.sub(/=/, ''), value)
111
+ else
112
+ the_class = @my_class
113
+ loop do
114
+ # p the_class, method
115
+ # p the_class.instance_variables
116
+ # p the_class.instance_variables.map{|v| the_class.instance_variable_get(v)}
117
+ return the_class.instance_variable_get("@"+method.to_s) if the_class.instance_variables.include?(("@"+method.to_s).to_sym)
118
+ the_class = the_class.superclass
119
+ return nil unless the_class
120
+ end
121
+
122
+ end
123
+ end
124
+
125
+ def [](prop)
126
+ send(prop.to_sym)
127
+ end
128
+ # def []=(prop, value)
129
+ # set(prop.to_sym, value)
130
+ # end
131
+ # end
132
+
133
+ end
134
+
135
+ # Access properties of the run class. These properties are stored as instance variables of the run class object. (Remember, in Ruby, every Class is an Object (and Object is a Class!)).
136
+ #
137
+ # E.g.
138
+ # puts rcp.variables
139
+
140
+ def self.rcp
141
+ @rcp ||= RunClassPropertyFetcher.new(self)
142
+ end
143
+
144
+ # Calls Run.rcp
145
+
146
+ def rcp
147
+ self.class.rcp
148
+ end
149
+
150
+ # Create a new run. <tt>runner</tt> should be an instance of the class CodeRunner.
151
+
152
+ def initialize(runner)
153
+ logf('initialize')
154
+ # raise "runner must be either a CodeRunner or a RemoteCoderunner: it is a #{runner.class}" unless [CodeRunner, RemoteCodeRunner].include? runner.class
155
+ @runner = runner
156
+ # raise CRFatal.new("Code not defined: #{CODE}") unless @@code and @@code.class == String and @@code =~ /\S/
157
+ @sys, @code = rcp.sys, rcp.code
158
+ @naming_pars = rcp.naming_pars.dup
159
+ raise CRFatal.new("@modlet not specified for #{self.class}") if rcp.modlet_required and not rcp.modlet
160
+ # @modlet = @@modlet; @modlet_location = @@modlet_location
161
+ # # @executable_location = executable_location
162
+ # @@necessary_run_variables.each{|v,clas| instance_eval("@#{v} = nil")}
163
+
164
+ # initialize_code_specific
165
+
166
+ # @script_folder = @@script_folder
167
+ # @recalc_all = @@recalc_all
168
+ @wall_mins = @runner.wall_mins if @runner
169
+ @smaxes = {}; @csmaxes = {}; @max_complete = {};
170
+ end
171
+
172
+ # Here we redefine the inspect function p to raise an error if anything is written to standard out
173
+ # while in server mode. This is because the server mode uses standard out to communicate
174
+ # and writing to standard out can break it. All messages, debug information and so on, should always
175
+ # be written to standard error.
176
+
177
+ def p(*args)
178
+ if @runner and @runner.server
179
+ raise "Writing to stdout in server mode will break things!"
180
+ else
181
+ super(*args)
182
+ end
183
+ end
184
+
185
+ # Here we redefine the function puts to raise an error if anything is written to standard out
186
+ # while in server mode. This is because the server mode uses standard out to communicate
187
+ # and writing to standard out can break it. All messages, debug information and so on, should always
188
+ # be written to standard error.
189
+
190
+ def puts(*args)
191
+ if @runner and @runner.server
192
+ raise "Writing to stdout in server mode will break things!"
193
+ else
194
+ super(*args)
195
+ end
196
+ end
197
+
198
+ # Here we redefine the function print to raise an error if anything is written to standard out
199
+ # while in server mode. This is because the server mode uses standard out to communicate
200
+ # and writing to standard out can break it. All messages, debug information and so on, should always
201
+ # be written to standard error.
202
+
203
+ def print(*args)
204
+ if @runner and @runner.server
205
+ raise "Writing to stdout in server mode will break things!"
206
+ else
207
+ super(*args)
208
+ end
209
+ end
210
+
211
+
212
+ # Analyse the directory of the run. This should be called from the directory where the files of the run are located. This method reads in the CodeRunner data already available in <tt>code_runner_info.rb</tt> and <tt>code_runner_results.rb</tt>, and then calls <tt>process_directory_code_specific</tt> which is defined in the code module.
213
+
214
+ def process_directory
215
+
216
+ # Clear the cache
217
+ @runner.cache[:runs]||={}
218
+ @runner.cache[:runs][@id] = {}
219
+ logf(:process_directory)
220
+ raise CRFatal.new("Something has gone horribly wrong: runner.class is #{@runner.class} instead of CodeRunner") unless @runner.class.to_s == "CodeRunner"
221
+
222
+ begin
223
+ @code_runner_version = Version.new(File.read('.code_runner_version.txt'))
224
+ File.read('code_runner_info.rb')
225
+ rescue Errno::ENOENT # version may be less than 0.5.1 when .code_runner_version.txt was introduced
226
+ @code_runner_version = Version.new('0.5.0')
227
+ end
228
+
229
+ @directory = Dir.pwd
230
+ @relative_directory = File.expand_path(Dir.pwd).sub(File.expand_path(@runner.root_folder) + '/', '')
231
+ # p @directory
232
+ @readme = nil
233
+
234
+ if @code_runner_version < Version.new('0.5.1')
235
+ begin
236
+ update_from_version_0_5_0_and_lower
237
+ rescue Errno::ENOENT => err # No code runner files were found
238
+ unless @runner.heuristic_analysis
239
+ puts err
240
+ raise CRFatal.new("No code runner files found: suggest using heuristic analysis (flag -H if you are using the code_runner script)")
241
+ end
242
+ unless @runner.current_request == :traverse_directories
243
+ @runner.requests.push :traverse_directories unless @runner.requests.include? :traverse_directories
244
+ raise CRMild.new("can't begin heuristic analysis until there has been a sweep over all directories") # this will get rescued
245
+ end
246
+ @runner.increment_max_id
247
+ @id = @runner.max_id
248
+ @job_no = -1
249
+ run_heuristic_analysis
250
+ end
251
+ end
252
+
253
+
254
+ read_info
255
+ begin
256
+ read_results if FileTest.exist? 'code_runner_results.rb'
257
+ rescue NoMethodError, SyntaxError => err
258
+ puts err
259
+ puts 'Results file possibly corrupted for ' + @run_name
260
+ end
261
+
262
+ if methods.include? :get_run_status
263
+ @status = get_run_status(@job_no, @@current_status) rescue :Unknown
264
+ else
265
+ @status ||= :Unknown
266
+ end
267
+ @running = (@@current_status =~ Regexp.new(@job_no.to_s)) ? true : false
268
+ #logi '@@current_status', @@current_status, '@job_no', @job_no
269
+ #logi '@running', @running
270
+ process_directory_code_specific
271
+
272
+ raise CRFatal.new("status must be one of #{PERMITTED_STATI.inspect}") unless PERMITTED_STATI.include? @status
273
+ @max = {}
274
+ write_results
275
+ generate_phantom_runs
276
+ save
277
+ return self
278
+ end
279
+
280
+ # Read input parameters from the file <tt>code_runner_info.rb</tt>
281
+
282
+ def read_info
283
+ eval(File.read('code_runner_info.rb')).each do |key, value|
284
+ set(key, value)
285
+ end
286
+ end
287
+
288
+ # Read results from the file <tt>code_runner_results.rb</tt>
289
+
290
+ def read_results
291
+ return if @runner.recalc_all
292
+ eval(File.read('code_runner_results.rb')).each do |key, value|
293
+ set(key, value)
294
+ end
295
+ end
296
+
297
+ # Write results to the file <tt>code_runner_results.rb</tt>
298
+
299
+ def write_results
300
+ logf(:write_results)
301
+ Dir.chdir(@directory){File.open("code_runner_results.rb", 'w'){|file| file.puts results_file}}
302
+ end
303
+
304
+ # Return the text of the results file.
305
+
306
+ def results_file
307
+ logf(:results_file)
308
+ return <<EOF
309
+ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
310
+ # #{rcp.code_long} Results
311
+ # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
312
+ #
313
+ # This is a syntactically correct Ruby file, which is used by CodeRunner. Please do not edit unless you know what you are doing.
314
+ # Directory: #{@directory}
315
+ # Runname: #{@run_name}
316
+ # ID: #{@id}
317
+
318
+ # Results:
319
+ #{(rcp.results+rcp.run_info).inject({}){|hash, (var,type_co)| hash[var] = send(var); hash}.pretty_inspect}
320
+
321
+ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
322
+ EOF
323
+
324
+ end
325
+
326
+ # Return a line of data for printing to file in CodeRunner#readout, organised according to the run class property rcp.readout_list
327
+
328
+ def data_string
329
+ rcp.readout_list.inject(""){|str,var| str+"#{send(var)}code_runner_spacer"}.gsub(/\s/, '_').gsub(/code_runner_spacer/, "\t") + "\n"
330
+ end
331
+
332
+ # Used for the status with comments command.
333
+
334
+ def comment_line
335
+ "#{id}: #{@comment}"
336
+ sprintf("%2d:%d %1s:%2.1f(%s) %3s%1s %s", @id, @job_no, @status.to_s[0,1], @run_time.to_f / 60.0, @nprocs.to_s, percent_complete, "%", @comment)
337
+ end
338
+
339
+ # Cache the run object in the file <tt>.code_runner_run_data</tt>
340
+
341
+ def save
342
+ logf(:save)
343
+ raise CRFatal.new("Something has gone horribly wrong: runner.class is #{@runner.class} instead of CodeRunner") unless @runner.class.to_s == "CodeRunner"
344
+ runner, @runner = @runner, nil
345
+ @system_triers, old_triers = nil, @system_triers
346
+ @phantom_runs.each{|run| run.runner = nil} if @phantom_runs
347
+ # logi(self)
348
+ Dir.chdir(@directory){File.open(".code_runner_run_data", 'w'){|file| file.puts Marshal.dump(self)}}
349
+ @runner = runner
350
+ @phantom_runs.each{|run| run.runner = runner} if @phantom_runs
351
+ @system_triers = old_triers
352
+ end
353
+
354
+
355
+ # Load the run object from the file <tt>.code_runner_run_data</tt>
356
+
357
+ def self.load(dir, runner)
358
+ raise CRFatal.new("runner supplied in Run.load was not an instance of code runner; runner.class = #{runner.class}") unless runner.class.to_s == "CodeRunner"
359
+ begin
360
+ raise CRMild.new("No saved run data") unless FileTest.exist? (dir+"/.code_runner_run_data")
361
+ run = Marshal.load(File.read(dir+"/.code_runner_run_data"))
362
+ rescue ArgumentError => err
363
+ raise err unless err.message =~ /undefined class/
364
+ #NB this means that all code_names have to contain only lowercase letters:
365
+ # code, modlet = err.message.scan(/CodeRunner\:\:([A-Z][a-z0-9]+)((?:[A-Z]\w+)+)?Run/)[0]
366
+ # code, modlet = err.message.scan(/CodeRunner\:\:([A-Z][a-z0-9_]+)(?:::([A-Z]\w+))?/)[0]
367
+ # ep code, modlet; exit
368
+ # code.gsub!(/([a-z0-9])([A-Z])/, '\1_\2')
369
+ # modlet.gsub!(/([a-z0-9])([A-Z])/, '\1_\2')
370
+ # ep err, modlet, code
371
+ # runner.setup_run_class(code.downcase, modlet: modlet.downcase)
372
+ # retry
373
+ CodeRunner.repair_marshal_run_class_not_found_error(err)
374
+ run = Marshal.load(File.read(dir+"/.code_runner_run_data"))
375
+ end
376
+ run.runner = runner
377
+ raise CRFatal.new("Something has gone horribly wrong: runner.class is #{run.runner.class} instead of CodeRunner") unless run.runner.class.to_s == "CodeRunner"
378
+ run.directory = dir
379
+ run.phantom_runs.each{|r| runner.add_phantom_run(r)} if run.phantom_runs
380
+ #@phantom_runs = []
381
+ return run
382
+ end
383
+
384
+ # Return the name of the defaults file currently in use.
385
+
386
+ def defaults_file_name
387
+ if @runner.defaults_file
388
+ return "#{@runner.defaults_file}_defaults.rb"
389
+ else
390
+ return "#{rcp.code}_defaults.rb"
391
+ end
392
+ end
393
+
394
+ # Return the folder where the default defaults file is located.
395
+
396
+ def defaults_location
397
+ if @runner.defaults_file
398
+ location = ["#{SCRIPT_FOLDER}/code_modules/#@code/my_defaults_files", "#{SCRIPT_FOLDER}/code_modules/#@code/defaults_files"].find{|folder| FileTest.exist? folder and Dir.entries(folder).include? defaults_file_name}
399
+ raise "Defaults file: #{defaults_file_name} not found" unless location
400
+ return location
401
+ else
402
+ return "#{SCRIPT_FOLDER}/code_modules/#@code"
403
+ end
404
+ end
405
+
406
+ # Return true if the run is completed, false otherwise
407
+
408
+ def is_complete
409
+ @status == :Complete
410
+ end
411
+
412
+ alias :ctd :is_complete
413
+
414
+ # This function is a hook which is used by system modules. For runs it is defined as the id.
415
+
416
+ def job_identifier
417
+ id
418
+ end
419
+
420
+ class NoRunnerError < StandardError
421
+ def new(mess)
422
+ super("No Runner: a runner was needed for this Run method call "+mess)
423
+ end
424
+ end
425
+
426
+ # Update instance variables using the given defaults file. Give warnings if the defaults file contains variables which are not simulation input parameters
427
+
428
+ def evaluate_defaults_file(filename)
429
+ text = File.read(filename)
430
+ text.scan(/^\s*@(\w+)/) do
431
+ var_name = $~[1].to_sym
432
+ next if var_name == :defaults_file_description
433
+ unless rcp.variables.include? var_name
434
+ warning("---#{var_name}---, specified in #{File.expand_path(filename)}, is not a variable. This could be an error")
435
+ end
436
+ end
437
+ instance_eval(text)
438
+ end
439
+
440
+ # This function set the input parameters of the run using the following sources in ascending order of priority: main defaults file (in the code module folder), local defaults file (in the local Directory), parameters (an inspected hash usually specified on the command line).
441
+
442
+ def update_submission_parameters(parameters, start_from_defaults=true)
443
+ logf(:update_submission_parameters)
444
+ if start_from_defaults
445
+ upgrade_defaults_from_0_5_0 if self.class.constants.include? :DEFAULTS_FILE_NAME_0_5_0
446
+ main_defaults_file = "#{defaults_location}/#{defaults_file_name}"
447
+ main_defaults_file_text = File.read(main_defaults_file)
448
+ evaluate_defaults_file(main_defaults_file)
449
+
450
+ unless FileTest.exist?(defaults_file_name)
451
+ main_defaults_file_text.gsub!(/^/, "#")
452
+ header = <<EOF
453
+ #############################################################
454
+ # CodeRunner Local Defaults File
455
+ ############################################################
456
+ #
457
+ # This is a local copy of the central defaults file, which
458
+ # was copied from the central defaults file
459
+ # #{defaults_file_name}
460
+ #
461
+ # to the folder
462
+ # #{Dir.pwd}
463
+ #
464
+ # at
465
+ # #{Time.now}
466
+ #
467
+ # by CodeRunner version #{CODE_RUNNER_VERSION}
468
+ #
469
+ # All lines in the original file have been commented out:
470
+ # they are kept as a reference to make adding local defaults easier.
471
+ # It is suggested that local changes are placed at the top
472
+ # of this file, not in the body of the commented out section.
473
+ #
474
+ # Local changes override the central defaults file. However,
475
+ # if the central defaults file changes, any variables which
476
+ # are not overidden here will change for any future simulations
477
+ # in this folder.
478
+ #
479
+ ##############################################################
480
+
481
+
482
+
483
+
484
+
485
+
486
+ # Begin Copy of Central Defaults:
487
+ #
488
+ #
489
+ EOF
490
+ main_defaults_file_text = header + main_defaults_file_text
491
+ File.open(defaults_file_name, 'w'){|file| file.puts main_defaults_file_text}
492
+ end
493
+ #FileUtils.cp("#{defaults_location}/#{defaults_file_name}", defaults_file_name)
494
+
495
+ evaluate_defaults_file(defaults_file_name)
496
+ end
497
+ return unless parameters
498
+ raise "parameters: #{parameters.inspect} must be a string which evaluates to a hash" unless parameters.class == String and parameters = eval(parameters) and parameters.class == Hash # parameters.class == String and parameters =~ /\S/
499
+ @parameter_hash = parameters
500
+ parameters.each do |var, value|
501
+ raise CRFatal.new('Cannot specify id as a parameter') if var.to_sym == :id
502
+ set(var, value) unless value == :default
503
+ next if [:comment].include? var
504
+ @naming_pars.push var
505
+ end
506
+ @naming_pars.uniq!
507
+ self
508
+ end
509
+
510
+ def execute_submission
511
+ if @runner.test_submission
512
+ log 'testing submission'
513
+ eputs info_file
514
+ File.delete(@runner.root_folder + "/submitting")
515
+ exit
516
+ else
517
+ execute
518
+ end
519
+ end
520
+
521
+ # def submit
522
+ # logf(:submit)
523
+ # logi(:@nprocs, @nprocs)
524
+ #
525
+ # raise "Test Submit Error Handling" if @run_test_flags and @run_test_flags[:test_submit_error_handling]
526
+ #
527
+ # eputs "System " + SYS
528
+ # eputs "nprocs " + @nprocs
529
+ # # puts send(:q)
530
+ #
531
+ # raise CRFatal.new ("Can't find executable: #{executable_location}/#{executable_name}") unless FileTest.exist? File.expand_path("#{executable_location}/#{executable_name}")
532
+ #
533
+ # @naming_pars.each{|par| raise CRFatal.new("@naming_par #{par} is not listed in variables") unless rcp.variables.include? par}
534
+ # # @other_pars = []
535
+ # # @@variables.dup.each do |par, type_co|
536
+ # # @other_pars.push par unless @naming_pars.include? par
537
+ # # end
538
+ #
539
+ # # @dir_name = %[v#@version] + @naming_pars.inject("") do |str, par|
540
+ # # str+="/#{par}_#{send(par)}"
541
+ # # end
542
+ #
543
+ # @dir_name = %[v#@version]
544
+ #
545
+ # @run_name = %[v#@version] + @naming_pars.inject("") do |str, par|
546
+ # str+="_#{par}_#{send(par)}"
547
+ # end
548
+ # @dir_name = @dir_name.gsub(/\s+/, "_") + "/id_#@id"
549
+ # @run_name = @run_name.gsub(/\s+/, "_") + "_id_#@id"
550
+ # @directory = File.expand_path(@dir_name)
551
+ #
552
+ # @job_no = nil
553
+ # qstat = queue_status #|| ""
554
+ # # puts qstat;# gets
555
+ # # qstat = qstat =~ /\S/ ? qstat : nil
556
+ # if qstat and qstat.class == String
557
+ # FileUtils.makedirs(@dir_name)
558
+ # Dir.chdir(@dir_name) do
559
+ # generate_input_file
560
+ # job_nos = qstat.scan(/^\s*(\d+)/).map{|match| match[0].to_i} if qstat
561
+ # # logi(:job_nos, job_nos)
562
+ # ##################
563
+ # execute_submission
564
+ # ##################
565
+ # qstat = queue_status #|| ""
566
+ # # qstat = qstat=~/\S/ ? qstat : nil
567
+ # 5.times do # job_no may not appear instantly
568
+ # new_job_nos = qstat.scan(/^\s*(\d+)/).map{|match| match[0].to_i}
569
+ # # puts new_job_nos
570
+ # logi(:new_minus_old, new_job_nos-job_nos)
571
+ # @job_no = (new_job_nos-job_nos).sort[-1]
572
+ # break if @job_no
573
+ # sleep 0.2
574
+ # qstat = queue_status
575
+ # end
576
+ # @job_no ||= -1 # some functions don't work if job_no couldn't be found, but most are ok
577
+ # eputs info_file
578
+ # @sys = SYS
579
+ # write_info
580
+ # File.open(".code_runner_version.txt", 'w'){|file| file.puts CODE_RUNNER_VERSION}
581
+ # File.open("code_runner_modlet.rb", 'w'){|file| file.puts rcp.modlet_source} if rcp.modlet_required
582
+ # end
583
+ #
584
+ #
585
+ # else
586
+ # File.delete("submitting")
587
+ # raise CRFatal.new("queue_status did not return a string; submission cancelled. Suggest editing system_modules/#{SYS}.rb")
588
+ # end
589
+ #
590
+ # end
591
+
592
+ # Generate the run name and the directory name, and check that the directory is empty. The run name, i.e. @run_name can be set beforehand, in which case it will not be changed. The directory name choice can be influenced by the variable @dir_name, which is not used outside this function.
593
+
594
+ def prepare_submission(options={})
595
+ raise "Test Submit Error Handling" if @run_test_flags and @run_test_flags[:test_submit_error_handling]
596
+
597
+ #p '@nprocs', @nprocs
598
+ if @runner
599
+ SUBMIT_OPTIONS.each do |option|
600
+ set(option, @runner.send(option)) if @runner.send(option)
601
+ end
602
+ end
603
+ #p '@nprocs', @nprocs
604
+
605
+ # puts send(:q)
606
+
607
+ raise CRFatal.new ("Can't find executable: #{executable_location}/#{executable_name}") unless FileTest.exist? File.expand_path("#{executable_location}/#{executable_name}")
608
+
609
+ @naming_pars.each{|par| raise CRFatal.new("@naming_par #{par} is not listed in variables or run_info") unless (rcp.variables + rcp.run_info).include? par}
610
+ @naming_pars.delete(:g_exb_start_timestep)
611
+ unless @dir_name # dir_name can be set in advance to change the default directory name
612
+ @dir_name = %[v#@version]
613
+ @dir_name = @dir_name.gsub(/\s+/, "_") + "/id_#@id"
614
+ end
615
+ generate_run_name unless @run_name
616
+
617
+ @directory = File.expand_path(@dir_name)
618
+ #@relative_directory = File.expand_path(Dir.pwd).sub(File.expand_path(@runner.root_folder) + '/', '')
619
+ #@relative_directory = @directory.sub(File.expand_path(@runner.root_folder) + '/', '')
620
+ @relative_directory = @dir_name
621
+
622
+ raise "Directory #@dir_name contains code_runner_info" if FileTest.exist? @directory and Dir.entries(@directory).include? ["code_runner_info.rb"]
623
+
624
+ @job_no = nil
625
+ FileUtils.makedirs(@dir_name)
626
+ Dir.chdir(@dir_name) do
627
+ generate_input_file
628
+
629
+ File.open(".code_runner_version.txt", 'w'){|file| file.puts CODE_RUNNER_VERSION}
630
+ File.open("code_runner_modlet.rb", 'w'){|file| file.puts rcp.modlet_source} if rcp.modlet_required
631
+ end
632
+ @dir_name = nil
633
+
634
+ end
635
+
636
+ def generate_run_name
637
+ @run_name = %[v#@version] + @naming_pars.inject("") do |str, par|
638
+ str+="_#{par}_#{send(par).to_s[0...8]}"
639
+ end
640
+ @run_name = @run_name.gsub(/\s+/, "_").gsub(/\//, '') + "_id_#@id"
641
+ end
642
+
643
+ def write_info
644
+ Dir.chdir(@directory){File.open("code_runner_info.rb", 'w'){|file| file.puts info_file}}
645
+ end
646
+
647
+ # private :write_info
648
+
649
+ def info_file
650
+ @modlet = rcp.modlet
651
+ return <<EOF
652
+ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
653
+ # #{rcp.code_long} Input Parameters
654
+ # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
655
+ # Code: #{rcp.code}
656
+ # System: #{@sys}
657
+ # Version: #{@version}
658
+ # Nprocs: #{@nprocs}
659
+ # Directory: #{Dir.pwd}
660
+ # Runname: #{@run_name}
661
+ # ID: #{@id}
662
+ # #{rcp.modlet_required ? "Modlet:\t#{rcp.modlet}" : ""}
663
+ # Classname: #{self.class.to_s}
664
+
665
+ # #{@job_no ? "Job_No: #{@job_no}" : ""}
666
+
667
+ # Parameters:
668
+ #{(rcp.variables + rcp.run_info + [:version, :code, :modlet, :sys]).inject({}){|hash, var| hash[var] = send(var) unless (!send(var) and send(var) == nil); hash}.pretty_inspect}
669
+
670
+
671
+ # Actual Command:
672
+ # #{run_command}
673
+ # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
674
+ EOF
675
+
676
+ end
677
+
678
+ def set_modlet(modlet, folder=nil)
679
+ logf(:set_modlet)
680
+ rcp.modlet.sub!(/.*/, modlet)
681
+ self.class.set_modlet(modlet, folder)
682
+ end
683
+ private :set_modlet
684
+
685
+ def self.set_modlet(modlet, folder = nil)
686
+ raise 'old method -- needs to be debugged'
687
+ Log.log("self.set_modlet", self.to_s)
688
+ class_eval(File.read("#{folder ? folder + "/" : ""}#{modlet}"))
689
+ check_and_update
690
+ end
691
+
692
+ # aliold :inspect
693
+ def inspect
694
+ old, @runner = @runner, nil
695
+ str = super
696
+ @runner = old
697
+ str
698
+ end
699
+
700
+
701
+ # aliold :pretty_inspect
702
+ def pretty_print(q)
703
+ old, @runner = @runner, nil
704
+ str = q.pp_object(self)
705
+ @runner = old
706
+ str
707
+
708
+ end
709
+
710
+ # def pretty_print(q)
711
+ # if /\(Kernel\)#/ !~ Kernel.instance_method(:method).bind(self).call(:inspect).inspect
712
+ # q.text self.inspect
713
+ # elsif /\(Kernel\)#/ !~ Kernel.instance_method(:method).bind(self).call(:to_s).inspect && instance_variables.empty?
714
+ # q.text self.to_s
715
+ # else
716
+ # q.pp_object(self)
717
+ # end
718
+ # end
719
+
720
+ # A hook for module developers
721
+
722
+ def self.finish_setting_up_class
723
+ end
724
+
725
+ # ALL = []
726
+ # READOUT_LIST = []
727
+ # CODE = nil
728
+
729
+ def self.check_and_update
730
+ Log.logf(:check_and_update)
731
+
732
+ #
733
+ finish_setting_up_class
734
+ # ep self.to_s, constants, self.ancestors
735
+
736
+ # raise CRFatal.new("Code not defined (#{CODE.inspect}) in class #{self.to_s}") unless CODE and CODE.class == String and CODE =~ /\S/
737
+
738
+
739
+ NECESSARY_RUN_SYSTEM_METHODS.each do |method|
740
+ raise CRFatal.new("#{method} not defined in #{SYS}_system_runner.rb") unless instance_methods.include?(method)
741
+ end
742
+
743
+ NECESSARY_RUN_CODE_METHODS.each do |method|
744
+ raise CRFatal.new("#{method} not defined in #{self.class}_code_runner.rb") unless instance_methods.include?(method)
745
+ end
746
+
747
+
748
+ NECESSARY_RUN_CLASS_PROPERTIES.each do |v,class_list|
749
+ # raise CRFatal.new("#{v} not defined") unless rcp[v]
750
+ raise CRFatal.new("#{v} not defined correctly: class is #{rcp[v].class} instead of one of #{class_list.to_s}") unless class_list.include? rcp[v].class
751
+ end
752
+
753
+ @readout_list = (rcp.variables+rcp.results) unless rcp.readout_list
754
+ # (variables+results).each{|v| const_get(:READOUT_LIST).push v} unless READOUT_LIST.size > 0
755
+
756
+ if rcp.variables_0_5_0
757
+ rcp.variables_0_5_0.dup.each do |par, info| #for backwards compatibility only
758
+ rcp.variables_0_5_0[par] = info[0] if info.class == Array
759
+ end
760
+ end
761
+
762
+
763
+
764
+
765
+
766
+ # Log.log(:@@variables0, @@variables[0])
767
+
768
+ @run_info = rcp.run_info || [] # Run info can optionally be defined in the code module.
769
+ # ep @run_info
770
+ @run_info = rcp.run_info + ([:job_no, :running, :id, :status, :sys, :is_phantom, :naming_pars, :run_name, :resubmit_id, :real_id, :phantom_runs, :parameter_hash, :output_file, :error_file] + SUBMIT_OPTIONS) #.each{|v| RUN_INFO.push v} unless RUN_INFO.include? :job_no
771
+ @all = (rcp.variables + rcp.results + rcp.run_info) #.each{|v| ALL.push v}
772
+ # ep "GOT HERE"
773
+ (@all + [:directory, :run_name, :modlet, :relative_directory]).each{|var| send(:attr_accessor, var)}
774
+ define_method(:output_file) do
775
+ return @output_file if @output_file
776
+ @output_file = super()
777
+ end
778
+ define_method(:error_file) do
779
+ return @error_file if @error_file
780
+ @error_file = super()
781
+ end
782
+
783
+ Dir.chdir(SCRIPT_FOLDER + "/system_modules") do
784
+ @system_run_classes ||=
785
+ Dir.entries(Dir.pwd).find_all{|file| file =~ /^[^\.].+\.rb$/}.inject([]) do |arr, file|
786
+ #p Dir.pwd
787
+ #p 'required', file, Dir.pwd
788
+ require Dir.pwd + '/' + file
789
+ # p CodeRunner.constants
790
+ sys = file.sub(/\.rb$/, '')
791
+ arr.push(add_a_child_class("#{sys.variable_to_class_name}Run"))
792
+ arr[-1].send(:include, CodeRunner.const_get(sys.variable_to_class_name))
793
+ arr
794
+ end
795
+ end
796
+
797
+
798
+ end
799
+
800
+ def dup
801
+ return self.class.new(@runner).learn_from(self)
802
+ end
803
+
804
+ def create_phantom
805
+ @phantom_runs ||= []
806
+ new_run = dup
807
+ new_run.is_phantom = true
808
+ new_run.real_id = @id
809
+ @runner.add_phantom_run(new_run)
810
+ @phantom_runs.push new_run
811
+ new_run
812
+ end
813
+
814
+ def learn_from(run)
815
+ run.instance_variables.each do |var|
816
+ # puts var
817
+ # puts run.instance_variable_get(var)
818
+ instance_variable_set(var,run.instance_variable_get(var))
819
+ # puts instance_variable_get(var)
820
+
821
+ # rescue NoMethodError
822
+ # next
823
+ # end
824
+ end
825
+ self
826
+ end
827
+
828
+
829
+
830
+
831
+ def logiv
832
+ instance_variables.each do |var|
833
+ unless var == :@runner or var == :@system_triers
834
+ log(var); logi(instance_variable_get(var))
835
+ end
836
+ end
837
+ end
838
+
839
+ def recheck
840
+ logf(:recheck)
841
+ Dir.chdir(@directory) do
842
+ # puts 'ackack'
843
+ puts "Rechecking #@run_name"
844
+ runner = @runner
845
+ instance_variables.each{|var| instance_variable_set(var, nil) unless var == :@runner}
846
+ begin File.delete("CODE_RUNNER_RUN_DATA") rescue Errno::ENOENT end
847
+ begin File.delete("CODE_RUNNER_RESULTS") rescue Errno::ENOENT end
848
+ process_directory
849
+ save
850
+ end
851
+ end
852
+
853
+ def generate_phantom_runs
854
+ end
855
+
856
+ def generate_combined_ids(type)
857
+ raise CRFatal.new("Can't call generate_combined_ids from a run")
858
+ end
859
+
860
+ # @@maxes = {}
861
+ # @@cmaxes = {}
862
+
863
+ def max(variable, complete=false) #does this run have the maximum value of this variable
864
+ raise ArgumentError.new("complete must be true or false") unless [TrueClass, FalseClass].include? complete.class
865
+ @runner.generate_combined_ids
866
+ ids = @runner.combined_ids
867
+ if complete
868
+ ids = ids.find_all{|id| @runner.combined_run_list[id].status == :Complete}
869
+ max_id = @runner.cmaxes[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[-1]
870
+ else
871
+ max_id = @runner.maxes[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[-1]
872
+ end
873
+ return @runner.combined_run_list[max_id].send(variable) == send(variable)
874
+ end
875
+
876
+ # # @@mins = {}
877
+ # @@cmins = {}
878
+
879
+
880
+ def min(variable, complete=false) #does this run have the minimum value of this variable
881
+ raise ArgumentError.new("complete must be true or false") unless [TrueClass, FalseClass].include? complete.class
882
+ @runner.generate_combined_ids
883
+ ids = @runner.combined_ids
884
+
885
+ if complete
886
+ ids = ids.find_all{|id| @runner.combined_run_list[id].status == :Complete}
887
+ min_id = @runner.cmins[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[0]
888
+ else
889
+ min_id = @runner.mins[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[0]
890
+ end
891
+ return @runner.combined_run_list[min_id].send(variable) == send(variable)
892
+ end
893
+
894
+ # @@fmaxes = {}
895
+ # @@cfmaxes = {}
896
+
897
+ # # Does this run have the maximum value of this variable to be found amoung the filtered runs?
898
+ #
899
+ # def fmax(variable, complete = false)
900
+ # raise ArgumentError.new("complete must be true or false") unless [TrueClass, FalseClass].include complete.class
901
+ # @runner.generate_combined_ids
902
+ # ids = @runner.filtered_ids # o^o-¬
903
+ # if complete
904
+ # ids = ids.find_all{|id| @runner.combined_run_list[id].status == :Complete}
905
+ # max_id = @@cfmaxes[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[-1]
906
+ # else
907
+ # max_id = @@fmaxes[variable] ||= ids.sort_by{|id| @runner.combined_run_list[id].send(variable)}[-1]
908
+ # end
909
+ # return @runner.combined_run_list[max_id].send(variable) == send(variable)
910
+ # end
911
+ #
912
+
913
+ def smax(variable,sweep=nil, complete=nil)
914
+ logf(:max)
915
+ sweep ||= variable
916
+ if complete
917
+ @csmaxes[variable] ||= {}
918
+ max_id = @csmaxes[variable][sweep] = @runner.get_max(self, variable,sweep, complete)
919
+ else
920
+ @smaxes[variable] ||= {}
921
+ max_id = @smaxes[variable][sweep] = @runner.get_max(self, variable,sweep, complete)
922
+ end
923
+ return @runner.combined_run_list[max_id].send(variable) == send(variable)
924
+ end
925
+
926
+ def smin(variable,sweep=nil, complete=nil)
927
+ logf(:min)
928
+ sweep ||= variable
929
+ @smins ||= {}
930
+ @csmins ||= {}
931
+ if complete
932
+ @csmins[variable] ||= {}
933
+ min_id = @csmins[variable][sweep] = @runner.get_min(self, variable,sweep, complete)
934
+ else
935
+ @smins[variable] ||= {}
936
+ min_id = @smins[variable][sweep] = @runner.get_min(self, variable,sweep, complete)
937
+ end
938
+ return @runner.combined_run_list[min_id].send(variable) == send(variable)
939
+ end
940
+
941
+ # aliold :_dump
942
+ # def _dump(*args)
943
+ # @runner, runner = nil, @runner
944
+ # ans = super(*args)
945
+ # @runner = runner
946
+ # return ans
947
+ # end
948
+
949
+ def executable_name
950
+ File.basename(@executable||=@runner.executable)
951
+ end
952
+
953
+ def executable_location
954
+ File.dirname(@executable||=@runner.executable)
955
+ end
956
+
957
+ def update_in_queue
958
+ unless @status == :Queueing
959
+ raise 'Can only updated runs whose status is :Queueing'
960
+ end
961
+ unless methods.include? :batch_script_file
962
+ raise 'Can only update runs which have been submitted using a batch script file'
963
+ end
964
+ old_run_name = @run_name
965
+ generate_run_name
966
+ new_run_name = @run_name
967
+ #@run_name = old_run_name
968
+ unless FileTest.exist?(filename = @directory + '/' + batch_script_file) or
969
+ FileTest.exist?(filename = @runner.root_folder + '/' + batch_script_file)
970
+ raise 'Could not find batch_script_file'
971
+ end
972
+ old_batch_script=File.read(filename)
973
+ eputs old_batch_script
974
+ eputs old_batch_script.gsub(Regexp.new(Regexp.escape(old_run_name)), new_run_name)
975
+ ep Regexp.new(Regexp.escape(old_run_name))
976
+ File.open(filename, 'w'){|file| file.puts old_batch_script.gsub(Regexp.new(Regexp.escape(old_run_name)), new_run_name)}
977
+
978
+
979
+ generate_input_file
980
+ #throw(:done)
981
+ write_info
982
+ end
983
+
984
+ # A hook... default is to do nothing
985
+
986
+ def self.modify_job_script(runner, runs, script)
987
+ return script
988
+ end
989
+
990
+ # A hook... a string which gets put into the job
991
+ # script. Used to load modules, configure the run
992
+ # time environment for a given code. Default
993
+ # is to return an empty string.
994
+
995
+ def code_run_environment
996
+ ""
997
+ end
998
+ end
999
+
1000
+ end