gs2crmod 0.11.58 → 0.11.59

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gs2crmod/gs2.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  ##########################################
2
- # = Code Runner GS2 Module
2
+ # = Code Runner GS2 Module
3
3
  ##########################################
4
4
  #
5
5
  # Authors: Edmund Highcock
6
6
  # Copyright: 2009 Edmund Highcock
7
7
  #
8
- # This is free software released under the GPL v3
8
+ # This is free software released under the GPL v3
9
9
  #
10
10
  # This module allows easy running of the plasma turbulence simulation code gs2 using Code Runner, by automatically organising, naming and submitting runs, and analysing the run data.
11
11
  #
@@ -20,35 +20,35 @@
20
20
 
21
21
  #
22
22
 
23
- begin
24
- require "numru/netcdf"
23
+ begin
24
+ require "numru/netcdf"
25
25
  rescue LoadError
26
26
  eputs "Error: No NetCDF: data analysis for gs2 not possible"
27
27
  end
28
28
 
29
29
 
30
30
  class CodeRunner
31
-
32
-
33
-
34
- # This is a customised subclass of CodeRunner::Run which allows CodeRunner to submit and analyse simulations from the gyrokinetic flux tube code GS2, which is principally used for simulating plasmas in magnetic confinement fusion.
35
- #
36
- # It performs two distinct roles: submitting simulations and analysing the data.
37
- #
38
- # = Submitting Simulations
39
- #
40
- # This principally involves generating the input file, which is a very nontrivial task. In order to do this, it maintains a complete record of every possible input parameter for GS2, as well as what datatype that parameter is, and sometimes what values it is allowed to take. This allows that not only to generate the input file, but to check that the input file makes sense. However, although generating the input file works beautifully, the set of sanity checks that it makes is not exhaustive: intelligent use is still required!
41
- #
42
- # In tandem with this, it maintains a whole set of tools for manipulating its database of input parameters. This includes updating their allowed values and also editing and accessing help for every input parameter.
43
- #
44
- # = Analysing Simulations
45
- #
46
- # The amount of analysis possible on GS2 data is enormous, and CodeRunner hasn't got close to getting there. What it can do is:
47
- #
48
- # * Check if the run is complete by comparing the number of completed timesteps against nstep
49
- # * Calculate growth rates for linear runs.
50
- # * Check if non-linear runs have saturated and calculate fluxes for those runs.
51
- # * Automatically plot a huge variety of different graphs, ranging from simple plots of heat flux versus time to three-dimensional plots of the spectrum and potential.
31
+
32
+
33
+
34
+ # This is a customised subclass of CodeRunner::Run which allows CodeRunner to submit and analyse simulations from the gyrokinetic flux tube code GS2, which is principally used for simulating plasmas in magnetic confinement fusion.
35
+ #
36
+ # It performs two distinct roles: submitting simulations and analysing the data.
37
+ #
38
+ # = Submitting Simulations
39
+ #
40
+ # This principally involves generating the input file, which is a very nontrivial task. In order to do this, it maintains a complete record of every possible input parameter for GS2, as well as what datatype that parameter is, and sometimes what values it is allowed to take. This allows that not only to generate the input file, but to check that the input file makes sense. However, although generating the input file works beautifully, the set of sanity checks that it makes is not exhaustive: intelligent use is still required!
41
+ #
42
+ # In tandem with this, it maintains a whole set of tools for manipulating its database of input parameters. This includes updating their allowed values and also editing and accessing help for every input parameter.
43
+ #
44
+ # = Analysing Simulations
45
+ #
46
+ # The amount of analysis possible on GS2 data is enormous, and CodeRunner hasn't got close to getting there. What it can do is:
47
+ #
48
+ # * Check if the run is complete by comparing the number of completed timesteps against nstep
49
+ # * Calculate growth rates for linear runs.
50
+ # * Check if non-linear runs have saturated and calculate fluxes for those runs.
51
+ # * Automatically plot a huge variety of different graphs, ranging from simple plots of heat flux versus time to three-dimensional plots of the spectrum and potential.
52
52
 
53
53
  class Gs2 < Run::FortranNamelist
54
54
 
@@ -57,15 +57,15 @@ GS2_CRMOD_VERSION = Version.new('0.5.0')
57
57
 
58
58
 
59
59
  def agk?
60
- false
60
+ false
61
61
  end
62
62
 
63
63
  def spectrogk?
64
- false
64
+ false
65
65
  end
66
66
 
67
67
  def gryfx?
68
- false
68
+ false
69
69
  end
70
70
 
71
71
  CODE_SCRIPT_FOLDER = MODULE_FOLDER = File.dirname(File.expand_path(__FILE__))
@@ -88,13 +88,13 @@ NaN = GSL::NAN
88
88
 
89
89
 
90
90
  def code_run_environment
91
- case CodeRunner::SYS
92
- when /iridis/
93
- <<EOF
91
+ case CodeRunner::SYS
92
+ when /iridis/
93
+ <<EOF
94
94
  module load openmpi
95
95
  EOF
96
- when /helios/
97
- <<EOF
96
+ when /helios/
97
+ <<EOF
98
98
  module purge
99
99
  module load intel
100
100
  module load bullxmpi
@@ -104,18 +104,18 @@ module load fftw/3.3.3
104
104
  module load bullxde papi
105
105
  module load scalasca
106
106
  EOF
107
- #when /archer/
108
- #<<EOF
107
+ #when /archer/
108
+ #<<EOF
109
109
  #module swap PrgEnv-cray PrgEnv-intel
110
110
  #module load intel/14.0.0.080
111
111
  #module load fftw
112
112
  #module load netcdf-hdf5parallel
113
113
  #module load cray-hdf5-parallel
114
114
  #EOF
115
- else
115
+ else
116
116
 
117
- @code_run_environment
118
- end
117
+ @code_run_environment
118
+ end
119
119
  end
120
120
 
121
121
  eval(%[
@@ -130,44 +130,44 @@ eval(%[
130
130
 
131
131
 
132
132
  @results = [
133
- :converged,
134
- :decaying,
135
- :growth_rates,
136
- :real_frequencies,
137
- :growth_rates_by_ky, # deprecated
138
- :growth_rates_by_kx, # deprecated
139
- :growth_rate_at_ky,
140
- :growth_rate_at_kx,
141
- :growth_rate_at_ky_at_kx,
142
- :frequency_at_ky_at_kx,
143
- :real_frequencies_by_ky,
144
- :max_growth_rate,
145
- :fastest_growing_mode,
146
- :freq_of_max_growth_rate,
147
- :ky,
148
- :gamma_r,
149
- :gamma_i,
150
- :run_time,
151
- :hflux_tot_stav,
152
- :phi2_tot_stav,
153
- :saturation_time_index,
154
- :es_heat_flux_stav,
155
- :es_mom_flux_stav,
156
- :hflux_tot_stav_error,
157
- :es_heat_flux_stav_error,
158
- :es_mom_flux_stav_error,
159
- :saturated,
160
- :shot_time,
161
- :spectrum_check,
162
- :par_mom_flux_stav,
163
- :perp_mom_flux_stav,
164
- :transient_amplification_at_kx,
165
- :transient_amplification_at_ky,
166
- :transient_amplification_at_ky_at_kx,
167
- :transient_es_heat_flux_amplification_at_species_at_kx,
168
- :transient_es_heat_flux_amplification_at_species_at_ky,
169
- :transient_es_heat_flux_amplification_at_species_at_ky_at_kx,
170
- :vspace_check
133
+ :converged,
134
+ :decaying,
135
+ :growth_rates,
136
+ :real_frequencies,
137
+ :growth_rates_by_ky, # deprecated
138
+ :growth_rates_by_kx, # deprecated
139
+ :growth_rate_at_ky,
140
+ :growth_rate_at_kx,
141
+ :growth_rate_at_ky_at_kx,
142
+ :frequency_at_ky_at_kx,
143
+ :real_frequencies_by_ky,
144
+ :max_growth_rate,
145
+ :fastest_growing_mode,
146
+ :freq_of_max_growth_rate,
147
+ :ky,
148
+ :gamma_r,
149
+ :gamma_i,
150
+ :run_time,
151
+ :hflux_tot_stav,
152
+ :phi2_tot_stav,
153
+ :saturation_time_index,
154
+ :es_heat_flux_stav,
155
+ :es_mom_flux_stav,
156
+ :hflux_tot_stav_error,
157
+ :es_heat_flux_stav_error,
158
+ :es_mom_flux_stav_error,
159
+ :saturated,
160
+ :shot_time,
161
+ :spectrum_check,
162
+ :par_mom_flux_stav,
163
+ :perp_mom_flux_stav,
164
+ :transient_amplification_at_kx,
165
+ :transient_amplification_at_ky,
166
+ :transient_amplification_at_ky_at_kx,
167
+ :transient_es_heat_flux_amplification_at_species_at_kx,
168
+ :transient_es_heat_flux_amplification_at_species_at_ky,
169
+ :transient_es_heat_flux_amplification_at_species_at_ky_at_kx,
170
+ :vspace_check
171
171
  ]
172
172
 
173
173
 
@@ -183,30 +183,30 @@ eval(%[
183
183
  # For backwards compatibility with CodeRunner version 0.5.0
184
184
  ##############################################################
185
185
 
186
- @run_info_0_5_0 = {
187
- time: :to_f,
188
- percent_of_total_time: :to_f,
189
- checked_converged: :to_b
190
- }
186
+ @run_info_0_5_0 = {
187
+ time: :to_f,
188
+ percent_of_total_time: :to_f,
189
+ checked_converged: :to_b
190
+ }
191
191
 
192
192
  @results_0_5_0 = {
193
- converged: :to_b,
194
- decaying: :to_b,
195
- :growth_rates => :to_h,
196
- :real_frequencies => :to_h,
197
- # :ky_list => :to_h,
198
- # :kx_list => :to_h,
199
- :growth_rates_by_ky => :to_s,
200
- :real_frequencies_by_ky => :to_s,
201
- :max_growth_rate => :to_f,
202
- :fastest_growing_mode => :to_f,
203
- :freq_of_max_growth_rate => :to_f,
204
- :ky => :to_f,
205
- :gamma_r => :to_f,
206
- :gamma_i => :to_f,
207
- :run_time => :to_f
208
- # :theta_list => :to_h
209
- }
193
+ converged: :to_b,
194
+ decaying: :to_b,
195
+ :growth_rates => :to_h,
196
+ :real_frequencies => :to_h,
197
+ # :ky_list => :to_h,
198
+ # :kx_list => :to_h,
199
+ :growth_rates_by_ky => :to_s,
200
+ :real_frequencies_by_ky => :to_s,
201
+ :max_growth_rate => :to_f,
202
+ :fastest_growing_mode => :to_f,
203
+ :freq_of_max_growth_rate => :to_f,
204
+ :ky => :to_f,
205
+ :gamma_r => :to_f,
206
+ :gamma_i => :to_f,
207
+ :run_time => :to_f
208
+ # :theta_list => :to_h
209
+ }
210
210
 
211
211
  ###############################################################
212
212
 
@@ -220,7 +220,7 @@ Phi = Struct.new("Phi", :phi, :ri, :theta_index, :kx_index, :ky_index)
220
220
  @naming_pars = []
221
221
 
222
222
  # def self.finish_setting_up_class
223
- # @@variables += [
223
+ # @@variables += [
224
224
  # end
225
225
 
226
226
  # This method, as its name suggests, is called whenever CodeRunner is asked to analyse a run directory.this happens if the run status is not :Complete, or if the user has specified recalc_all(-A on the command line) or reprocess_all (-a on the command line).
@@ -228,178 +228,178 @@ Phi = Struct.new("Phi", :phi, :ri, :theta_index, :kx_index, :ky_index)
228
228
  # the structure of this function is very simple: first it calls get_status to determine the directory status, i.e. :Complete, :Incomplete, :NotStarted or :Failed, then it gets the time, which is the GS2 time at the end of the run, and it also gets the run_time, which is the wall clock time of the run. Finally,if non-linear mode is switched off, it calls calculate_growth_rates_and_frequencies, and if the non-linear mode is switched on, it calls calculate_time_averaged_fluxes.
229
229
 
230
230
  def process_directory_code_specific
231
- run_namelist_backwards_compatibility
231
+ run_namelist_backwards_compatibility
232
232
 
233
- unless @status == :Queueing
234
- get_status
235
- end
236
-
237
- eputs "Run #@status: #@run_name" if [:Complete,:Failed].include? @status
233
+ unless @status == :Queueing
234
+ get_status
235
+ end
238
236
 
239
- try_to_get_error_file
240
- @sys = @@successful_trial_system
237
+ eputs "Run #@status: #@run_name" if [:Complete,:Failed].include? @status
241
238
 
242
- return if @status == :NotStarted or @status == :Failed or @status == :Queueing
243
- begin
244
- percent_complete = get_completed_timesteps/@nstep
245
- @percent_of_total_time = percent_complete
246
- rescue
247
- get_time
248
- @percent_of_total_time = @time / (@delt*@nstep) * 100.0 rescue 0.0
249
- end
250
- return if @status == :Incomplete
239
+ try_to_get_error_file
240
+ @sys = @@successful_trial_system
241
+
242
+ return if @status == :NotStarted or @status == :Failed or @status == :Queueing
243
+ begin
244
+ percent_complete = get_completed_timesteps/@nstep
245
+ @percent_of_total_time = percent_complete
246
+ rescue
247
+ get_time
248
+ @percent_of_total_time = @time / (@delt*@nstep) * 100.0 rescue 0.0
249
+ end
250
+ return if @status == :Incomplete
251
251
 
252
- get_run_time
252
+ get_run_time
253
253
 
254
- calculate_results
254
+ calculate_results
255
255
 
256
256
  end
257
257
  def calculate_results
258
- return if ENV['CODE_RUNNER_NO_ANALYSIS'] =~ /true/
259
-
260
-
261
- eputs "Analysing run"
262
-
263
- if @nonlinear_mode == "off"
264
-
265
- calculate_growth_rates_and_frequencies
258
+ return if ENV['CODE_RUNNER_NO_ANALYSIS'] =~ /true/
259
+
260
+
261
+ eputs "Analysing run"
262
+
263
+ if @nonlinear_mode == "off"
264
+
265
+ calculate_growth_rates_and_frequencies
266
266
  calculate_transient_amplifications
267
- elsif @nonlinear_mode == "on"
268
- calculate_saturation_time_index
269
- calculate_time_averaged_fluxes
270
- begin
271
- calculate_spectral_checks
272
- calculate_vspace_checks
273
- rescue
274
- end
275
- end
276
-
277
- @growth_rates ||={}
278
- @real_frequencies ||={}
267
+ elsif @nonlinear_mode == "on"
268
+ calculate_saturation_time_index
269
+ calculate_time_averaged_fluxes
270
+ begin
271
+ calculate_spectral_checks
272
+ calculate_vspace_checks
273
+ rescue
274
+ end
275
+ end
276
+
277
+ @growth_rates ||={}
278
+ @real_frequencies ||={}
279
279
  end
280
-
280
+
281
281
 
282
282
  # Try to read the runtime in minutes from the GS2 standard out.
283
283
 
284
284
  def get_run_time
285
- logf(:get_run_time)
286
- output = @output_file || try_to_get_output_file
287
- return nil unless output
288
- begin
289
- Regexp.new("total from timer is:\\s*#{LongRegexen::NUMBER}", Regexp::IGNORECASE).match FileUtils.tail(output, 300)
290
- logi $~
291
- @run_time = $~[:number].to_f
292
- rescue
293
- @run_time = nil
294
- end
285
+ logf(:get_run_time)
286
+ output = @output_file || try_to_get_output_file
287
+ return nil unless output
288
+ begin
289
+ Regexp.new("total from timer is:\\s*#{LongRegexen::NUMBER}", Regexp::IGNORECASE).match FileUtils.tail(output, 300)
290
+ logi $~
291
+ @run_time = $~[:number].to_f
292
+ rescue
293
+ @run_time = nil
294
+ end
295
295
  end
296
296
 
297
297
  # Output useful information from the NetCDF file. If no names are provided, output a list of all variables in the NetCDF file. <tt>names</tt> can either be a symbol or an array of symbols, in which case information will be output for the variables with those names. If values are provided, for example :dims,:get, :ndims, this information is retrieved from the file for every variable named.
298
- # ncdump
299
- # ncdump(:hflux)
300
- # ncdump([:hflux, :phi])
301
- # ncdump([:hflux, :phi], :dims)
298
+ # ncdump
299
+ # ncdump(:hflux)
300
+ # ncdump([:hflux, :phi])
301
+ # ncdump([:hflux, :phi], :dims)
302
302
 
303
303
 
304
304
  def ncdump(names=nil, values=nil, extension = '.out.nc')
305
- names = [names] unless !names or names.class == Array
306
- names.map!{|name| name.to_s} if names
307
- pp NumRu::NetCDF.open(@run_name + extension).vars(names).to_a.sort{|var1, var2| var1.name <=> var2.name}.map{|var| values ? [var.name, var.send(values)] : var.name.to_sym}
305
+ names = [names] unless !names or names.class == Array
306
+ names.map!{|name| name.to_s} if names
307
+ pp NumRu::NetCDF.open(@run_name + extension).vars(names).to_a.sort{|var1, var2| var1.name <=> var2.name}.map{|var| values ? [var.name, var.send(values)] : var.name.to_sym}
308
308
  end
309
309
 
310
310
 
311
311
  #
312
312
 
313
313
  def generate_component_runs
314
- @component_runs = []
315
- logf(:generate_component_runs)
316
- return if @grid_option == "single" and @scan_type == "none"
317
- begin
318
- list(:ky) # This will fail unless the run has output the netcdf file
319
- rescue
320
- return
321
- end
322
- return unless @status == :Complete #and @converged
323
- log(@run_name)
324
- if @grid_option == "box" and @nonlinear_mode == "off"
325
- @ky = nil
326
- # raise CRFatal.new("no @ky_list") unless @ky_list
327
- # log list(:ky)
328
- list(:ky).each do |id, ky|
329
- component_run = create_component #self.dup
330
- component_run.ky = ky
331
- component_run.gamma_r = @growth_rates[ky]
332
- component_run.gamma_i = @real_frequencies[ky]
333
- log @runner.component_ids
334
- # log('@runner.class', @runner.class)
335
- # @runner.add_component_run(component_run)
336
- end
337
- elsif (not gryfx?) and @scan_type and @scan_type != "none"
338
- t = gsl_vector('t')
339
- scan_vals = gsl_vector('scan_parameter_value')
340
- current = scan_vals[0]
341
- start = 0
342
- for i in 0...t.size
343
- if scan_vals[i] != current
344
- component = create_component
345
- component.scan_index_window = [start+1, i] #remember indexes are elements + 1
346
- #ep 'scan_index_window', component.scan_index_window
347
- component.scan_parameter_value = current
348
- component.growth_rate_at_ky = nil
349
- component.growth_rate_at_kx = nil
350
- component.growth_rate_at_ky_at_kx = nil
351
- component.calculate_results
352
- current = scan_vals[i]
353
- start = i
354
- end
355
- end
356
- end
314
+ @component_runs = []
315
+ logf(:generate_component_runs)
316
+ return if @grid_option == "single" and @scan_type == "none"
317
+ begin
318
+ list(:ky) # This will fail unless the run has output the netcdf file
319
+ rescue
320
+ return
321
+ end
322
+ return unless @status == :Complete #and @converged
323
+ log(@run_name)
324
+ if @grid_option == "box" and @nonlinear_mode == "off"
325
+ @ky = nil
326
+ # raise CRFatal.new("no @ky_list") unless @ky_list
327
+ # log list(:ky)
328
+ list(:ky).each do |id, ky|
329
+ component_run = create_component #self.dup
330
+ component_run.ky = ky
331
+ component_run.gamma_r = @growth_rates[ky]
332
+ component_run.gamma_i = @real_frequencies[ky]
333
+ log @runner.component_ids
334
+ # log('@runner.class', @runner.class)
335
+ # @runner.add_component_run(component_run)
336
+ end
337
+ elsif (not gryfx?) and @scan_type and @scan_type != "none"
338
+ t = gsl_vector('t')
339
+ scan_vals = gsl_vector('scan_parameter_value')
340
+ current = scan_vals[0]
341
+ start = 0
342
+ for i in 0...t.size
343
+ if scan_vals[i] != current
344
+ component = create_component
345
+ component.scan_index_window = [start+1, i] #remember indexes are elements + 1
346
+ #ep 'scan_index_window', component.scan_index_window
347
+ component.scan_parameter_value = current
348
+ component.growth_rate_at_ky = nil
349
+ component.growth_rate_at_kx = nil
350
+ component.growth_rate_at_ky_at_kx = nil
351
+ component.calculate_results
352
+ current = scan_vals[i]
353
+ start = i
354
+ end
355
+ end
356
+ end
357
357
  end
358
358
 
359
359
 
360
360
 
361
361
  def get_time
362
- begin
363
- lt = list(:t)
364
- return lt.values.max if lt.size>0
365
- rescue
366
- end
367
- time = nil
368
- # eputs File.readlines(@run_name +".out").slice(-4..-1).reverse.join( "\n"); gets
369
- raise CRFatal.new("Couldn't find outfile #{@run_name}.out") unless FileTest.exist?(@run_name + ".out")
370
- tail = FileUtils.tail("#@run_name.out", 4)
371
- #File.readlines(@run_name +".out").slice(-4..-1).reverse.join( "\n")
372
- tail.sub(LongRegexen::FLOAT) do
373
- # eputs $~.inspect
374
- time = $~[:float].to_f
375
- end #if FileTest.exist? (@run_name +".out")
376
- #raise CRFatal.new("couldn't get the time from #{tail}") unless time
377
- @time = time
362
+ begin
363
+ lt = list(:t)
364
+ return lt.values.max if lt.size>0
365
+ rescue
366
+ end
367
+ time = nil
368
+ # eputs File.readlines(@run_name +".out").slice(-4..-1).reverse.join( "\n"); gets
369
+ raise CRFatal.new("Couldn't find outfile #{@run_name}.out") unless FileTest.exist?(@run_name + ".out")
370
+ tail = FileUtils.tail("#@run_name.out", 4)
371
+ #File.readlines(@run_name +".out").slice(-4..-1).reverse.join( "\n")
372
+ tail.sub(LongRegexen::FLOAT) do
373
+ # eputs $~.inspect
374
+ time = $~[:float].to_f
375
+ end #if FileTest.exist? (@run_name +".out")
376
+ #raise CRFatal.new("couldn't get the time from #{tail}") unless time
377
+ @time = time
378
378
  end
379
379
 
380
- def get_completed_timesteps
381
- #raise CRFatal.new("Couldn't find outfile #{@run_name}.out") unless FileTest.exist?(@run_name + ".out")
382
- #p 'try to get completed_timesteps', Dir.pwd, 'nwrite', @nwrite, 'delt', @delt
383
- @completed_timesteps = (list(:t).size - 1) * (@nwrite || 1)
384
- #p 'tried to get completed_timesteps'
385
- #rescue
386
- #`grep time= #@run_name.out`.split.size
387
- # File.read("#@run_name.out").scan(/^\s+time\s*=\s+/).size * @nwrite
380
+ def get_completed_timesteps
381
+ #raise CRFatal.new("Couldn't find outfile #{@run_name}.out") unless FileTest.exist?(@run_name + ".out")
382
+ #p 'try to get completed_timesteps', Dir.pwd, 'nwrite', @nwrite, 'delt', @delt
383
+ @completed_timesteps = (list(:t).size - 1) * (@nwrite || 1)
384
+ #p 'tried to get completed_timesteps'
385
+ #rescue
386
+ #`grep time= #@run_name.out`.split.size
387
+ # File.read("#@run_name.out").scan(/^\s+time\s*=\s+/).size * @nwrite
388
388
  end
389
389
 
390
390
  def incomplete
391
- return (not 100 == percent_complete)
391
+ return (not 100 == percent_complete)
392
392
  end
393
393
 
394
394
  def parameter_transition(run)
395
395
  end
396
396
  # @@executable_location = nil
397
397
  # def executable_location
398
- # return "~/gs2_newterm" #(@@executable_location || ($gs2_new_term ? "~/gs2_newterm" : "~/gs2"))
398
+ # return "~/gs2_newterm" #(@@executable_location || ($gs2_new_term ? "~/gs2_newterm" : "~/gs2"))
399
399
  # end
400
- #
400
+ #
401
401
  # def executable_name
402
- # "gs2"
402
+ # "gs2"
403
403
  # end
404
404
 
405
405
  @code_long = "GS2 Gyrokinetic Flux Tube Code"
@@ -410,114 +410,114 @@ attr_accessor :theta_list, :ky_list, :ky_graphs, :eigenfunctions, :ky_list, :t_l
410
410
  attr_accessor :scan_index_window, :scan_parameter_value
411
411
 
412
412
  class << self
413
- aliold(:check_and_update)
414
- def check_and_update
415
- old_check_and_update
416
- @readout_list = (@variables + @results - [:growth_rates_by_ky, :growth_rates, :real_frequencies, :real_frequencies_by_ky, :ky_list, :kx_list, :theta_list, :t_list])
417
- end
413
+ aliold(:check_and_update)
414
+ def check_and_update
415
+ old_check_and_update
416
+ @readout_list = (@variables + @results - [:growth_rates_by_ky, :growth_rates, :real_frequencies, :real_frequencies_by_ky, :ky_list, :kx_list, :theta_list, :t_list])
417
+ end
418
418
  end
419
419
 
420
420
  def data_string
421
- logf(:data_string)
422
- return "" unless @converged unless @grid_option == 'single'
423
- logi(@ky, @growth_rates, @real_frequencies)
424
- # log(:@@readout_list, @@readout_list)
425
- return rcp.readout_list.inject(""){|str,(var,type_co)| str+"#{(send(var) || "0")}\t"} + "\n"
421
+ logf(:data_string)
422
+ return "" unless @converged unless @grid_option == 'single'
423
+ logi(@ky, @growth_rates, @real_frequencies)
424
+ # log(:@@readout_list, @@readout_list)
425
+ return rcp.readout_list.inject(""){|str,(var,_)| str+"#{(send(var) || "0")}\t"} + "\n"
426
426
 
427
- # @ky ? (@@variables + @@results - ).inject(""){|str,(var,type_co)| str+"#{(send(var) || "0")}\t"} + sprintf("%e\t%e\t%e\n", @ky, @growth_rates[@ky], @real_frequencies[@ky]) : (@@variables + @@results).inject(""){|str,(var,type_co)| str+"#{(send(var) || "0")}\t"} + sprintf("%e\t%e\t%e\n", @fastest_growing_mode, @max_growth_rate, @freq_of_max_growth_rate)
427
+ # @ky ? (@@variables + @@results - ).inject(""){|str,(var,type_co)| str+"#{(send(var) || "0")}\t"} + sprintf("%e\t%e\t%e\n", @ky, @growth_rates[@ky], @real_frequencies[@ky]) : (@@variables + @@results).inject(""){|str,(var,type_co)| str+"#{(send(var) || "0")}\t"} + sprintf("%e\t%e\t%e\n", @fastest_growing_mode, @max_growth_rate, @freq_of_max_growth_rate)
428
428
  end
429
429
 
430
430
  def percent_complete
431
- @completed_timesteps ? @completed_timesteps.to_f / @nstep.to_f * 100.0 : @percent_of_total_time
431
+ @completed_timesteps ? @completed_timesteps.to_f / @nstep.to_f * 100.0 : @percent_of_total_time
432
432
  end
433
433
 
434
434
  def print_out_line
435
- logf(:print_out_line)
436
- name = @run_name
437
- name += " (res: #@restart_id)" if @restart_id
438
- name += " real_id: #@real_id" if @real_id
439
- beginning = sprintf("%2d:%d %-60s %1s:%2.1f(%s) %3s%1s %1s", @id, @job_no, name, @status.to_s[0,1], @run_time.to_f / 60.0, @nprocs.to_s, percent_complete, "%", @converged.to_s)
440
- if @ky
441
- beginning += sprintf("%3s %4s %4s", @ky, @growth_rates[@ky], @real_frequencies[@ky])
442
- elsif @nonlinear_mode == "off"
443
- beginning += sprintf("%3s %4s %4s",
444
- @fastest_growing_mode, @max_growth_rate,
445
- @freq_of_max_growth_rate)
446
- elsif @nonlinear_mode == "on"
447
- # p @hflux_tot_stav
448
- beginning += " sat:#{saturated.to_s[0]}"
449
- beginning += sprintf(" hflux:%1.2e", @hflux_tot_stav) if @hflux_tot_stav
450
- beginning += sprintf("+/-%1.2e", @hflux_tot_stav_error) if @hflux_tot_stav_error
451
- beginning += sprintf(" momflux:%1.2e", @es_mom_flux_stav.values.sum) if @es_mom_flux_stav and @es_mom_flux_stav.values[0]
452
- beginning += ' SC:' + @spectrum_check.map{|c| c.to_s}.join(',') if @spectrum_check
453
- beginning += ' VC:' + @vspace_check.map{|c| sprintf("%d", ((c*10.0).to_i rescue -1))}.join(',') if @vspace_check
454
- end
455
- beginning += " ---#{@comment}" if @comment
456
- beginning
457
-
458
- end
435
+ logf(:print_out_line)
436
+ name = @run_name
437
+ name += " (res: #@restart_id)" if @restart_id
438
+ name += " real_id: #@real_id" if @real_id
439
+ beginning = sprintf("%2d:%d %-60s %1s:%2.1f(%s) %3s%1s %1s", @id, @job_no, name, @status.to_s[0,1], @run_time.to_f / 60.0, @nprocs.to_s, percent_complete, "%", @converged.to_s)
440
+ if @ky
441
+ beginning += sprintf("%3s %4s %4s", @ky, @growth_rates[@ky], @real_frequencies[@ky])
442
+ elsif @nonlinear_mode == "off"
443
+ beginning += sprintf("%3s %4s %4s",
444
+ @fastest_growing_mode, @max_growth_rate,
445
+ @freq_of_max_growth_rate)
446
+ elsif @nonlinear_mode == "on"
447
+ # p @hflux_tot_stav
448
+ beginning += " sat:#{saturated.to_s[0]}"
449
+ beginning += sprintf(" hflux:%1.2e", @hflux_tot_stav) if @hflux_tot_stav
450
+ beginning += sprintf("+/-%1.2e", @hflux_tot_stav_error) if @hflux_tot_stav_error
451
+ beginning += sprintf(" momflux:%1.2e", @es_mom_flux_stav.values.sum) if @es_mom_flux_stav and @es_mom_flux_stav.values[0]
452
+ beginning += ' SC:' + @spectrum_check.map{|c| c.to_s}.join(',') if @spectrum_check
453
+ beginning += ' VC:' + @vspace_check.map{|c| sprintf("%d", ((c*10.0).to_i rescue -1))}.join(',') if @vspace_check
454
+ end
455
+ beginning += " ---#{@comment}" if @comment
456
+ beginning
457
+
458
+ end
459
459
 
460
460
 
461
461
  def get_list_of(*args)
462
- #args can be any list of e.g. :ky, :kx, :theta, :t ...
463
- logf(:get_list_of)
464
- refresh = args[-1] == true ? true : false
465
- args.pop if args[-1] == true
466
- logd
467
- Dir.chdir(@directory) do
468
- args.each do |var|
469
- # eputs "Loading #{var}"
470
- list_name = var + :_list
471
- log list_name
472
-
473
- # self.class.send(:attr_accessor, list_name)
474
- next if (cache[list_name] and [:Failed, :Complete].include? status and not refresh)
475
-
476
- cache[list_name] = {}
477
- if netcdf_file.var(var.to_s)
478
- netcdf_file.var(var.to_s).get.to_a.each_with_index do |value, element|
479
- # print '.'
480
- cache[list_name][element+1]=value
481
- end
482
-
483
- else
484
- netcdf_file.dim(var.to_s).length.times.each do |element|
485
- cache[list_name][element+1]='unknown'
486
- end
487
- end
488
-
489
- # eputs send(var+:_list)
490
- end
491
- end
492
- logfc :get_list_of
493
- return cache[args[0] + :_list] if args.size == 1
462
+ #args can be any list of e.g. :ky, :kx, :theta, :t ...
463
+ logf(:get_list_of)
464
+ refresh = args[-1] == true ? true : false
465
+ args.pop if args[-1] == true
466
+ logd
467
+ Dir.chdir(@directory) do
468
+ args.each do |var|
469
+ # eputs "Loading #{var}"
470
+ list_name = var + :_list
471
+ log list_name
472
+
473
+ # self.class.send(:attr_accessor, list_name)
474
+ next if (cache[list_name] and [:Failed, :Complete].include? status and not refresh)
475
+
476
+ cache[list_name] = {}
477
+ if netcdf_file.var(var.to_s)
478
+ netcdf_file.var(var.to_s).get.to_a.each_with_index do |value, element|
479
+ # print '.'
480
+ cache[list_name][element+1]=value
481
+ end
482
+
483
+ else
484
+ netcdf_file.dim(var.to_s).length.times.each do |element|
485
+ cache[list_name][element+1]='unknown'
486
+ end
487
+ end
488
+
489
+ # eputs send(var+:_list)
490
+ end
491
+ end
492
+ logfc :get_list_of
493
+ return cache[args[0] + :_list] if args.size == 1
494
494
  end
495
495
 
496
496
  alias :list :get_list_of
497
497
 
498
498
  def visually_check_growth_rate(ky=nil)
499
- logf :visually_check_growth_rate
500
- phi_vec = gsl_vector(:phi2_by_ky_over_time, {ky: ky})
501
- t_vec = gsl_vector(:t)
502
- constant, growth_rate = GSL::Fit::linear(t_vec, 0.5*GSL::Sf::log(phi_vec)).slice(0..1)
503
- eputs growth_rate
504
-
505
- graph = @@phi2tot_vs_time_template.graph(["#{constant} * exp (2 * #{growth_rate} * x)"], [[[t_vec, phi_vec], "u 1:2 title 'phi2tot #{@run_name}' w p"]], {"set_show_commands" => "\nset log y\n", "point_size"=>'1.0'})
506
- # eputs graph.inline_data.inspect
507
- graph.show
508
- gets
509
- graph.kill
499
+ logf :visually_check_growth_rate
500
+ phi_vec = gsl_vector(:phi2_by_ky_over_time, {ky: ky})
501
+ t_vec = gsl_vector(:t)
502
+ constant, growth_rate = GSL::Fit::linear(t_vec, 0.5*GSL::Sf::log(phi_vec)).slice(0..1)
503
+ eputs growth_rate
504
+
505
+ graph = @@phi2tot_vs_time_template.graph(["#{constant} * exp (2 * #{growth_rate} * x)"], [[[t_vec, phi_vec], "u 1:2 title 'phi2tot #{@run_name}' w p"]], {"set_show_commands" => "\nset log y\n", "point_size"=>'1.0'})
506
+ # eputs graph.inline_data.inspect
507
+ graph.show
508
+ gets
509
+ graph.kill
510
510
 
511
511
  end
512
512
 
513
513
 
514
514
  def show_graph
515
- thegraph = special_graph('phi2tot_vs_time_all_kys')
516
- thegraph.title += " for g_exb = #{@g_exb.to_f.to_s}"
517
- thegraph.show
518
- sleep 1.5
519
- # @decaying = Feedback.get_boolean("Is the graph decaying?")
520
- thegraph.kill
515
+ thegraph = special_graph('phi2tot_vs_time_all_kys')
516
+ thegraph.title += " for g_exb = #{@g_exb.to_f.to_s}"
517
+ thegraph.show
518
+ sleep 1.5
519
+ # @decaying = Feedback.get_boolean("Is the graph decaying?")
520
+ thegraph.kill
521
521
  end
522
522
 
523
523
  # @@phi2tot_vs_time_template = {title: "Phi^2 Total vs Time", xlabel: " Time ", ylabel: "Phi^2 Total"})
@@ -526,70 +526,70 @@ end
526
526
 
527
527
 
528
528
  def restart(new_run)
529
- #new_run = self.dup
530
- (rcp.variables).each{|v| new_run.set(v, send(v)) if send(v)}
529
+ #new_run = self.dup
530
+ (rcp.variables).each{|v| new_run.set(v, send(v)) if send(v)}
531
531
  @naming_pars.delete(:preamble)
532
- SUBMIT_OPTIONS.each{|v| new_run.set(v, self.send(v)) unless new_run.send(v)}
533
- #(rcp.results + rcp.gs2_run_info).each{|result| new_run.set(result, nil)}
534
- new_run.is_a_restart = true
535
- new_run.ginit_option = "many"
536
- new_run.delt_option = "check_restart"
537
- #if Dir.entries(@directory).include? "nc"
538
- #old_restart_run_name = (@restart_run_name or Dir.entries(@directory + '/nc').grep(/\.nc/)[0].sub(/\.nc\.\d+$/, ''))
539
- #new_run.restart_file = File.expand_path("#@directory/nc/#{old_restart_run_name}.nc")
540
- #else
541
- #new_run.restart_file = File.expand_path("#@directory/#@run_name.nc")
542
- #end
543
- new_run.restart_id = @id
544
- new_run.restart_run_name = @run_name
545
- @runner.nprocs = @nprocs if @runner.nprocs == "1" # 1 is the default so this means the user probably didn't specify nprocs
546
- raise "Restart must be on the same number of processors as the previous run: new is #{new_run.nprocs.inspect} and old is #{@nprocs.inspect}" if !new_run.nprocs or new_run.nprocs != @nprocs
547
- # @runner.parameters.each{|var, value| new_run.set(var,value)} if @runner.parameters
532
+ SUBMIT_OPTIONS.each{|v| new_run.set(v, self.send(v)) unless new_run.send(v)}
533
+ #(rcp.results + rcp.gs2_run_info).each{|result| new_run.set(result, nil)}
534
+ new_run.is_a_restart = true
535
+ new_run.ginit_option = "many"
536
+ new_run.delt_option = "check_restart"
537
+ #if Dir.entries(@directory).include? "nc"
538
+ #old_restart_run_name = (@restart_run_name or Dir.entries(@directory + '/nc').grep(/\.nc/)[0].sub(/\.nc\.\d+$/, ''))
539
+ #new_run.restart_file = File.expand_path("#@directory/nc/#{old_restart_run_name}.nc")
540
+ #else
541
+ #new_run.restart_file = File.expand_path("#@directory/#@run_name.nc")
542
+ #end
543
+ new_run.restart_id = @id
544
+ new_run.restart_run_name = @run_name
545
+ @runner.nprocs = @nprocs if @runner.nprocs == "1" # 1 is the default so this means the user probably didn't specify nprocs
546
+ raise "Restart must be on the same number of processors as the previous run: new is #{new_run.nprocs.inspect} and old is #{@nprocs.inspect}" if !new_run.nprocs or new_run.nprocs != @nprocs
547
+ # @runner.parameters.each{|var, value| new_run.set(var,value)} if @runner.parameters
548
548
  # ep @runner.parameters
549
549
  new_run.run_name = nil
550
- new_run.naming_pars = @naming_pars
551
- new_run.update_submission_parameters(new_run.parameter_hash_string, false) if new_run.parameter_hash
552
- new_run.naming_pars.delete(:restart_id)
553
- new_run.generate_run_name
554
- eputs 'Copying Restart files', ''
555
- FileUtils.makedirs(new_run.directory + '/nc')
556
- #old_dir = File.dirname(@restart_file)
557
- new_run.restart_file = "#@run_name.nc" #+ File.basename(@restart_file) #.sub(/\.nc/, '')
558
- new_run.restart_dir = "nc"
559
- #files = Dir.entries(old_dir).grep(/\.nc(?:\.\d|_ene)/)
560
- #files = Dir.entries(old_dir).grep(/^\.\d+$/) if files.size == 0
561
- files = list_of_restart_files.map do |file|
562
- @directory + "/" + file
563
- end
564
- files.each_with_index do |file , index|
565
- eputs "\033[2A" # Terminal jargon - go back one line
566
- eputs "#{index+1} out of #{files.size}"
567
- num = file.scan(/(?:\.\d+|_ene)$/)[0]
568
- #FileUtils.cp("#{old_dir}/#{file}", "nc/#@restart_file#{num}")
569
- FileUtils.cp(file, new_run.directory + "/nc/#{new_run.restart_file}#{num}")
570
- end
571
- #@runner.submit(new_run)
572
- new_run
573
- end
574
-
575
- # Return a list of restart file paths (relative to the run directory).
550
+ new_run.naming_pars = @naming_pars
551
+ new_run.update_submission_parameters(new_run.parameter_hash_string, false) if new_run.parameter_hash
552
+ new_run.naming_pars.delete(:restart_id)
553
+ new_run.generate_run_name
554
+ eputs 'Copying Restart files', ''
555
+ FileUtils.makedirs(new_run.directory + '/nc')
556
+ #old_dir = File.dirname(@restart_file)
557
+ new_run.restart_file = "#@run_name.nc" #+ File.basename(@restart_file) #.sub(/\.nc/, '')
558
+ new_run.restart_dir = "nc"
559
+ #files = Dir.entries(old_dir).grep(/\.nc(?:\.\d|_ene)/)
560
+ #files = Dir.entries(old_dir).grep(/^\.\d+$/) if files.size == 0
561
+ files = list_of_restart_files.map do |file|
562
+ @directory + "/" + file
563
+ end
564
+ files.each_with_index do |file , index|
565
+ eputs "\033[2A" # Terminal jargon - go back one line
566
+ eputs "#{index+1} out of #{files.size}"
567
+ num = file.scan(/(?:\.\d+|_ene)$/)[0]
568
+ #FileUtils.cp("#{old_dir}/#{file}", "nc/#@restart_file#{num}")
569
+ FileUtils.cp(file, new_run.directory + "/nc/#{new_run.restart_file}#{num}")
570
+ end
571
+ #@runner.submit(new_run)
572
+ new_run
573
+ end
574
+
575
+ # Return a list of restart file paths (relative to the run directory).
576
576
 
577
577
  def list_of_restart_files
578
- Dir.chdir(@directory) do
579
- files = Dir.entries.grep(/^\.\d+$/)
580
- files = Dir.entries.grep(/\.nc(?:\.\d|_ene)/) if files.size == 0
581
- if files.size == 0
582
- (Dir.entries.find_all{|dir| FileTest.directory? dir} - ['.', '..']).each do |dir|
583
- files = Dir.entries(dir).grep(/\.nc(?:\.\d|_ene)/).map{|file| dir + "/" + file}
584
- break if files.size == 0
585
- end
586
- end #if files.size == 0
578
+ Dir.chdir(@directory) do
579
+ files = Dir.entries.grep(/^\.\d+$/)
580
+ files = Dir.entries.grep(/\.nc(?:\.\d|_ene)/) if files.size == 0
581
+ if files.size == 0
582
+ (Dir.entries.find_all{|dir| FileTest.directory? dir} - ['.', '..']).each do |dir|
583
+ files = Dir.entries(dir).grep(/\.nc(?:\.\d|_ene)/).map{|file| dir + "/" + file}
584
+ break if files.size == 0
585
+ end
586
+ end #if files.size == 0
587
587
  # This just finds a .nc file (w/o a number) in the nc folder if using single restart file
588
- if files.size == 0
589
- files = Dir.entries('nc').grep(/\.nc/).map{|file| 'nc' + "/" + file}
590
- end #if files.size == 0
591
- return files
592
- end # Dir.chdir(@directory) do
588
+ if files.size == 0
589
+ files = Dir.entries('nc').grep(/\.nc/).map{|file| 'nc' + "/" + file}
590
+ end #if files.size == 0
591
+ return files
592
+ end # Dir.chdir(@directory) do
593
593
  end
594
594
 
595
595
  alias :lorf :list_of_restart_files
@@ -597,14 +597,14 @@ alias :lorf :list_of_restart_files
597
597
  # Put restart files in the conventional location, i.e. nc/run_name.proc
598
598
 
599
599
  def standardize_restart_files
600
- Dir.chdir(@directory) do
601
- FileUtils.makedirs('nc')
602
- list_of_restart_files.each do |file|
603
- proc_id = file.scan(/\.\d+$|_ene$/)[0]
604
- #p 'proc_id', proc_id
605
- FileUtils.mv(file, "nc/#@run_name.nc#{proc_id}")
606
- end
607
- end
600
+ Dir.chdir(@directory) do
601
+ FileUtils.makedirs('nc')
602
+ list_of_restart_files.each do |file|
603
+ proc_id = file.scan(/\.\d+$|_ene$/)[0]
604
+ #p 'proc_id', proc_id
605
+ FileUtils.mv(file, "nc/#@run_name.nc#{proc_id}")
606
+ end
607
+ end
608
608
  end
609
609
 
610
610
  # Delete all the restart files (irreversible!)
@@ -613,267 +613,271 @@ end
613
613
  def delete_restart_files(options={})
614
614
  puts 'You are about to delete the restart files for:'
615
615
  puts @run_name
616
- return unless Feedback.get_boolean("This action cannot be reversed. Do you wish to continue?") unless options[:no_confirm]
617
- list_of_restart_files.each{|file| FileUtils.rm file}
616
+ return unless Feedback.get_boolean("This action cannot be reversed. Do you wish to continue?") unless options[:no_confirm]
617
+ list_of_restart_files.each{|file| FileUtils.rm file}
618
618
  end
619
619
 
620
620
 
621
-
621
+
622
622
 
623
623
 
624
624
  def species_letter
625
- species_type(1).downcase[0,1]
625
+ species_type(1).downcase[0,1]
626
626
  end
627
627
 
628
- def species_type(index)
629
- if rcp.variables.include? :type_1
630
- type = send(:type_ + index.to_sym)
631
- else
632
- types = rcp.variables.find_all{|var| var.to_s =~ /^type/}.map{|var| send(var)}
633
- type = types[index.to_i - 1]
634
- end
635
- type
628
+ def species_type(index)
629
+ if rcp.variables.include? :type_1
630
+ type = send(:type_ + index.to_sym)
631
+ else
632
+ types = rcp.variables.find_all{|var| var.to_s =~ /^type/}.map{|var| send(var)}
633
+ type = types[index.to_i - 1]
634
+ end
635
+ type
636
636
  end
637
637
 
638
638
 
639
639
  # Returns true if this run has not been restarted, false if it has. This allows one to get data from the final run of a series of restarts.
640
640
 
641
641
  def no_restarts
642
- raise NoRunnerError unless @runner
643
- !(@runner.runs.find{|run| run.restart_id == @id})
642
+ raise NoRunnerError unless @runner
643
+ !(@runner.runs.find{|run| run.restart_id == @id})
644
644
  end
645
645
 
646
646
 
647
647
  def restart_chain
648
- if @restart_id
649
- return @runner.run_list[@restart_id].restart_chain
650
- end
651
- chain = []
652
- currid = @id
653
- loop do
654
- chain.push currid
655
- break unless (restrt = @runner.runs.find{|run| run.restart_id == currid})
656
- currid = restrt.id
657
- end
658
- return chain
648
+ if @restart_id
649
+ return @runner.run_list[@restart_id].restart_chain
650
+ end
651
+ chain = []
652
+ currid = @id
653
+ loop do
654
+ chain.push currid
655
+ break unless (restrt = @runner.runs.find{|run| run.restart_id == currid})
656
+ currid = restrt.id
657
+ end
658
+ return chain
659
659
  end
660
660
 
661
661
 
662
662
 
663
663
 
664
-
664
+
665
665
 
666
666
  def get_status
667
- # eputs 'Checking Status'
668
- logf(:get_status)
669
-
670
- Dir.chdir(@directory) do
671
- if @running
672
- if FileTest.exist?(@run_name + ".out") and FileUtils.tail(@run_name + ".out", 5).split(/\n/).size > 4 and FileUtils.tail(@run_name + ".out", 200) =~ /t\=/
673
- @status = :Incomplete
674
- else
675
- @status = :NotStarted
676
- end
677
-
678
- else
679
- if FileTest.exist?(@run_name + ".out") and FileUtils.tail(@run_name + ".out", 5).split(/\n/).size > 4
680
- #eputs "HERE", @scan_type
681
- if @nonlinear_mode == "off" and FileUtils.tail(@run_name + ".out",200) =~ /omega converged/
682
- eputs 'Omega converged...'
683
- @status = :Complete
684
- elsif @scan_type and @scan_type != "none" and FileUtils.tail(@run_name + ".par_scan",200) =~ /scan\s+is\s+complete/i
685
- eputs 'Scan complete...'
686
- @status = :Complete
687
- elsif @nonlinear_mode == "on" or !@omegatol or @omegatol < 0.0 or (@exit_when_converged and @exit_when_converged.fortran_false?)
688
- eputs 'No omegatol'
689
- if FileTest.exist?(@run_name + ".out.nc")
690
- #p ['pwd', Dir.pwd, netcdf_file, netcdf_file.dim('t'), netcdf_file.dims]
691
- if netcdf_file.dim('t').length > 0
692
- get_completed_timesteps
693
- else
694
- @status = :Failed
695
- return
696
- end
697
- else
698
- eputs "Warning: no netcdf file #@run_name.out.nc"
699
- @status = :Failed
700
- return
701
- end
702
- #ep "completed_timesteps", @completed_timesteps
703
- eputs "#{percent_complete}% of Timesteps Complete"
704
- if percent_complete >= 100.0
705
- @status = :Complete
706
- elsif percent_complete > 5 and FileUtils.tail(output_file, 200) =~ /total from timer is/
707
- @status = :Complete
708
- else
709
- @status = :Failed
710
- end
711
- else
712
- @status = :Failed
713
- end
714
- else
715
- @status=:Failed
716
- end
717
- end
718
- end
667
+ # eputs 'Checking Status'
668
+ logf(:get_status)
669
+
670
+ Dir.chdir(@directory) do
671
+ if @running
672
+ if FileTest.exist?(@run_name + ".out") and FileUtils.tail(@run_name + ".out", 5).split(/\n/).size > 4 and FileUtils.tail(@run_name + ".out", 200) =~ /t\=/
673
+ @status = :Incomplete
674
+ else
675
+ @status = :NotStarted
676
+ end
677
+
678
+ else
679
+ if FileTest.exist?(@run_name + ".out") and FileUtils.tail(@run_name + ".out", 5).split(/\n/).size > 4
680
+ #eputs "HERE", @scan_type
681
+ if @nonlinear_mode == "off" and FileUtils.tail(@run_name + ".out",200) =~ /omega converged/
682
+ eputs 'Omega converged...'
683
+ @status = :Complete
684
+ elsif @scan_type and @scan_type != "none" and FileUtils.tail(@run_name + ".par_scan",200) =~ /scan\s+is\s+complete/i
685
+ eputs 'Scan complete...'
686
+ @status = :Complete
687
+ elsif @nonlinear_mode == "on" or !@omegatol or @omegatol < 0.0 or (@exit_when_converged and @exit_when_converged.fortran_false?)
688
+ eputs 'No omegatol'
689
+ if FileTest.exist?(@run_name + ".out.nc")
690
+ #p ['pwd', Dir.pwd, netcdf_file, netcdf_file.dim('t'), netcdf_file.dims]
691
+ if netcdf_file.dim('t').length > 0
692
+ get_completed_timesteps
693
+ else
694
+ @status = :Failed
695
+ return
696
+ end
697
+ else
698
+ eputs "Warning: no netcdf file #@run_name.out.nc"
699
+ @status = :Failed
700
+ return
701
+ end
702
+ #ep "completed_timesteps", @completed_timesteps
703
+ eputs "#{percent_complete}% of Timesteps Complete"
704
+ if percent_complete >= 100.0
705
+ @status = :Complete
706
+ elsif percent_complete > 5 and FileUtils.tail(output_file, 200) =~ /total from timer is/
707
+ @status = :Complete
708
+ else
709
+ @status = :Failed
710
+ end
711
+ else
712
+ @status = :Failed
713
+ end
714
+ else
715
+ @status=:Failed
716
+ end
717
+ end
718
+ end
719
719
  end
720
720
 
721
721
 
722
- def self.modify_job_script(runner, runs, script)
723
- if CODE_OPTIONS[:gs2] and CODE_OPTIONS[:gs2][:list]
724
- if (list_size = CODE_OPTIONS[:gs2][:list]).kind_of? Integer
725
- raise "The total number of runs must be a multiple of the list size!" unless runs.size % list_size == 0
726
- pieces = runs.pieces(runs.size/list_size)
727
- else
728
- pieces = [runs]
729
- end
730
- script = ""
731
- pieces.each do |runs|
732
- #ep 'there is a list'
733
- FileUtils.makedirs('job_lists')
734
- jid = "#{runs[0].id}-#{runs[-1].id}"
735
- list_file = "job_lists/gs2_list_#{jid}.list"
736
- File.open(list_file,'w') do |file|
737
- file.puts runs.size
738
- file.puts runs.map{|r| "#{r.relative_directory}/#{r.run_name}"}.join("\n")
739
- end
740
- raise "runs must all have the same nprocs" unless runs.map{|r| r.nprocs}.uniq.size == 1
741
- runs.each do |r|
742
- # Make sure the restart file name includes the relative directory for
743
- # list runs
744
- reldir = r.relative_directory
745
- rdir = r.restart_dir
746
- #puts rdir[0...reldir.size] == reldir, rdir[0...reldir.size], reldir
747
- #raise ""
748
- if rdir
749
- r.restart_dir = reldir + '/' + rdir if not rdir[0...reldir.size] == reldir
750
- else
751
- r.restart_dir = reldir
752
- end
753
- Dir.chdir(r.directory){r.write_input_file}
754
- end
755
- np = runs[0].nprocs.split('x').map{|n| n.to_i}
756
- np[0] *= runs.size
757
- nprocs = np.map{|n| n.to_s}.join('x')
758
- @runner.nprocs = nprocs
759
- ls = ListSubmitter.new(@runner, nprocs, list_file, jid)
760
- script << ls.run_command
761
- end
762
- end
763
- return script
764
- end
765
-
766
- class ListSubmitter
767
- include CodeRunner::SYSTEM_MODULE
768
- @uses_mpi = true
769
- attr_reader :executable_location, :executable_name, :parameter_string
770
- attr_reader :job_identifier
771
- def initialize(runner, nprocs, list_file, jid)
772
- @executable_location = runner.executable_location
773
- @executable_name = runner.executable_name
774
- @parameter_string = list_file
775
- @job_identifier = jid
776
- @nprocs = nprocs
777
- end
778
- def rcp
779
- self.class.rcp
780
- end
781
- def self.rcp
782
- @rcp ||= CodeRunner::Run::RunClassPropertyFetcher.new(self)
783
- end
784
-
785
- end #class ListSubmitter
722
+ def self.modify_job_script(runner, runs_in, script)
723
+ if CODE_OPTIONS[:gs2] and CODE_OPTIONS[:gs2][:list]
724
+ if (list_size = CODE_OPTIONS[:gs2][:list]).kind_of? Integer
725
+ raise "The total number of runs must be a multiple of the list size!" unless runs_in.size % list_size == 0
726
+ pieces = runs_in.pieces(runs_in.size/list_size)
727
+ else
728
+ pieces = [runs_in]
729
+ end
730
+ script = ""
731
+ pieces.each do |runs|
732
+ #ep 'there is a list'
733
+ FileUtils.makedirs('job_lists')
734
+ jid = "#{runs[0].id}-#{runs[-1].id}"
735
+ list_file = "job_lists/gs2_list_#{jid}.list"
736
+ File.open(list_file,'w') do |file|
737
+ file.puts runs.size
738
+ file.puts runs.map{|r| "#{r.relative_directory}/#{r.run_name}"}.join("\n")
739
+ end
740
+ raise "runs must all have the same nprocs" unless runs.map{|r| r.nprocs}.uniq.size == 1
741
+ runs.each do |r|
742
+ # Make sure the restart file name includes the relative directory for
743
+ # list runs
744
+ reldir = r.relative_directory
745
+ rdir = r.restart_dir
746
+ #puts rdir[0...reldir.size] == reldir, rdir[0...reldir.size], reldir
747
+ #raise ""
748
+ if rdir
749
+ r.restart_dir = reldir + '/' + rdir if not rdir[0...reldir.size] == reldir
750
+ else
751
+ r.restart_dir = reldir
752
+ end
753
+ Dir.chdir(r.directory){r.write_input_file}
754
+ end
755
+ np = runs[0].nprocs.split('x').map{|n| n.to_i}
756
+ np[0] *= runs.size
757
+ nprocs = np.map{|n| n.to_s}.join('x')
758
+ @runner.nprocs = nprocs
759
+ ls = ListSubmitter.new(@runner, nprocs, list_file, jid)
760
+ script << ls.run_command
761
+ end
762
+ end
763
+ return script
764
+ end
765
+
766
+ class ListSubmitter
767
+ include CodeRunner::SYSTEM_MODULE
768
+ @uses_mpi = true
769
+ attr_reader :executable_location, :executable_name, :parameter_string
770
+ attr_reader :job_identifier
771
+ def initialize(runner, nprocs, list_file, jid)
772
+ @executable_location = runner.executable_location
773
+ @executable_name = runner.executable_name
774
+ @parameter_string = list_file
775
+ @job_identifier = jid
776
+ @nprocs = nprocs
777
+ end
778
+ def rcp
779
+ self.class.rcp
780
+ end
781
+ def self.rcp
782
+ @rcp ||= CodeRunner::Run::RunClassPropertyFetcher.new(self)
783
+ end
784
+
785
+ end #class ListSubmitter
786
786
 
787
787
  def recheck
788
- logf(:recheck)
789
- Dir.chdir(@directory) do
790
- logi('@runner.object_id', @runner.object_id)
791
- log('@runner.class', @runner.class)
792
- runner = @runner
793
- instance_variables.each{|var| instance_variable_set(var, nil) unless var == :@runner}
794
- begin File.delete(".code_runner_run_data") rescue Errno::ENOENT end
795
- begin File.delete("code_runner_results.rb") rescue Errno::ENOENT end
796
- logi(:@checked_converged, @checked_converged)
797
- logi('@runner.object_id after reset', @runner.object_id)
798
- log('@runner.class', @runner.class)
799
- process_directory
800
- end
788
+ logf(:recheck)
789
+ Dir.chdir(@directory) do
790
+ logi('@runner.object_id', @runner.object_id)
791
+ log('@runner.class', @runner.class)
792
+ #runner = @runner
793
+ instance_variables.each{|var| instance_variable_set(var, nil) unless var == :@runner}
794
+ begin File.delete(".code_runner_run_data") rescue Errno::ENOENT end
795
+ begin File.delete("code_runner_results.rb") rescue Errno::ENOENT end
796
+ logi(:@checked_converged, @checked_converged)
797
+ logi('@runner.object_id after reset', @runner.object_id)
798
+ log('@runner.class', @runner.class)
799
+ process_directory
800
+ end
801
801
  end
802
802
 
803
803
 
804
804
  def generate_input_file(&block)
805
- raise CRFatal("No Input Module File Given or Module Corrupted") unless methods.include? (:input_file_text)
806
- run_namelist_backwards_compatibility
807
- if @restart_id and (not @is_a_restart or @resubmit_id) # The second test checks that the restart function has not been called manually earlier (e.g. in Trinity), but we must check that it is not in fact a resubmitted run
808
- @runner.run_list[@restart_id].restart(self)
809
- elsif @save_for_restart and @save_for_restart.fortran_true? and (not @is_a_restart or @resubmit_id)
810
- @restart_dir = "nc"
811
- #if CODE_OPTIONS[:gs2] and CODE_OPTIONS[:gs2][:list]
812
- #FileUtils.makedirs "#{@runner.root_folder}/#@restart_dir"
813
- #else
814
- FileUtils.makedirs @restart_dir
815
- #end
816
- @restart_file = "#@run_name.nc"
817
-
818
- end
819
-
820
- # Let Gs2 know how much wall clock time is available. avail_cpu_time is a GS2 input parameter.
821
- @avail_cpu_time = @wall_mins * 60 if @wall_mins
822
-
823
- # Automatically set the number of nodes to be the maximum possible without parallelising over x, if the user has left the number of nodes unspecified.
824
-
825
- set_nprocs
826
-
827
-
828
- if block
829
- ##### Allow the user to define their own pre-flight checks and changes
830
- instance_eval(&block)
831
- else
832
- ######### Check for errors and inconsistencies
833
- ingen
834
- #########
805
+ raise CRFatal("No Input Module File Given or Module Corrupted") unless methods.include? (:input_file_text)
806
+ run_namelist_backwards_compatibility
807
+ if @restart_id and (not @is_a_restart or @resubmit_id) # The second test checks that the restart function has not been called manually earlier (e.g. in Trinity), but we must check that it is not in fact a resubmitted run
808
+ @runner.run_list[@restart_id].restart(self)
809
+ elsif @save_for_restart and @save_for_restart.fortran_true? and (not @is_a_restart or @resubmit_id)
810
+ @restart_dir = "nc"
811
+ #if CODE_OPTIONS[:gs2] and CODE_OPTIONS[:gs2][:list]
812
+ #FileUtils.makedirs "#{@runner.root_folder}/#@restart_dir"
813
+ #else
814
+ FileUtils.makedirs @restart_dir
815
+ #end
816
+ @restart_file = "#@run_name.nc"
817
+
818
+ end
819
+
820
+ # Let Gs2 know how much wall clock time is available. avail_cpu_time is a GS2 input parameter.
821
+ @avail_cpu_time = @wall_mins * 60 if @wall_mins
822
+
823
+ # Automatically set the number of nodes to be the maximum possible without parallelising over x, if the user has left the number of nodes unspecified.
824
+
825
+ set_nprocs
826
+
827
+
828
+ if block
829
+ ##### Allow the user to define their own pre-flight checks and changes
830
+ instance_eval(&block)
831
+ else
832
+ ######### Check for errors and inconsistencies
833
+ check_parameters
834
+ #########
835
835
  end
836
-
837
836
 
838
- write_input_file
837
+
838
+ write_input_file
839
+
840
+ ######### Generate a report using the ingen tool if possible
841
+ ingen unless block
842
+ ########
839
843
  end
840
844
 
841
845
  def write_input_file
842
- File.open(@run_name + ".in", 'w'){|file| file.puts input_file_text}
846
+ File.open(@run_name + ".in", 'w'){|file| file.puts input_file_text}
843
847
  end
844
848
 
845
849
  def set_nprocs
846
850
 
847
- if (nprocs_in = @nprocs) =~ /^x/
848
- max = max_nprocs_no_x
849
- nodes = 0
850
- @nprocs = "#{nodes}#{nprocs_in}"
851
- loop do
852
- nodes += 1
853
- @nprocs = "#{nodes}#{nprocs_in}"
854
- if actual_number_of_processors > max
855
- nodes -= 1
856
- @nprocs = "#{nodes}#{nprocs_in}"
857
- break
858
- end
859
- end
860
- end
851
+ if (nprocs_in = @nprocs) =~ /^x/
852
+ max = max_nprocs_no_x
853
+ nodes = 0
854
+ @nprocs = "#{nodes}#{nprocs_in}"
855
+ loop do
856
+ nodes += 1
857
+ @nprocs = "#{nodes}#{nprocs_in}"
858
+ if actual_number_of_processors > max
859
+ nodes -= 1
860
+ @nprocs = "#{nodes}#{nprocs_in}"
861
+ break
862
+ end
863
+ end
864
+ end
861
865
  end
862
866
 
863
867
  def actual_number_of_processors
864
868
  raise "Please specify the processor layout using the -n or (n:) option" unless @nprocs
865
- @nprocs.split('x').map{|n| n.to_i}.inject(1){|ntot, n| ntot*n}
869
+ @nprocs.split('x').map{|n| n.to_i}.inject(1){|ntot, n| ntot*n}
866
870
  end
867
871
 
868
872
  alias :anop :actual_number_of_processors
869
873
 
870
874
  def approximate_grid_size
871
- case @grid_option
872
- when "box"
873
- (2*(@nx-1)/3+1).to_i * (@naky||(@ny-1)/3+1).to_i * @ntheta * (2 * @ngauss + @ntheta/2).to_i * @negrid * 2 * @nspec
874
- else
875
- @ntheta * (2 * @ngauss + @ntheta/2).to_i * @negrid * 2 * @nspec
876
- end
875
+ case @grid_option
876
+ when "box"
877
+ (2*(@nx-1)/3+1).to_i * (@naky||(@ny-1)/3+1).to_i * @ntheta * (2 * @ngauss + @ntheta/2).to_i * @negrid * 2 * @nspec
878
+ else
879
+ @ntheta * (2 * @ngauss + @ntheta/2).to_i * @negrid * 2 * @nspec
880
+ end
877
881
  end
878
882
 
879
883
  alias :agridsze :approximate_grid_size
@@ -882,51 +886,51 @@ alias :agridsze :approximate_grid_size
882
886
  # can be parallelized (i.e. excluding ntheta)
883
887
  #
884
888
  def parallelizable_meshpoints
885
- approximate_grid_size / ntheta
889
+ approximate_grid_size / ntheta
886
890
  end
887
891
 
888
892
  # Gives a guess as to the maximum number of nodes which can be
889
893
  # can be utilized on the current system
890
894
  #
891
895
  def estimated_nodes
892
- parallelizable_meshpoints / max_ppn
896
+ parallelizable_meshpoints / max_ppn
893
897
  end
894
898
 
895
899
  alias :estnod :estimated_nodes
896
900
 
897
-
901
+
898
902
 
899
903
 
900
904
  def parameter_string
901
- return "#{@run_name}.in"
905
+ return "#{@run_name}.in"
902
906
  end
903
907
 
904
908
 
905
909
  def self.list_code_commands
906
- puts (methods - Run.methods).sort
910
+ puts (methods - Run.methods).sort
907
911
  end
908
912
 
909
913
  def self.add_variable_to_namelist(namelist, var, value)
910
- var = :stir_ + var if namelist == :stir
911
- super(namelist, var, value)
914
+ var = :stir_ + var if namelist == :stir
915
+ super(namelist, var, value)
912
916
  end
913
917
 
914
918
  def input_file_header
915
- run_namelist_backwards_compatibility
916
- <<EOF
919
+ run_namelist_backwards_compatibility
920
+ <<EOF
917
921
  !==============================================================================
918
- ! GS2 INPUT FILE automatically generated by CodeRunner
922
+ ! GS2 INPUT FILE automatically generated by CodeRunner
919
923
  !==============================================================================
920
924
  !
921
- ! GS2 is a gyrokinetic flux tube initial value turbulence code
925
+ ! GS2 is a gyrokinetic flux tube initial value turbulence code
922
926
  ! which can be used for fusion or astrophysical plasmas.
923
- !
924
- ! See http://gyrokinetics.sourceforge.net
925
927
  !
926
- ! CodeRunner is a framework for the automated running and analysis
927
- ! of large simulations.
928
+ ! See http://gyrokinetics.sourceforge.net
929
+ !
930
+ ! CodeRunner is a framework for the automated running and analysis
931
+ ! of large simulations.
928
932
  !
929
- ! See http://coderunner.sourceforge.net
933
+ ! See http://coderunner.sourceforge.net
930
934
  !
931
935
  ! Created on #{Time.now.to_s}
932
936
  ! by CodeRunner version #{CodeRunner::CODE_RUNNER_VERSION.to_s}
@@ -937,7 +941,7 @@ EOF
937
941
  end
938
942
 
939
943
  def self.defaults_file_header
940
- <<EOF1
944
+ <<EOF1
941
945
  ######################################################################
942
946
  # Automatically generated defaults file for GS2 CodeRunner module #
943
947
  # #
@@ -956,96 +960,96 @@ end
956
960
  # Customize this method from Run::FortranNamelist by saying when diagnostics are not switched on.
957
961
 
958
962
  #def namelist_text(namelist, enum = nil)
959
- #hash = rcp.namelists[namelist]
960
- #text = ""
961
- #ext = enum ? "_#{enum}" : ""
962
- #text << "!#{'='*30}\n!#{hash[:description]} #{enum} \n!#{'='*30}\n" if hash[:description]
963
- #text << "&#{namelist}#{ext}\n"
964
- #hash[:variables].each do |var, var_hash|
965
- #code_var = (var_hash[:code_name] or var)
966
- #cr_var = var+ext.to_sym
967
- ## ep cr_var, namelist
968
- #if send(cr_var) and (not var_hash[:should_include] or eval(var_hash[:should_include]))
969
- ## var_hash[:tests].each{|tst| eval(tst).test(send(cr_var), cr_var)}
970
- #if String::FORTRAN_BOOLS.include? send(cr_var) # var is a Fortran Bool, not really a string
971
- #output = send(cr_var).to_s
972
- #elsif (v = send(cr_var)).kind_of? Complex
973
- #output = "(#{v.real}, #{v.imag})"
974
- #else
975
- #output = send(cr_var).inspect
976
- #end
977
- #text << " #{code_var} = #{output} #{var_hash[:description] ? "! #{var_hash[:description]}": ""}\n"
978
- #elsif namelist == :gs2_diagnostics_knobs or namelist == :diagnostics
979
- #text << " ! #{code_var} not specified --- #{var_hash[:description]}\n"
980
- #end
981
- #end
982
- ## # end
983
- #text << "/\n\n"
984
- #text
963
+ #hash = rcp.namelists[namelist]
964
+ #text = ""
965
+ #ext = enum ? "_#{enum}" : ""
966
+ #text << "!#{'='*30}\n!#{hash[:description]} #{enum} \n!#{'='*30}\n" if hash[:description]
967
+ #text << "&#{namelist}#{ext}\n"
968
+ #hash[:variables].each do |var, var_hash|
969
+ #code_var = (var_hash[:code_name] or var)
970
+ #cr_var = var+ext.to_sym
971
+ ## ep cr_var, namelist
972
+ #if send(cr_var) and (not var_hash[:should_include] or eval(var_hash[:should_include]))
973
+ ## var_hash[:tests].each{|tst| eval(tst).test(send(cr_var), cr_var)}
974
+ #if String::FORTRAN_BOOLS.include? send(cr_var) # var is a Fortran Bool, not really a string
975
+ #output = send(cr_var).to_s
976
+ #elsif (v = send(cr_var)).kind_of? Complex
977
+ #output = "(#{v.real}, #{v.imag})"
978
+ #else
979
+ #output = send(cr_var).inspect
980
+ #end
981
+ #text << " #{code_var} = #{output} #{var_hash[:description] ? "! #{var_hash[:description]}": ""}\n"
982
+ #elsif namelist == :gs2_diagnostics_knobs or namelist == :diagnostics
983
+ #text << " ! #{code_var} not specified --- #{var_hash[:description]}\n"
984
+ #end
985
+ #end
986
+ ## # end
987
+ #text << "/\n\n"
988
+ #text
985
989
  #end
986
990
 
987
991
  @namelists_to_print_not_specified = [:gs2_diagnostics_knobs, :diagnostics]
988
992
 
989
993
  # def self.add_code_var
990
- # rcp.namelists.each do |namelist, hash|
991
- # hash[:variables].each do |var, var_hash|
992
- # p var
993
- # var_hash[:code_name] = var_hash[:gs2_name] if var_hash[:gs2_name]
994
- # end
995
- # end
996
- # save_namelists
994
+ # rcp.namelists.each do |namelist, hash|
995
+ # hash[:variables].each do |var, var_hash|
996
+ # p var
997
+ # var_hash[:code_name] = var_hash[:gs2_name] if var_hash[:gs2_name]
998
+ # end
999
+ # end
1000
+ # save_namelists
997
1001
  # end
998
-
999
-
1002
+
1003
+
1000
1004
  def update_physics_parameters_from_miller_input_file(file)
1001
- hash = self.class.parse_input_file(file)
1002
- hash[:parameters].each do |var, val|
1003
- set(var,val)
1004
- end
1005
- hash[:theta_grid_parameters].each do |var, val|
1006
- next if [:ntheta, :nperiod].include? var
1007
- set(var, val)
1008
- end
1009
- hash[:dist_fn_knobs].each do |var, val|
1010
- next unless [:g_exb].include? var
1011
- set(var, val)
1012
- end
1013
- hash[:theta_grid_eik_knobs].each do |var, val|
1014
- next unless [:s_hat_input, :beta_prime_input].include? var
1015
- set(var, val)
1016
- end
1017
-
1018
- hash[:species_parameters_2].each do |var, val|
1019
- #next unless [:s_hat_input, :beta_prime_input].include? var
1020
- set((var.to_s + '_2').to_sym, val)
1021
- end
1022
- hash[:species_parameters_1].each do |var, val|
1023
- #next unless [:s_hat_input, :beta_prime_input].include? var
1024
- set((var.to_s + '_1').to_sym, val)
1025
- end
1005
+ hash = self.class.parse_input_file(file)
1006
+ hash[:parameters].each do |var, val|
1007
+ set(var,val)
1008
+ end
1009
+ hash[:theta_grid_parameters].each do |var, val|
1010
+ next if [:ntheta, :nperiod].include? var
1011
+ set(var, val)
1012
+ end
1013
+ hash[:dist_fn_knobs].each do |var, val|
1014
+ next unless [:g_exb].include? var
1015
+ set(var, val)
1016
+ end
1017
+ hash[:theta_grid_eik_knobs].each do |var, val|
1018
+ next unless [:s_hat_input, :beta_prime_input].include? var
1019
+ set(var, val)
1020
+ end
1021
+
1022
+ hash[:species_parameters_2].each do |var, val|
1023
+ #next unless [:s_hat_input, :beta_prime_input].include? var
1024
+ set((var.to_s + '_2').to_sym, val)
1025
+ end
1026
+ hash[:species_parameters_1].each do |var, val|
1027
+ #next unless [:s_hat_input, :beta_prime_input].include? var
1028
+ set((var.to_s + '_1').to_sym, val)
1029
+ end
1026
1030
  end
1027
1031
 
1028
1032
 
1029
1033
 
1030
1034
  def renew_info_file
1031
- Dir.chdir(@directory){make_info_file("#@run_name.in")}
1035
+ Dir.chdir(@directory){make_info_file("#@run_name.in")}
1032
1036
  end
1033
-
1037
+
1034
1038
  # This method overrides a method defined in heuristic_run_methods.rb in the CodeRunner source. It is called when CodeRunner cannot find any of its own files in the folder being analysed. It takes a GS2 input file and generates a CodeRunner info file. This means that GS2 runs which were not run using CodeRunner can nonetheless be analysed by it. In order for it to be called the -H flag must be specified on the command line.
1035
-
1039
+
1036
1040
  def run_heuristic_analysis
1037
- ep 'run_heuristic_analysis', Dir.pwd
1038
- infiles = Dir.entries.grep(/^[^\.].*\.in$/)
1039
- ep infiles
1040
- raise CRMild.new('No input file') unless infiles[0]
1041
- raise CRError.new("More than one input file in this directory: \n\t#{infiles}") if infiles.size > 1
1042
- input_file = infiles[0]
1043
- ep 'asdf'
1044
- @nprocs ||= "1"
1045
- @executable ||= "/dev/null"
1046
- make_info_file(input_file, false)
1041
+ ep 'run_heuristic_analysis', Dir.pwd
1042
+ infiles = Dir.entries.grep(/^[^\.].*\.in$/)
1043
+ ep infiles
1044
+ raise CRMild.new('No input file') unless infiles[0]
1045
+ raise CRError.new("More than one input file in this directory: \n\t#{infiles}") if infiles.size > 1
1046
+ input_file = infiles[0]
1047
+ ep 'asdf'
1048
+ @nprocs ||= "1"
1049
+ @executable ||= "/dev/null"
1050
+ make_info_file(input_file, false)
1047
1051
  end
1048
-
1052
+
1049
1053
  @source_code_subfolders = ['utils', 'geo', 'diagnostics']
1050
1054
 
1051
1055
  attr_accessor :iphi00, :saturation_time #Necessary for back. comp. due to an old bug
@@ -1053,122 +1057,122 @@ attr_accessor :iphi00, :saturation_time #Necessary for back. comp. due to an old
1053
1057
  folder = File.dirname(File.expand_path(__FILE__)) # i.e. the directory this file is in
1054
1058
 
1055
1059
  SPECIES_DEPENDENT_NAMELISTS = eval(File.read(folder + '/species_dependent_namelists.rb'), binding, folder + '/species_dependent_namelists.rb')
1056
- #
1060
+ #
1057
1061
  SPECIES_DEPENDENT_VARIABLES_WITH_HELP = SPECIES_DEPENDENT_NAMELISTS.values.inject({}) do |hash, namelist_hash|
1058
- namelist_hash[:variables].each do |var, var_hash|
1059
- hash[var] = var_hash[:help]
1060
- end
1061
- hash
1062
+ namelist_hash[:variables].each do |var, var_hash|
1063
+ hash[var] = var_hash[:help]
1064
+ end
1065
+ hash
1062
1066
  end
1063
1067
 
1064
1068
  SPECIES_DEPENDENT_VARIABLES = SPECIES_DEPENDENT_VARIABLES_WITH_HELP.keys
1065
1069
  SPECIES_DEPENDENT_VARIABLES.each{|var| attr_accessor var} # for backwards compatibility
1066
1070
 
1067
- ['i', 'e'].each do |n|
1068
- SPECIES_DEPENDENT_VARIABLES_WITH_HELP.each do |name, help|
1069
- attr_accessor name + "_#{n}".to_sym #for backwards compatibility
1070
- end
1071
+ ['i', 'e'].each do |n|
1072
+ SPECIES_DEPENDENT_VARIABLES_WITH_HELP.each do |name, help|
1073
+ attr_accessor name + "_#{n}".to_sym #for backwards compatibility
1074
+ end
1071
1075
  end
1072
1076
 
1073
1077
  old_vars = %w[
1074
- :TiTe
1075
- :Rmaj
1076
- :R_geo
1077
- :invLp_input
1078
- :D_hypervisc
1079
- :D_hyperres
1080
- :D_hyper
1081
- :C_par
1082
- :C_perp
1078
+ :TiTe
1079
+ :Rmaj
1080
+ :R_geo
1081
+ :invLp_input
1082
+ :D_hypervisc
1083
+ :D_hyperres
1084
+ :D_hyper
1085
+ :C_par
1086
+ :C_perp
1083
1087
  ].map{|n| n.to_s.sub(/^:/, '').to_sym}
1084
1088
 
1085
1089
  old_vars.each do |var|
1086
- alias_method(var, var.to_s.downcase.to_sym)
1087
- alias_method("#{var}=".to_sym, "#{var.downcase}=".to_sym)
1090
+ alias_method(var, var.to_s.downcase.to_sym)
1091
+ alias_method("#{var}=".to_sym, "#{var.downcase}=".to_sym)
1088
1092
  end
1089
1093
 
1090
1094
 
1091
1095
 
1092
1096
 
1093
1097
  def run_namelist_backwards_compatibility
1094
- SPECIES_DEPENDENT_VARIABLES.each do |var|
1095
- set(var + "_1".to_sym, (send(var + "_1".to_sym) or send(var + "_i".to_sym) or send(var)))
1096
- set(var + "_2".to_sym, (send(var + "_2".to_sym) or send(var + "_e".to_sym)))
1097
- end
1098
+ SPECIES_DEPENDENT_VARIABLES.each do |var|
1099
+ set(var + "_1".to_sym, (send(var + "_1".to_sym) or send(var + "_i".to_sym) or send(var)))
1100
+ set(var + "_2".to_sym, (send(var + "_2".to_sym) or send(var + "_e".to_sym)))
1101
+ end
1098
1102
  end
1099
1103
 
1100
1104
 
1101
1105
  def stop
1102
- `touch #@directory/#@run_name.stop`
1106
+ `touch #@directory/#@run_name.stop`
1103
1107
  end
1104
1108
 
1105
1109
  def vim_output
1106
- system "vim -Ro #{output_file} #{error_file} #@directory/#@run_name.error #@directory/#@run_name.out "
1107
- end
1108
- alias :vo :vim_output
1110
+ system "vim -Ro #{output_file} #{error_file} #@directory/#@run_name.error #@directory/#@run_name.out "
1111
+ end
1112
+ alias :vo :vim_output
1109
1113
  def vim_stdout
1110
- system "vim -Ro #{output_file} "
1111
- end
1112
- alias :vo1 :vim_stdout
1113
- def plot_efit_file
1114
- Dir.chdir(@directory) do
1115
- text = File.read(@eqfile)
1116
- text_lines = text.split("\n")
1117
- first_line = text_lines[0].split(/\s+/)
1118
- second_line = text_lines[1].split(/\s+/)
1119
- nr = first_line[-2].to_i
1120
- nz = first_line[-1].to_i
1121
- rwidth = second_line[1].to_f
1122
- zwidth = second_line[2].to_f
1123
- rmag = second_line[3].to_f
1124
- nlines = (nr.to_f/5.0).ceil
1125
- nlines_psi = ((nr*nz).to_f/5.0).ceil
1126
- start = 5
1127
- f = text_lines[start...(start+=nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1128
- pres = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1129
- dumy = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1130
- ffprime = text_lines[(start)...(start+= nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1131
- psi = text_lines[(start)...(start += nlines_psi)].join(" ")
1132
- q = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1133
- nbound = text_lines[start...start+=1].join(" ").to_i
1134
- rz = text_lines[(start)...(start += nbound*2)].join(" ").split(/\s+/)
1135
- rz.shift
1136
- rbound, zbound, dummy = rz.inject([[], [], true]){|arr,val| arr[2] ? [arr[0].push(val), arr[1], false] : [arr[0], arr[1].push(val), true]}
1137
- #rbound.shift
1138
-
1139
- psi = psi.split(/\s+/)
1140
- psi.shift
1141
- psi.map!{|v| v.to_f}
1142
- psi_arr = SparseTensor.new(2)
1143
- k = 0
1144
- for i in 0...nz
1145
- for j in 0...nr
1146
- psi_arr[j,i] = psi[k]
1147
- k+=1
1148
- end
1149
- end
1150
- kit = GraphKit.quick_create([((0...nr).to_a.to_gslv - nr/2 - 1 )/(nr-1)*rwidth+rmag, ((0...nz).to_a.to_gslv-nz/2 + 1)/(nz-1) * zwidth, psi_arr], [rbound, zbound, rbound.map{|r| 0}])
1151
- kit.gp.contour = ""
1152
- kit.gp.view = "map"
1153
- #kit.gp.nosurface = ""
1154
- kit.gp.cntrparam = "levels 20"
1155
- kit.data[0].gp.with = 'l'
1156
- kit.data[1].gp.with = 'l lw 2 nocontours'
1157
- kit.gnuplot
1158
-
1159
- kit2 = GraphKit.quick_create([pres/pres.max],[f/f.max],[q/q.max])
1160
- kit2.data[0].title = 'Pressure/Max Pressure'
1161
- kit2.data[1].title = 'Poloidal current function/Max poloidal current function'
1162
- kit2.data[2].title = 'Safety factor/Max Safety factor'
1163
- kit2.gnuplot
1164
-
1165
-
1166
-
1167
- #p ['f', f, 'p', pres, 'ffprime', ffprime, 'nlines', nlines, 'psi', psi, 'q', q, 'nbound', nbound, 'rbound', rbound, 'zbound', zbound]
1168
-
1169
-
1170
- end
1171
- end
1114
+ system "vim -Ro #{output_file} "
1115
+ end
1116
+ alias :vo1 :vim_stdout
1117
+ def plot_efit_file
1118
+ Dir.chdir(@directory) do
1119
+ text = File.read(@eqfile)
1120
+ text_lines = text.split("\n")
1121
+ first_line = text_lines[0].split(/\s+/)
1122
+ second_line = text_lines[1].split(/\s+/)
1123
+ nr = first_line[-2].to_i
1124
+ nz = first_line[-1].to_i
1125
+ rwidth = second_line[1].to_f
1126
+ zwidth = second_line[2].to_f
1127
+ rmag = second_line[3].to_f
1128
+ nlines = (nr.to_f/5.0).ceil
1129
+ nlines_psi = ((nr*nz).to_f/5.0).ceil
1130
+ start = 5
1131
+ f = text_lines[start...(start+=nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1132
+ pres = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1133
+ _ = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1134
+ _ffprime = text_lines[(start)...(start+= nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1135
+ psi = text_lines[(start)...(start += nlines_psi)].join(" ")
1136
+ q = text_lines[(start)...(start += nlines)].join(" ").split(nil).map{|s| s.to_f}.to_gslv
1137
+ nbound = text_lines[start...start+=1].join(" ").to_i
1138
+ rz = text_lines[(start)...(start += nbound*2)].join(" ").split(/\s+/)
1139
+ rz.shift
1140
+ rbound, zbound, _ = rz.inject([[], [], true]){|arr,val| arr[2] ? [arr[0].push(val), arr[1], false] : [arr[0], arr[1].push(val), true]}
1141
+ #rbound.shift
1142
+
1143
+ psi = psi.split(/\s+/)
1144
+ psi.shift
1145
+ psi.map!{|v| v.to_f}
1146
+ psi_arr = SparseTensor.new(2)
1147
+ k = 0
1148
+ for i in 0...nz
1149
+ for j in 0...nr
1150
+ psi_arr[j,i] = psi[k]
1151
+ k+=1
1152
+ end
1153
+ end
1154
+ kit = GraphKit.quick_create([((0...nr).to_a.to_gslv - nr/2 - 1 )/(nr-1)*rwidth+rmag, ((0...nz).to_a.to_gslv-nz/2 + 1)/(nz-1) * zwidth, psi_arr], [rbound, zbound, rbound.map{|r| 0}])
1155
+ kit.gp.contour = ""
1156
+ kit.gp.view = "map"
1157
+ #kit.gp.nosurface = ""
1158
+ kit.gp.cntrparam = "levels 20"
1159
+ kit.data[0].gp.with = 'l'
1160
+ kit.data[1].gp.with = 'l lw 2 nocontours'
1161
+ kit.gnuplot
1162
+
1163
+ kit2 = GraphKit.quick_create([pres/pres.max],[f/f.max],[q/q.max])
1164
+ kit2.data[0].title = 'Pressure/Max Pressure'
1165
+ kit2.data[1].title = 'Poloidal current function/Max poloidal current function'
1166
+ kit2.data[2].title = 'Safety factor/Max Safety factor'
1167
+ kit2.gnuplot
1168
+
1169
+
1170
+
1171
+ #p ['f', f, 'p', pres, 'ffprime', ffprime, 'nlines', nlines, 'psi', psi, 'q', q, 'nbound', nbound, 'rbound', rbound, 'zbound', zbound]
1172
+
1173
+
1174
+ end
1175
+ end
1172
1176
 
1173
1177
  #This function will handle running the correlation analysis and writing the results to a NetCDF file.
1174
1178
  #Cases need to be handled differently since perp, par and full are just subsets of the full correlation function
@@ -1188,14 +1192,14 @@ end
1188
1192
  # why the perp/par/full splitting is implemented, allowing one dimension to be taken out essentially.
1189
1193
  def correlation_analysis(options={})
1190
1194
 
1191
- #Sanity checks:
1192
- #Cannot only have one bin since require difference between bins for index calculation
1195
+ #Sanity checks:
1196
+ #Cannot only have one bin since require difference between bins for index calculation
1193
1197
  if options[:nbins_array].include?1
1194
1198
  raise('Cannot have only one bin in nbins_array. Minuimum is two.')
1195
1199
  end
1196
1200
  #Thetamin shouldn't be equal to thetamax to avoid possibili
1197
1201
  #
1198
-
1202
+
1199
1203
  case options[:correlation_type]
1200
1204
  when 'perp', 'par', 'full'
1201
1205
  gsl_tensor = field_correlation_gsl_tensor(options)
@@ -1240,7 +1244,7 @@ end
1240
1244
  file = NumRu::NetCDF.create(@run_name + "_correlation_analysis_#{options[:correlation_type]}.nc")
1241
1245
  ydim = file.def_dim('x',shape[0])
1242
1246
  xdim = file.def_dim('y',shape[1])
1243
- zdim = file.def_dim('z',shape[2])
1247
+ zdim = file.def_dim('z',shape[2])
1244
1248
  tdim = file.def_dim('t',shape[3])
1245
1249
  end
1246
1250
  file.redef
@@ -1255,9 +1259,9 @@ end
1255
1259
  end
1256
1260
  end
1257
1261
 
1258
- def input_file_extension
1259
- '.in'
1260
- end
1262
+ def input_file_extension
1263
+ '.in'
1264
+ end
1261
1265
 
1262
1266
  #This function will interpolate and output either phi or density at the outboard midplane
1263
1267
  #on a 40x40 grid appropriate to analyse as experimental data. It called as a run_command
@@ -1304,8 +1308,8 @@ end
1304
1308
  raise 'Need to specify amin AND v_ref options when specifying omega to move to LAB frame!'
1305
1309
  end
1306
1310
  if options[:output_box_size] and options[:output_box_size].kind_of?Array
1307
- r_box_size = options[:output_box_size][0]
1308
- z_box_size = options[:output_box_size][1]
1311
+ _r_box_size = options[:output_box_size][0] # EGH These variables are marked as unused... are they used anywhere?
1312
+ _z_box_size = options[:output_box_size][1]
1309
1313
  #else
1310
1314
  # raise 'Option output_box_size must be specified (in units of amin) and must be an Array.'
1311
1315
  end
@@ -1321,7 +1325,7 @@ end
1321
1325
  options[:t_index] = t_index_beg
1322
1326
  kit = field_real_space_poloidal_plane_graphkit(options)
1323
1327
  x = kit.data[0].x.data
1324
- y = kit.data[0].y.data
1328
+ _y = kit.data[0].y.data
1325
1329
  z = kit.data[0].z.data
1326
1330
 
1327
1331
  #Set up NetCDf file
@@ -1340,13 +1344,13 @@ end
1340
1344
 
1341
1345
  #Loop over time, load field as function of space at each time index, write to file
1342
1346
  for i in t_index_beg...t_index_end #inclusive of end
1343
- Terminal.erewind(1) #go back one line in terminal
1344
- eputs sprintf("Writing time index = %d of %d#{Terminal::CLEAR_LINE}", i, t_index_end-t_index_beg+1) #clear line and print time index
1347
+ Terminal.erewind(1) #go back one line in terminal
1348
+ eputs sprintf("Writing time index = %d of %d#{Terminal::CLEAR_LINE}", i, t_index_end-t_index_beg+1) #clear line and print time index
1345
1349
  options[:t_index] = i
1346
1350
  #Need to test whether omega is specified to change torphi at each time step. If not, do nothing since torphi must be
1347
1351
  #set to a value to call the graphkit below
1348
1352
  if options[:omega]
1349
- options[:torphi] = omega * (gsl_vector(:t)[i] - gsl_vector(:t)[0]) * (amin/v_ref)
1353
+ options[:torphi] = omega * (gsl_vector(:t)[i] - gsl_vector(:t)[0]) * (amin/v_ref)
1350
1354
  end
1351
1355
  kit = field_real_space_poloidal_plane_graphkit(options)
1352
1356
  t_var.put(gsl_vector(:t)[i], 'index'=>[i-t_index_beg]) #Write time to unlimited time NetCDF variable
@@ -1355,7 +1359,7 @@ end
1355
1359
  file.close
1356
1360
 
1357
1361
  #Ignore this until interpolation issue is sorted
1358
- =begin
1362
+ =begin
1359
1363
  #**************************
1360
1364
  # Set up new regular grid *
1361
1365
  #**************************
@@ -1372,14 +1376,14 @@ end
1372
1376
  z_reg[i,j] = z_vec_reg[j]
1373
1377
  end
1374
1378
  end
1375
-
1379
+
1376
1380
  #************************************************
1377
1381
  # Find the field at every point on regular grid *
1378
1382
  #************************************************
1379
1383
  #To evaluate field on a regular grid given the field on an irregular grid, need to interpolate. The rubygem
1380
- #gsl_extras contains an interpolation routine called ScatterInterp which does exactly this based on a
1384
+ #gsl_extras contains an interpolation routine called ScatterInterp which does exactly this based on a
1381
1385
  #'Radial Basis Function' method.
1382
-
1386
+
1383
1387
  #Have R, Z, and field on an irregular grid in the form of matrices. ScatterInterp only takes in GSL vectors
1384
1388
  #so simply convert these matrices to vectors (of size row*col) since the order of the pts don't matter.
1385
1389
  x_vec = GSL::Vector.alloc(x.shape[0]*x.shape[1])
@@ -1402,15 +1406,15 @@ end
1402
1406
  for j in 0...z_vec_reg.size
1403
1407
  field_reg[i,j] = interp.eval(x_vec_reg[i], z_vec_reg[j])
1404
1408
  end
1405
- end
1409
+ end
1406
1410
 
1407
- kit = GraphKit.quick_create([x_vec_reg, z_vec_reg, field_reg])
1408
- #kit2 = GraphKit.quick_create([x_vec, z_vec, field_vec])
1411
+ kit = GraphKit.quick_create([x_vec_reg, z_vec_reg, field_reg])
1412
+ #kit2 = GraphKit.quick_create([x_vec, z_vec, field_vec])
1409
1413
  =end
1410
1414
 
1411
1415
  end
1412
- end # class GS2
1413
- # For backwards compatibility
1416
+ end # class GS2
1417
+ # For backwards compatibility
1414
1418
 
1415
1419
  Gs2BoxNtRun = Gs2CycloneRun = Gs2BoxCollisionalRun = Gs2Jet42982Run = Gs2ArtunRun = Gs2LinskerRun = Gs2BarnesLinskerRun = Gs2BoxMovieRun = Gs2Run = Gs2
1416
1420
  end # class CodeRunner
@@ -1420,56 +1424,56 @@ end # class CodeRunner
1420
1424
 
1421
1425
  class Float
1422
1426
  def <=>(other) # necessary because of netcdf quirks
1423
-
1424
- d = (self - other)
1425
- if d.abs / (self.abs + 1) < 1e-10
1426
- return 0
1427
- else
1428
- return (d / d.abs).to_i
1429
- end
1427
+
1428
+ d = (self - other)
1429
+ if d.abs / (self.abs + 1) < 1e-10
1430
+ return 0
1431
+ else
1432
+ return (d / d.abs).to_i
1433
+ end
1430
1434
  end
1431
1435
  def ==(other)
1432
- return false unless other.kind_of? Numeric
1433
- return (self - other).abs < 1e-14
1436
+ return false unless other.kind_of? Numeric
1437
+ return (self - other).abs < 1e-14
1434
1438
  end
1435
- end
1436
-
1439
+ end
1440
+
1437
1441
  class Hash
1438
-
1439
- # puts self
1440
-
1441
- def convert_to_index(run, *names)
1442
- if self[:strongest_non_zonal_mode]
1443
- ky_element, kx_element = run.gsl_matrix('spectrum_over_ky_over_kx', no_zonal: true).max_index
1444
- p self[:kx_index] = kx_element + 1
1445
- p self[:ky_index] = ky_element + 1
1446
- self[:strongest_non_zonal_mode] = false
1447
- end
1448
- raise "No names specified" if names.size == 0
1449
-
1450
-
1451
- # ep run
1452
- names.each do |name|
1453
- if name == :kx
1454
- if lkx = self[:lagrangian_kx]
1455
- self[:lagrangian_kx_index] = list(:kx).key(lkx)
1456
- end
1457
- if lkxi = self[:lagrangian_kx_index] ||= self[:lkx_index]
1458
- self[:kx_index] = run.eulerian_kx_index(kx_index: lkxi, ky_index: self[:ky_index], t_index: self[:t_index])
1459
- end
1460
- end
1461
-
1462
- #ep 'name', name
1463
- self[:ky_index] = 1 if name == :ky and run.grid_option == "single"
1464
- self[:kx_index] = 1 if name == :kx and run.grid_option == "single"
1465
- # ep run.list(name)
1466
- self[name + :_index] ||= run.list(name).key(self[name]) || (raise ("#{name} not specified"))
1467
- end
1468
-
1469
- end
1470
- def setup_time_window
1471
- self[:t_index_window] ||= [self[:t_index],self[:t_index]] if self[:t_index]
1472
- self[:begin_element], self[:end_element] = (self[:t_index_window] ? self[:t_index_window].map{|ind| ind -1} : [0, -1])
1473
- end
1442
+
1443
+ # puts self
1444
+
1445
+ def convert_to_index(run, *names)
1446
+ if self[:strongest_non_zonal_mode]
1447
+ ky_element, kx_element = run.gsl_matrix('spectrum_over_ky_over_kx', no_zonal: true).max_index
1448
+ p self[:kx_index] = kx_element + 1
1449
+ p self[:ky_index] = ky_element + 1
1450
+ self[:strongest_non_zonal_mode] = false
1451
+ end
1452
+ raise "No names specified" if names.size == 0
1453
+
1454
+
1455
+ # ep run
1456
+ names.each do |name|
1457
+ if name == :kx
1458
+ if lkx = self[:lagrangian_kx]
1459
+ self[:lagrangian_kx_index] = list(:kx).key(lkx)
1460
+ end
1461
+ if lkxi = self[:lagrangian_kx_index] ||= self[:lkx_index]
1462
+ self[:kx_index] = run.eulerian_kx_index(kx_index: lkxi, ky_index: self[:ky_index], t_index: self[:t_index])
1463
+ end
1464
+ end
1465
+
1466
+ #ep 'name', name
1467
+ self[:ky_index] = 1 if name == :ky and run.grid_option == "single"
1468
+ self[:kx_index] = 1 if name == :kx and run.grid_option == "single"
1469
+ # ep run.list(name)
1470
+ self[name + :_index] ||= run.list(name).key(self[name]) || (raise ("#{name} not specified"))
1471
+ end
1472
+
1473
+ end
1474
+ def setup_time_window
1475
+ self[:t_index_window] ||= [self[:t_index],self[:t_index]] if self[:t_index]
1476
+ self[:begin_element], self[:end_element] = (self[:t_index_window] ? self[:t_index_window].map{|ind| ind - 1} : [0, -1])
1477
+ end
1474
1478
 
1475
1479
  end