gs2crmod 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.md +4 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +56 -0
  7. data/VERSION +1 -0
  8. data/ext/extconf.rb +9 -0
  9. data/ext/gs2crmod_ext.c +366 -0
  10. data/gs2crmod.gemspec +98 -0
  11. data/include/gs2crmod_ext.h +58 -0
  12. data/lib/gs2crmod/astrogk/astrogk.rb +201 -0
  13. data/lib/gs2crmod/astrogk/calculations.rb +57 -0
  14. data/lib/gs2crmod/astrogk/check_convergence.rb +7 -0
  15. data/lib/gs2crmod/astrogk/deleted_variables.rb +76 -0
  16. data/lib/gs2crmod/astrogk/graphs.rb +13 -0
  17. data/lib/gs2crmod/astrogk/gsl_data.rb +13 -0
  18. data/lib/gs2crmod/astrogk/gsl_tools.rb +182 -0
  19. data/lib/gs2crmod/astrogk/ingen.rb +18 -0
  20. data/lib/gs2crmod/astrogk/input_file_tools.rb +7 -0
  21. data/lib/gs2crmod/astrogk/namelist_tools.rb +14 -0
  22. data/lib/gs2crmod/astrogk/namelists.rb +2800 -0
  23. data/lib/gs2crmod/astrogk/properties.rb +17 -0
  24. data/lib/gs2crmod/astrogk/species_dependent_namelists.rb +228 -0
  25. data/lib/gs2crmod/astrogk/test_gs2.rb +231 -0
  26. data/lib/gs2crmod/astrogk.rb +200 -0
  27. data/lib/gs2crmod/calculations.rb +780 -0
  28. data/lib/gs2crmod/check_convergence.rb +179 -0
  29. data/lib/gs2crmod/deleted_variables.rb +916 -0
  30. data/lib/gs2crmod/graphs.rb +1899 -0
  31. data/lib/gs2crmod/graphs_rdoc.rb +556 -0
  32. data/lib/gs2crmod/gs2.rb +1143 -0
  33. data/lib/gs2crmod/gsl_data.rb +1181 -0
  34. data/lib/gs2crmod/gsl_data_3d.rb +705 -0
  35. data/lib/gs2crmod/gsl_tools.rb +187 -0
  36. data/lib/gs2crmod/ingen.rb +218 -0
  37. data/lib/gs2crmod/namelists.rb +5142 -0
  38. data/lib/gs2crmod/properties.rb +22 -0
  39. data/lib/gs2crmod/species_dependent_namelists.rb +228 -0
  40. data/lib/gs2crmod/test_gs2.rb +231 -0
  41. data/lib/gs2crmod.rb +2 -0
  42. data/lib/gs2crmod_extension.rb +1 -0
  43. data/test/helper.rb +18 -0
  44. data/test/test_gs2crmod.rb +7 -0
  45. metadata +176 -0
@@ -0,0 +1,780 @@
1
+ ##########################################
2
+ # Calculations for GS2 Code Runner Module
3
+ #
4
+ # This module contains any methods that
5
+ # begin with the word calculate.
6
+ #
7
+ # These methods calculate results and
8
+ # quantities that are not directly
9
+ # obtainable from the GS2 output files.
10
+ #
11
+ ##########################################
12
+
13
+
14
+ class CodeRunner
15
+ class Gs2
16
+
17
+
18
+
19
+ def calculate_time_averaged_fluxes
20
+ eputs 'Calculating time averaged fluxes'
21
+ calculate_saturation_time_index unless @saturation_time_index
22
+ return unless FileTest.exist?("#@run_name.out.nc")
23
+ @hflux_tot_stav = saturated_time_average('hflux_tot_over_time', {})
24
+ @hflux_tot_stav_error = saturated_time_average_error('hflux_tot_over_time', {})
25
+ @phi2_tot_stav = saturated_time_average('phi2tot_over_time', {})
26
+ #@par_mom_flux_stav = saturated_time_average('par_mom_flux_over_time', {}) rescue nil
27
+ #@perp_mom_flux_stav = saturated_time_average('perp_mom_flux_over_time', {}) rescue nil
28
+ @es_mom_flux_stav = {}
29
+ @es_heat_flux_stav = {}
30
+ @es_mom_flux_stav_error = {}
31
+ @es_heat_flux_stav_error = {}
32
+
33
+ @nspec.times do |i|
34
+ species_index = i + 1
35
+ @es_mom_flux_stav[species_index] = saturated_time_average('es_mom_flux_over_time', {species_index: species_index})
36
+ @es_heat_flux_stav[species_index] = saturated_time_average('es_heat_flux_over_time', {species_index: species_index})
37
+ @es_mom_flux_stav_error[species_index] = saturated_time_average_error('es_mom_flux_over_time', {species_index: species_index})
38
+ @es_heat_flux_stav_error[species_index] = saturated_time_average_error('es_heat_flux_over_time', {species_index: species_index})
39
+ end
40
+ # ep @es_mom_flux_stav, @es_heat_flux_stav
41
+ end
42
+
43
+ alias :ctaf :calculate_time_averaged_fluxes
44
+
45
+ def saturated_time_average(name, options)
46
+ # calculate_saturation_time_index unless @saturation_time_index
47
+ # p 'sat', @saturation_time_index, 'max', list(:t).keys.max
48
+ raise "saturation_time_index not calculated for #@run_name" unless @saturation_time_index
49
+ options[:t_index_window] = [@saturation_time_index, list(:t).keys.max - 1]
50
+ #ep gsl_vector(name, {}).size
51
+ #ep name, options
52
+ begin
53
+ vec = gsl_vector(name, options)
54
+ rescue GSL::ERROR::EINVAL
55
+ # IF the vector doesn't have enough values for each timestep (due to run aborting early?), this error will be thrown.
56
+ options[:t_index_window] = [@saturation_time_index, gsl_vector(name, {}).size]
57
+ retry
58
+ rescue NoMethodError
59
+ eputs "Warning: could not calculate #{name} saturated time average"
60
+ return nil
61
+ end
62
+
63
+
64
+ tvec = gsl_vector('t', options)
65
+
66
+
67
+ dt = tvec.subvector(1, tvec.size - 1) - tvec.subvector(0, tvec.size - 1)
68
+ trapezium = (vec.subvector(1, tvec.size - 1) + vec.subvector(0, tvec.size - 1)) / 2.0
69
+ return trapezium.mul(dt).sum / dt.sum
70
+ end
71
+
72
+ def saturated_time_average_error(name, options)
73
+ # calculate_saturation_time_index unless @saturation_time_index
74
+ options[:t_index_window] = [@saturation_time_index, list(:t).keys.max]
75
+ begin
76
+ vec = gsl_vector(name, options)
77
+ tavg = GSL::Vector.alloc(vec.size)
78
+ vec.size.times.each{|i| tavg[i] = vec.subvector(i+1).mean}
79
+ rescue NoMethodError
80
+ eputs "Warning: could not calculate #{name} saturated_time_average_error"
81
+ return nil
82
+ end
83
+ # tavg = 0.0; i = 0
84
+
85
+ # tavg_vec = vec.collect{|val| tavg += val; tavg = tavg / (i+=1); tavg}
86
+ # ind = GSL::Vector.indgen(vec.size)
87
+ # i = 0
88
+ # begin
89
+ # fit = GSL::Fit::linear(ind.subvector(i, ind.size - i) , vec.subvector(i, ind.size - i))
90
+ # # p fit[1].abs - 100.0 * fit[4].abs
91
+ # i += 1
92
+ # (eputs "Not Saturated"; break) if i > vec.size * 0.9
93
+ # end while (fit[1].abs - Math.sqrt(fit[4].abs)) > 0
94
+ # p fit
95
+ # fit_vec = ind * fit[1] + fit[0]
96
+ # # p tavg.size
97
+ # # GraphKit.autocreate({x: {data: gsl_vector(name, {})}})
98
+ # (GraphKit.autocreate({x: {data: tavg}}) + GraphKit.autocreate({x: {data: vec}}) + GraphKit.autocreate({x: {data: fit_vec}})).gnuplot
99
+ return tavg.sd
100
+ end
101
+
102
+
103
+ # I.e. the time at which the primary modes are saturated and the fluxes settle around a long term average.
104
+
105
+ def calculate_saturation_time_index(show_graph = false)
106
+
107
+ eprint "Checking for saturation..."
108
+
109
+ #hflux = gsl_vector('hflux_tot_over_time', {})
110
+ hflux = gsl_vector('phi2tot_over_time', {})
111
+
112
+ #eputs 'got hflux'
113
+ #ep 'hflux', hflux
114
+
115
+ #Check if it's decayed to 0
116
+ if hflux[-1] < 1.0e-10
117
+ for i in 1..hflux.size
118
+ # raise "negative heat flux: #{hflux[-i]} " if hflux[-i] < 0
119
+ (break) unless hflux[- i] < 1.0e-10
120
+ end
121
+ if i > hflux.size * 1.0/10.0 #i.e if was 0 for more than a tenth of the time
122
+ @saturated = true
123
+ @saturation_time_index = hflux.size - i + 1
124
+ eputs "saturation time = #{list(:t)[@saturation_time_index]}"
125
+ GraphKit.quick_create([gsl_vector('t',{}), hflux]).gnuplot(log_axis: 'y') if show_graph
126
+ return
127
+ end
128
+ end
129
+
130
+ # Get initial estimate for saturation time
131
+ for i in 0...hflux.size
132
+ rem = hflux.subvector(i, hflux.size - i)
133
+ break if (hflux[i] - rem.mean).abs < rem.sd / 2.0
134
+ break if i > 3.0/4.0*hflux.size
135
+ end
136
+
137
+ @saturation_time_index = [i + 1, hflux.size - 2].min
138
+
139
+ # fit = GSL::Fit::linear(GSL::Vector.indgen(rem.size), rem)
140
+ #
141
+ # slope, covar11 = fit[1], fit[4]
142
+ # range = [slope + Math.sqrt(covar11), slope - Math.sqrt(covar11)]
143
+ #
144
+ # unless range.min < 0 and range.max > 0
145
+ # eputs "Warning: This run (#{id}) has probably not reached a saturated state: the estimated slope of the heat flux is in this range: #{range.inspect}"
146
+ # @saturated = false
147
+ # end
148
+ #
149
+ # ep fit
150
+
151
+ # eputs "Saturation time estimate', @saturation_time_index = i + 1
152
+ # t_vec[@saturation_time_index - 1]
153
+ max_t_index = list(:t).keys.max
154
+ max_t = list(:t).values.max
155
+ min_t = list(:t).values.min
156
+ #hflux = gsl_vector('hflux_tot_over_time', {:t_index_window => [@saturation_time_index, max_t_index]})
157
+ hflux = gsl_vector('phi2tot_over_time', {:t_index_window => [@saturation_time_index, max_t_index]})
158
+ t_vec = gsl_vector('t', {:t_index_window => [@saturation_time_index, max_t_index]})
159
+ # p t_vec[0]
160
+ i = 0
161
+ t_arr = []; conf_arr = []
162
+ loop do
163
+ eprint '.'
164
+
165
+ # GraphKit.autocreate(x: {data: t_vec}, y: {data: hflux}).gnuplot
166
+
167
+ lomb = GSL::SpectralAnalysis::Lomb.alloc(t_vec.subvector(i, t_vec.size - i), hflux.subvector(i, hflux.size - i))
168
+ fs, periodogram = lomb.calculate_periodogram(1.0, 4.0, [0]) #(1.0) #0.1 * hflux.size / ( hflux.size - i))
169
+ # lomb.graphkit.gnuplot
170
+
171
+ # eputs 'Confidence that lowest frequency is not noise is: '
172
+ # pnoise is the probability of the strength of the lowest frequency signal in the heat flux given a hypothesis of gaussian noise. If it is high there is a low likelihood that there is a signal at the lowest frequency: ie. within that window the heat flux has reached a stationary state
173
+ pnoise = lomb.pnull(periodogram[0])
174
+ t_arr.push t_vec[i]; conf_arr.push pnoise
175
+
176
+ (@saturated = true; break) if pnoise > 0.9
177
+ step = (hflux.size / 25.0).to_i
178
+ step = 1 if step==0
179
+ i += step
180
+ #(@saturated = false; i ; break) if (i >= t_vec.size or t_vec[i] > (max_t - min_t) * 2.0 / 3.0 + min_t )
181
+ (@saturated = false; break) if (i >= t_vec.size or t_vec[i] > (max_t - min_t) * 2.0 / 3.0 + min_t )
182
+ @saturation_time_index += step
183
+ # ep '---i,t,size',i, t_vec[i], t_vec.size
184
+ end
185
+ (kit = GraphKit.autocreate({x: {data: t_vec}, y: {data: hflux / hflux.max}}, {x: {data: t_arr}, y: {data: conf_arr}}); kit.data[1].with = 'lp'; kit.gnuplot) if show_graph #(log_axis: 'y')
186
+ # puts
187
+ if @saturated
188
+ # p i
189
+ eputs "saturation time = #{list(:t)[@saturation_time_index]}"
190
+ else
191
+ eputs "run not saturated"
192
+ end
193
+
194
+ return
195
+ exit
196
+ # Get regularly spaced t vector
197
+
198
+ #
199
+ # t_delta_vec = GSL::Vector.alloc(t_vec.size - 1)
200
+ # t_delta_vec.size.times.each{|i| t_delta_vec[i] = t_vec[i+1] - t_vec[i]}
201
+ #
202
+ # ep t_delta_vec.max, t_delta_vec.min
203
+ #
204
+ # even_t = GSL::Vector.linspace(t_vec.min, t_vec.max, ((t_vec.max - t_vec.min) / t_delta_vec.max).round )
205
+ #
206
+ # # even_t = []
207
+ # # tm = t = t_vec[t_delta_vec.max_index]
208
+ #
209
+ # # loop do
210
+ # # even_t.push t
211
+ #
212
+ # #
213
+ # ep even_t.size, t_vec.size
214
+ #
215
+ # min_delt = t_delta_vec.min
216
+ # p even_t.any?{|el| bool = (not t_vec.any?{|ele| (ele - el).abs < 1.0e-1 * min_delt}); ep el if bool; bool}
217
+ #
218
+ # ep t_vec.dup.delete_if{|el| not (el - 71.3).abs < 0.5}
219
+ #
220
+ # exit
221
+
222
+
223
+
224
+
225
+ return
226
+
227
+ # Calculate a series of time averaged segments
228
+ pieces = hflux.pieces(20) # split into 20 pieces
229
+ avgs = GSL::Vector.alloc(pieces.map{|vec| vec.sum/vec.size})
230
+ # Calculate their variance
231
+ mean = (avgs.sum/avgs.size)
232
+ sig = Math.sqrt((avgs.square - mean**2).sum/avgs.size)
233
+ # Discount any at the start which are more than one standard deviation away from the average - they are from the linear growth phase
234
+ t_index = 1
235
+ kept_avgs = avgs.dup
236
+ for i in 0...pieces.size
237
+ if (avgs[i] - mean).abs > sig
238
+ kept_avgs.delete_at(i)
239
+ t_index += pieces[i].size
240
+ else
241
+ break
242
+ end
243
+ end
244
+ eputs "Warning: probably not saturated" if [kept_avgs, kept_avgs.reverse].include? kept_avgs.sort
245
+ ep kept_avgs
246
+ @saturation_time_index = t_index
247
+ # p t_index, list(:t)[t_index]
248
+ end
249
+
250
+ alias :csti :calculate_saturation_time_index
251
+
252
+ def calculate_growth_rates_and_frequencies
253
+ return if @grid_option == "single" and @aky == 0.0 # no meaningful results
254
+ Dir.chdir(@directory) do
255
+ logf(:calculate_growth_rates_and_frequencies)
256
+ logd
257
+
258
+ # get_list_of(:ky, :kx)
259
+ @growth_rates= FloatHash.new
260
+ @real_frequencies = FloatHash.new
261
+ gs2_out = FileUtils.tail(@run_name + ".out", list(:ky).size*list(:kx).size)
262
+ # a = gs2_out.split("\n")
263
+ final_timestep_list = gs2_out #a.slice((a.size-@ky_list.size*@kx_list.size-1)..a.size-1).join("\n")
264
+ log(final_timestep_list.slice(-2..-1))
265
+ # eputs final_timestep_list
266
+ f = LongRegexen::FLOAT.verbatim
267
+ logi(f)
268
+ regex = Regexp.new( "^.*aky=\\s*(?<aky>#{f}).*omav=\\s*(?<re>#{f})\\s*(?<gr>#{f})")
269
+ logi(regex)
270
+ final_timestep_list.gsub(regex) do
271
+ data = $~
272
+ # eputs data.inspect; gets
273
+ #raise CRFatal.new("Unknown value of ky read from output file: #{data[:aky].to_f}. Not in list:\n#{list(:ky).values.inspect}")
274
+
275
+ next unless (list(:ky).values).include? data[:aky].to_f
276
+ #@growth_rates[data[:aky].to_f] = data[:gr].to_f
277
+ aky = data[:aky].to_f
278
+ next if aky==0.0
279
+ @real_frequencies[data[:aky].to_f] = data[:re].to_f
280
+ end
281
+ # pp @ky_list
282
+
283
+ # With zero magnetic shear, calculate growth rates for both kx and ky
284
+ if @shat and @shat.abs < 1.0e-5 and @nx and @nx > 1
285
+ to_calc = [:kx, :ky]
286
+ @growth_rate_at_kx ||= FloatHash.new
287
+ else
288
+ to_calc = [:ky]
289
+ end
290
+
291
+ @growth_rate_at_ky ||= FloatHash.new
292
+ eputs
293
+ # p @growth_rate_at_kx; exit
294
+ to_calc.each do |kxy|
295
+ growth_rates = send(:growth_rate_at_ + kxy)
296
+ list(kxy).values.sort.each do |value|
297
+
298
+ #p growth_rates.keys, value, growth_rates[value.to_f-0.0],
299
+ #growth_rates.class, growth_rates.keys.include?(value); exit
300
+
301
+ next if growth_rates.keys.include? value
302
+
303
+
304
+ Terminal.erewind(1)
305
+ #ep growth_rates.keys
306
+ eputs sprintf("Calculating growth rate for #{kxy} = % 1.5e#{Terminal::CLEAR_LINE}", value)
307
+
308
+
309
+ # Mode has 0 growth rate at ky==0
310
+ (growth_rates[value] = 0.0; next) if value == 0.0 and kxy == :ky
311
+ if @g_exb_start_timestep
312
+ t_index_window = [1, [(g_exb_start_timestep-1)/@nwrite, list(:t).keys.max].min]
313
+ #ep "t_index_window", t_index_window
314
+ else
315
+ t_index_window = nil
316
+ end
317
+ if list(kxy).size == 1
318
+ phi2_vec = gsl_vector("phi2tot_over_time", t_index_window: t_index_window)
319
+ else
320
+ phi2_vec = gsl_vector("phi2_by_#{kxy}_over_time", kxy=>value, :t_index_window=> t_index_window)
321
+ end
322
+ (growth_rates[value] = 0.0; next) if phi2_vec.min <= 0.0
323
+ growth_rates[value] = calculate_growth_rate(phi2_vec)
324
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rate\n----------\n\n"; growth_rates[value] = -1; next) if growth_rates[value] == "NaN"
325
+ end
326
+ end
327
+
328
+ write_results
329
+
330
+ # ep "growth_rate_at_ky", @growth_rate_at_ky
331
+ if ENV['GS2_CALCULATE_ALL']
332
+ trap(0){eputs "Calculation of spectrum did not complete: run 'cgrf' (i.e. calculate_growth_rates_and_frequencies) for this run. E.g. from the command line \n $ coderunner rc 'cgrf' -j #{@id}"; exit}
333
+ @growth_rate_at_ky_at_kx ||= FloatHash.new
334
+ list(:ky).values.sort.each do |kyv|
335
+ @growth_rate_at_ky_at_kx[kyv] ||= FloatHash.new
336
+ #p @growth_rate_at_ky_at_kx[kyv]
337
+ list(:kx).values.sort.each do |kxv|
338
+ next if @growth_rate_at_ky_at_kx[kyv].keys.include? kxv
339
+ Terminal.erewind(1)
340
+ eputs sprintf("Calculating growth rate for kx = % 1.5e and ky = % 1.5e#{Terminal::CLEAR_LINE}", kxv, kyv)
341
+ (@growth_rate_at_ky_at_kx[kyv][kxv] = 0.0; next) if kyv == 0.0 # Mode has 0 growth rate at ky==0
342
+ phi2_vec = gsl_vector("phi2_by_mode_over_time", {:kx=>kxv, :ky=>kyv})
343
+ (@growth_rate_at_ky_at_kx[kyv][kxv] = 0.0; next) if phi2_vec.min <= 0.0
344
+ @growth_rate_at_ky_at_kx[kyv][kxv] = calculate_growth_rate(phi2_vec)
345
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rates\n----------\n\n"; @growth_rate_at_ky_at_kx[kyv][kxv] = -1; next) if @growth_rate_at_ky_at_kx[kyv][kxv] == "NaN"
346
+ end
347
+ write_results
348
+ end
349
+ trap(0){}
350
+ end
351
+ @growth_rates = @growth_rate_at_ky
352
+ @max_growth_rate = @growth_rates.values.max
353
+ @fastest_growing_mode = @growth_rates.key(@max_growth_rate)
354
+ @freq_of_max_growth_rate = @real_frequencies[@fastest_growing_mode]
355
+ ep @max_growth_rate, @growth_rates
356
+ @decaying = (@max_growth_rate < 0) if @max_growth_rate
357
+ @ky = @aky if @aky
358
+ if @grid_option == "single"
359
+ # ep @aky, @growth_rates
360
+ @gamma_r = @growth_rates[@aky.to_f]
361
+ @gamma_i = @real_frequencies[@aky.to_f]
362
+ end
363
+ # ep @gamma_r
364
+
365
+
366
+ # eputs @growth_rates; gets
367
+ end
368
+ end
369
+
370
+ alias :cgrf :calculate_growth_rates_and_frequencies
371
+
372
+ def calculate_growth_rate(vector, options={})
373
+ raise "This vector should be positive definite" if vector.min < 0.0
374
+ offset = 0
375
+ length = vector.length
376
+ offset+=1 while vector[offset] == 0.0
377
+ growth_rate = GSL::Fit::linear(gsl_vector(:t).subvector(offset, length-offset), 0.5*GSL::Sf::log(vector.subvector(offset, length - offset)))[1]
378
+ divisor = 1
379
+ while (growth_rate.to_s == "NaN")
380
+ #This corrects the growth rate if phi has grown all the way to NaN during the simulation
381
+ divisor *= 2
382
+ length = (vector.size.to_f / divisor.to_f).floor
383
+ # p length
384
+ return "NaN" if length <= offset + 1
385
+ growth_rate = GSL::Fit::linear(gsl_vector(:t).subvector(offset, length-offset), 0.5*GSL::Sf::log(vector.subvector(offset, length-offset)))[1]
386
+ end
387
+ growth_rate
388
+ end
389
+
390
+ # Not needed for GS2 built after 16/06/2010
391
+
392
+ def corrected_mom_flux_stav
393
+ par_mom_flux_stav - perp_mom_flux_stav
394
+ end
395
+
396
+ def calculate_transient_amplifications
397
+ return if @grid_option == "single" and @aky == 0.0 # no meaningful results
398
+ Dir.chdir(@directory) do
399
+ # With zero magnetic shear, calculate amplifications for both kx and ky
400
+ if @shat and @shat.abs < 1.0e-5 and @nx > 1
401
+ to_calc = [:kx, :ky]
402
+ @transient_amplification_at_kx ||= FloatHash.new
403
+ else
404
+ to_calc = [:ky]
405
+ end
406
+
407
+ @transient_amplification_at_ky ||= FloatHash.new
408
+ eputs
409
+ to_calc.each do |kxy|
410
+ transient_amplifications = send(:transient_amplification_at_ + kxy)
411
+ list(kxy).values.sort.each do |value|
412
+
413
+ #p transient_amplifications.keys, value, transient_amplifications[value.to_f-0.0],
414
+ #transient_amplifications.class, transient_amplifications.keys.include?(value); exit
415
+
416
+ next if transient_amplifications.keys.include? value
417
+
418
+
419
+ Terminal.erewind(1)
420
+ #ep transient_amplifications.keys
421
+ eputs sprintf("Calculating transient amplification for #{kxy} = % 1.5e#{Terminal::CLEAR_LINE}", value)
422
+
423
+
424
+ # Mode has 0 growth rate at ky==0
425
+ (transient_amplifications[value] = 0.0; next) if value == 0.0 and kxy == :ky
426
+ phi2_vec = gsl_vector("phi2_by_#{kxy}_over_time", {kxy=>value})
427
+ #(transient_amplifications[value] = 0.0; next) if phi2_vec.min <= 0.0
428
+ transient_amplifications[value] = calculate_transient_amplification(phi2_vec)
429
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rate\n----------\n\n"; transient_amplifications[value] = -1; next) if transient_amplifications[value].to_s == "NaN"
430
+ end
431
+ end
432
+
433
+ write_results
434
+
435
+ # ep "transient_amplification_at_ky", @transient_amplification_at_ky
436
+ if ENV['GS2_CALCULATE_ALL']
437
+ trap(0){eputs "Calculation of spectrum did not complete: run 'cgrf' (i.e. calculate_transient_amplifications_and_frequencies) for this run. E.g. from the command line \n $ coderunner rc 'cgrf' -j #{@id}"; exit}
438
+ @transient_amplification_at_ky_at_kx ||= FloatHash.new
439
+ list(:ky).values.sort.each do |kyv|
440
+ @transient_amplification_at_ky_at_kx[kyv] ||= FloatHash.new
441
+ #p @transient_amplification_at_ky_at_kx[kyv]
442
+ list(:kx).values.sort.each do |kxv|
443
+ next if @transient_amplification_at_ky_at_kx[kyv].keys.include? kxv
444
+ Terminal.erewind(1)
445
+ eputs sprintf("Calculating growth rate for kx = % 1.5e and ky = % 1.5e#{Terminal::CLEAR_LINE}", kxv, kyv)
446
+ (@transient_amplification_at_ky_at_kx[kyv][kxv] = 0.0; next) if kyv == 0.0 # Mode has 0 growth rate at ky==0
447
+ phi2_vec = gsl_vector("phi2_by_mode_over_time", {:kx=>kxv, :ky=>kyv})
448
+ #(@transient_amplification_at_ky_at_kx[kyv][kxv] = 0.0; next) if phi2_vec.min <= 0.0
449
+ @transient_amplification_at_ky_at_kx[kyv][kxv] = calculate_transient_amplification(phi2_vec)
450
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rates\n----------\n\n"; @transient_amplification_at_ky_at_kx[kyv][kxv] = -1; next) if @transient_amplification_at_ky_at_kx[kyv][kxv].to_s == "NaN"
451
+ end
452
+ write_results
453
+ end
454
+ trap(0){}
455
+ end
456
+ @transient_amplifications = @transient_amplification_at_ky
457
+ @max_transient_amplification = @transient_amplifications.values.max
458
+ @most_amplified_mode = @transient_amplifications.key(@max_transient_amplification)
459
+ #@freq_of_max_transient_amplification = @real_frequencies[@fastest_growing_mode]
460
+ #ep @max_transient_amplification, @transient_amplifications
461
+ #@decaying = (@max_transient_amplification < 0) if @max_transient_amplification
462
+ @ky = @aky if @aky
463
+ #if @grid_option == "single"
464
+ ## ep @aky, @transient_amplifications
465
+ #@gamma_r = @transient_amplifications[@aky.to_f]
466
+ #@gamma_i = @real_frequencies[@aky.to_f]
467
+ #end
468
+ # ep @gamma_r
469
+
470
+
471
+ # eputs @transient_amplifications; gets
472
+ end
473
+ end
474
+
475
+ alias :cta :calculate_transient_amplifications
476
+
477
+
478
+ def calculate_transient_es_heat_flux_amplifications
479
+ return if @grid_option == "single" and @aky == 0.0 # no meaningful results
480
+
481
+ @transient_es_heat_flux_amplification_at_species_at_kx = []
482
+ @transient_es_heat_flux_amplification_at_species_at_ky = []
483
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx = []
484
+ for species_index in 1..nspec
485
+
486
+ Dir.chdir(@directory) do
487
+ # With zero magnetic shear, calculate amplifications for both kx and ky
488
+ if @shat and @shat.abs < 1.0e-5 and @nx > 1 and !@ikx_init and false
489
+ to_calc = [:kx, :ky]
490
+ @transient_es_heat_flux_amplification_at_species_at_kx[species_index-1] ||= FloatHash.new
491
+ else
492
+ to_calc = [:ky]
493
+ end
494
+
495
+ @transient_es_heat_flux_amplification_at_species_at_ky[species_index-1] ||= FloatHash.new
496
+ eputs
497
+ to_calc.each do |kxy|
498
+ transient_es_heat_flux_amplifications = send(:transient_es_heat_flux_amplification_at_species_at_ + kxy)[species_index-1]
499
+ list(kxy).values.sort.each do |value|
500
+
501
+ #p transient_es_heat_flux_amplifications.keys, value, transient_es_heat_flux_amplifications[value.to_f-0.0],
502
+ #transient_es_heat_flux_amplifications.class, transient_es_heat_flux_amplifications.keys.include?(value); exit
503
+
504
+ next if transient_es_heat_flux_amplifications.keys.include? value
505
+
506
+
507
+ Terminal.erewind(1)
508
+ #ep transient_es_heat_flux_amplifications.keys
509
+ eputs sprintf("Calculating transient amplification for #{kxy} = % 1.5e#{Terminal::CLEAR_LINE}", value)
510
+
511
+
512
+ # Mode has 0 growth rate at ky==0
513
+ (transient_es_heat_flux_amplifications[value] = 0.0; next) if value == 0.0 and kxy == :ky
514
+ phi2_vec = gsl_vector("es_heat_by_#{kxy}_over_time", {kxy=>value, species_index: species_index})
515
+ #(transient_es_heat_flux_amplifications[value] = 0.0; next) if phi2_vec.min <= 0.0
516
+ transient_es_heat_flux_amplifications[value] = calculate_transient_amplification(phi2_vec)
517
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rate\n----------\n\n"; transient_es_heat_flux_amplifications[value] = -1; next) if transient_es_heat_flux_amplifications[value].to_s == "NaN"
518
+ end
519
+ end
520
+
521
+ write_results
522
+
523
+ # ep "transient_es_heat_flux_amplification_at_species_at_ky", @transient_es_heat_flux_amplification_at_species_at_ky
524
+ if ENV['GS2_CALCULATE_ALL']
525
+ trap(0){eputs "Calculation of spectrum did not complete: run 'ctehfa' (i.e. calculate_transient_es_heat_flux_amplifications) for this run. E.g. from the command line \n $ coderunner rc 'ctehfa' -j #{@id}"; exit}
526
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1] ||= FloatHash.new
527
+ list(:ky).values.sort.each do |kyv|
528
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv] ||= FloatHash.new
529
+ #p @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[kyv]
530
+ list(:kx).values.sort.each do |kxv|
531
+ next if @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv].keys.include? kxv
532
+ Terminal.erewind(1)
533
+ eputs sprintf("Calculating growth rate for kx = % 1.5e and ky = % 1.5e#{Terminal::CLEAR_LINE}", kxv, kyv)
534
+ (@transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = 0.0; next) if kyv == 0.0 # Mode has 0 growth rate at ky==0
535
+ phi2_vec = gsl_vector("phi2_by_mode_over_time", {:kx=>kxv, :ky=>kyv})
536
+ #(@transient_es_heat_flux_amplification_at_species_at_ky_at_kx[kyv][kxv] = 0.0; next) if phi2_vec.min <= 0.0
537
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = calculate_transient_es_heat_flux_amplification(phi2_vec)
538
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rates\n----------\n\n"; @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = -1; next) if @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv].to_s == "NaN"
539
+ end
540
+ write_results
541
+ end
542
+ trap(0){}
543
+ end
544
+ #@max_transient_es_heat_flux_amplification = @transient_es_heat_flux_amplifications.values.max
545
+ #@most_amplified_mode = @transient_es_heat_flux_amplifications.key(@max_transient_es_heat_flux_amplification)
546
+ #@ky = @aky if @aky
547
+ end
548
+ end # for species_index in 1..nspec
549
+ end
550
+
551
+ def calculate_transient_es_heat_flux_amplifications
552
+ return if @grid_option == "single" and @aky == 0.0 # no meaningful results
553
+ @transient_es_heat_flux_amplification_at_species_at_kx = []
554
+ @transient_es_heat_flux_amplification_at_species_at_ky = []
555
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx = []
556
+ for species_index in 1..nspec
557
+
558
+ Dir.chdir(@directory) do
559
+ #trap(0){eputs "Calculation of transient amplification did not complete: run 'ctehfa' (i.e. calculate_transient_es_heat_flux_amplifications) for this run. E.g. from the command line \n $ coderunner rc 'ctehfa' -j #{@id}"; exit}
560
+ es_heat_flux_narray = netcdf_file.var('es_heat_by_k').get
561
+
562
+ ep es_heat_flux_narray.shape, '', '', ''
563
+ t_size = es_heat_flux_narray.shape[-1]
564
+ temp_es_heat = GSL::Vector.alloc(t_size)
565
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1] ||= FloatHash.new
566
+ ky_index=0
567
+ list(:ky).values.each do |kyv|
568
+ ky_index +=1
569
+ kx_index = 0
570
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv] ||= FloatHash.new
571
+ #p @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[kyv]
572
+ list(:kx).values.each do |kxv|
573
+ kx_index +=1
574
+ next if @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv].keys.include? kxv
575
+ Terminal.erewind(1)
576
+ eputs sprintf("Calculating transient amplification for kx = % 1.5e and ky = % 1.5e#{Terminal::CLEAR_LINE}", kxv, kyv)
577
+ (@transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = 0.0; next) if kyv == 0.0 # Mode has 0 growth rate at ky==0
578
+ #phi2_vec = gsl_vector("phi2_by_mode_over_time", {:kx=>kxv, :ky=>kyv})
579
+
580
+ #ep({kx: kxv})
581
+ #hash = ({kx: kxv})
582
+ #ep(hash.convert_to_index(self, :kx))
583
+ #kx_index = {kx: kxv}.convert_to_index(self, :kx)[:kx_index]
584
+ #ky_index = {ky: kyv}.convert_to_index(self, :ky)[:ky_index]
585
+ #p t_size
586
+ for i in 0...t_size
587
+ #p i
588
+ temp_es_heat[i] = es_heat_flux_narray[kx_index-1, ky_index -1, species_index-1, i]
589
+ #temp_es_heat[i] = es_heat_flux_narray[i, species_index-1, ky_index-1, kx_index-1]
590
+ end
591
+ #(@transient_es_heat_flux_amplification_at_species_at_ky_at_kx[kyv][kxv] = 0.0; next) if phi2_vec.min <= 0.0
592
+ @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = calculate_transient_amplification(temp_es_heat)
593
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rates\n----------\n\n"; @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv] = -1; next) if @transient_es_heat_flux_amplification_at_species_at_ky_at_kx[species_index-1][kyv][kxv].to_s == "NaN"
594
+ end
595
+ write_results
596
+ end
597
+ #trap(0){}
598
+ # With zero magnetic shear, calculate amplifications for both kx and ky
599
+
600
+ #return
601
+ if @shat and @shat.abs < 1.0e-5 and @nx > 1 and !@ikx_init and false
602
+ to_calc = [:kx, :ky]
603
+ @transient_es_heat_flux_amplification_at_species_at_kx[species_index-1] ||= FloatHash.new
604
+ else
605
+ to_calc = [:ky]
606
+ end
607
+
608
+ @transient_es_heat_flux_amplification_at_species_at_ky[species_index-1] ||= FloatHash.new
609
+ eputs
610
+ to_calc.each do |kxy|
611
+ transient_es_heat_flux_amplifications = send(:transient_es_heat_flux_amplification_at_species_at_ + kxy)[species_index-1]
612
+ list(kxy).values.sort.each do |value|
613
+
614
+ #p transient_es_heat_flux_amplifications.keys, value, transient_es_heat_flux_amplifications[value.to_f-0.0],
615
+ #transient_es_heat_flux_amplifications.class, transient_es_heat_flux_amplifications.keys.include?(value); exit
616
+
617
+ next if transient_es_heat_flux_amplifications.keys.include? value
618
+
619
+
620
+ Terminal.erewind(1)
621
+ #ep transient_es_heat_flux_amplifications.keys
622
+ eputs sprintf("Calculating transient amplification for #{kxy} = % 1.5e#{Terminal::CLEAR_LINE}", value)
623
+
624
+
625
+ # Mode has 0 growth rate at ky==0
626
+ (transient_es_heat_flux_amplifications[value] = 0.0; next) if value == 0.0 and kxy == :ky
627
+ phi2_vec = gsl_vector("es_heat_by_#{kxy}_over_time", {kxy=>value, species_index: species_index})
628
+ #(transient_es_heat_flux_amplifications[value] = 0.0; next) if phi2_vec.min <= 0.0
629
+ transient_es_heat_flux_amplifications[value] = calculate_transient_amplification(phi2_vec)
630
+ (eputs "\n\n----------\nIn #@run_name:\n\nphi2_by_#{kxy}_over_time is all NaN; unable to calculate growth rate\n----------\n\n"; transient_es_heat_flux_amplifications[value] = -1; next) if transient_es_heat_flux_amplifications[value].to_s == "NaN"
631
+ end
632
+ end
633
+
634
+ write_results
635
+
636
+ # ep "transient_es_heat_flux_amplification_at_species_at_ky", @transient_es_heat_flux_amplification_at_species_at_ky
637
+
638
+ #@max_transient_es_heat_flux_amplification = @transient_es_heat_flux_amplifications.values.max
639
+ #@most_amplified_mode = @transient_es_heat_flux_amplifications.key(@max_transient_es_heat_flux_amplification)
640
+ #@ky = @aky if @aky
641
+ end # Dir.chdir
642
+ end # for species_index in 1..nspec
643
+ end
644
+
645
+ alias :ctehfa :calculate_transient_es_heat_flux_amplifications
646
+ alias :ctehfa :calculate_transient_es_heat_flux_amplifications
647
+
648
+ def calculate_transient_amplification(vector, options={})
649
+ turning_points = {}
650
+ old = vector[0]
651
+ i = 0
652
+ #for i in i...vector.size
653
+ #new = vector[i]
654
+ #if new > old
655
+ #turning_points[:first_min] = i-1
656
+ #ep "First turning point[#{i}]\n"
657
+ #break
658
+ #end
659
+ #old = new
660
+ #end
661
+
662
+ #for i in i...vector.size
663
+ #new = vector[i]
664
+ #if new < old
665
+ #turning_points[:first_max] = i-1
666
+ #ep "Second turning point[#{i}]\n"
667
+ #break
668
+ #end
669
+ #end
670
+
671
+ #unless turning_points[:first_max] # and turning_points[:first_min]
672
+ #return NaN
673
+ #end
674
+ ##t = gsl_vector('t')
675
+ ##for j in 0...vector.size
676
+ ##break if t[j] > 0.2
677
+ ##end
678
+ #ep "vector[0..5]: #{vector.subvector(0,5)}\n"
679
+ #return Math.sqrt(vector[turning_points[:first_max]]/@phiinit)
680
+ return vector.max/@phiinit
681
+ end
682
+
683
+ def ctan
684
+ list(:ky).each do |(ky_index, ky)|
685
+ eputs "ky: #{ky}"
686
+ phi_vec = gsl_vector("phi2_by_ky_over_time", ky_index: ky_index)
687
+ t_element = 0
688
+ old = phi_vec[0]
689
+
690
+ loop do
691
+ t_element+=1
692
+ #print t_element, ',', phi_vec.size
693
+ new = phi_vec[t_element]
694
+ break if new > old or t_element == phi_vec.size - 1
695
+ old = new
696
+ end
697
+
698
+ if t_element == phi_vec.size - 1
699
+ @transient_amplification_at_ky[ky] = -1
700
+ eputs "No Min"
701
+ next
702
+ end
703
+ first_min = t_element
704
+
705
+ eputs "ky: #{ky}, first_min: #{first_min}"
706
+ loop do
707
+ t_element+=1
708
+ #print t_element, ',', phi_vec.size
709
+ new = phi_vec[t_element]
710
+ break if new < old or t_element == phi_vec.size - 1
711
+ end
712
+ if t_element == phi_vec.size - 1
713
+ @transient_amplification_at_ky[ky] = -1
714
+ next
715
+ end
716
+ @transient_amplification_at_ky[ky] = phi_vec.subvector(t_element, phi_vec.size - t_element).max
717
+ end
718
+ end
719
+
720
+ def max_trans_phi
721
+ phivec = gsl_vector('phi2tot_over_time')
722
+ offset = 30
723
+ phivec.subvector(20, phivec.size - 20).max
724
+ end
725
+
726
+ def max_es_heat_amp(species_index)
727
+ @transient_es_heat_flux_amplification_at_species_at_ky[species_index-1].values.max
728
+ end
729
+
730
+ def calculate_spectral_checks
731
+ ky_spec = gsl_vector('spectrum_over_ky')
732
+ kx_spec = gsl_vector('spectrum_over_kx')
733
+ kpar_spec = gsl_vector('spectrum_over_kpar', ky_index: ky_spec.max_index + 1, kx_index: 1)
734
+
735
+ @spectrum_check = []
736
+ [kx_spec, ky_spec, kpar_spec].each do |spec|
737
+ begin
738
+ ends_max = [spec[0], spec[-1]].max + (10.0**(-9))
739
+ p ends_max
740
+ p spec.max
741
+ check = (Math.log(spec.max/ends_max)/Math.log(10)).round
742
+ rescue
743
+ check= -10
744
+ end
745
+ @spectrum_check.push check
746
+ end
747
+ end
748
+
749
+ def calculate_vspace_checks
750
+ @vspace_check = ['lpc_pitch_angle', 'vres_pitch_angle', 'lpc_energy', 'vres_energy'].map do |name|
751
+ saturated_time_average(name, {})
752
+ end
753
+
754
+ end
755
+
756
+ alias :cvc :calculate_vspace_checks
757
+
758
+ def spec_chec(min, *dirns)
759
+ return @spectrum_check.zip([0, 1, 2]).inject(true) do |bool, (check,dirn)|
760
+ unless dirns.include? dirn
761
+ bool and true
762
+ else
763
+ unless check >= min
764
+ false
765
+ else
766
+ bool and true
767
+ end
768
+ end
769
+ end
770
+ end
771
+
772
+ def sc(min)
773
+ return @spectrum_check.min >= min
774
+ end
775
+ alias :csc :calculate_spectral_checks
776
+
777
+
778
+ end
779
+ end
780
+