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,1181 @@
1
+ #########################
2
+ # GS2 CodeRunner module
3
+ # Data Analysis
4
+ #########################
5
+ #
6
+
7
+ #
8
+
9
+ class NumRu::NetCDF
10
+ aliold :var
11
+ def var(*args)
12
+ if args[0].kind_of? Symbol
13
+ args[0] = args[0].to_s
14
+ end
15
+ return old_var(*args)
16
+ end
17
+ end
18
+ class CodeRunner
19
+ class Gs2
20
+
21
+
22
+ eval(File.read(File.dirname(__FILE__) + '/gsl_tools.rb'), GLOBAL_BINDING, File.dirname(__FILE__) + '/gsl_tools.rb')
23
+
24
+ # def gsl_vector(name, options={})
25
+ # if options[:t_index] or options[:frame_index] or not [:Failed, :Complete].include? status
26
+ # return get_gsl_vector(name, options)
27
+ # else
28
+ # return cache[[:gsl_vector, name, options]] ||= get_gsl_vector(name, options)
29
+ # end
30
+ # end
31
+
32
+ def netcdf_file
33
+ #if @runner.cache[:runs] and (open = @runner.cache[:runs].keys.find_all{|id| @runner.cache[:runs][id][:netcdf_file]}).size > 200
34
+ #ep "my id", id
35
+ if (open = @runner.run_list.keys.find_all{|id| @runner.run_list[id].cache[:netcdf_file]}).size > 200
36
+ open = open.sort_by{|id| @runner.run_list[id].cache[:netcdf_file_otime]}
37
+ @runner.run_list[open[0]].ncclose
38
+ end
39
+
40
+ if cache[:netcdf_file] and not [:Complete, :Failed].include? @status
41
+ ncclose
42
+ end
43
+ cache[:netcdf_file_otime] = Time.now.to_i
44
+ cache[:netcdf_file] ||= NumRu::NetCDF.open(@directory + '/' + @run_name + '.out.nc')
45
+ end
46
+
47
+ def ncclose
48
+ cache[:netcdf_file].close
49
+ cache.delete(:netcdf_file)
50
+ end
51
+
52
+
53
+
54
+ module FixNormOption
55
+ #class << self
56
+ def fix_norm_action(options)
57
+ case options[:set_norm_option]
58
+ when "t_over_m", "bd"
59
+ if ["t_over_m", "bd"].include? @norm_option
60
+ return :none
61
+ else
62
+ return :from_root_2
63
+ end
64
+ else
65
+ #eputs "else", norm_option
66
+ if ["t_over_m", "bd"].include? @norm_option
67
+ #eputs "norm old"
68
+ return :to_root_2
69
+ else
70
+ return :none
71
+ end
72
+ end
73
+ end
74
+
75
+ def fix_heat_flux_norm(tensor, options={})
76
+ case fix_norm_action(options)
77
+ when :none
78
+ #eputs "none"
79
+ return tensor
80
+ when :to_root_2
81
+ eputs "to_root_2"
82
+ return tensor / 2.0**1.5
83
+ when :from_root_2
84
+ return tensor * 2.0**1.5
85
+ end
86
+ end
87
+
88
+ # Return tensor normalised according to options[:set_norm_option]
89
+ # (which may be "t_over_m", "bd" or "with_root_2", "mtk" etc)
90
+ # regardless of the original normalisation.
91
+ #
92
+ # <tt>power</tt> should be the power to which the reference thermal
93
+ # velocity is raised in the normalising quantity. For example,
94
+ # <tt>t</tt> is normalised to a / v_thr, so for times, power should
95
+ # be set equal to -1.
96
+
97
+ def fix_norm(tensor, power, options={})
98
+ case fix_norm_action(options)
99
+ when :none
100
+ #eputs "none"
101
+ return tensor
102
+ when :to_root_2
103
+ eputs "to_root_2"
104
+ return tensor / 2.0**(0.5 * power)
105
+ when :from_root_2
106
+ return tensor * 2.0**(0.5 * power)
107
+ end
108
+ end
109
+
110
+ #end # class << self
111
+ end # module FixNormOption
112
+
113
+ include FixNormOption
114
+
115
+ def gsl_vector(name, options={})
116
+ Dir.chdir(@directory) do
117
+ options[:t_index_window] ||= @scan_index_window
118
+ options.setup_time_window
119
+ if [:ky, :kx].include? name.to_sym
120
+ return fix_norm(
121
+ GSL::Vector.alloc(netcdf_file.var(name.to_s).get.to_a.sort),
122
+ -1, options
123
+ ) # ky, ky are normalised to 1 / rho_i
124
+ elsif [:theta].include? name.to_sym
125
+ #ep options; gets
126
+ #vec = GSL::Vector.alloc(netcdf_file.var(name.to_s).get({'start' => [options[:thetamin]||0], 'end' => [options[:thetamax]||-1]}).to_a)
127
+ vec = GSL::Vector.alloc(netcdf_file.var(name.to_s).get.to_a)
128
+ if ith = options[:interpolate_theta]
129
+ osize = vec.size
130
+ newsize = (osize-1)*ith+1
131
+ newvec = GSL::Vector.alloc(newsize)
132
+ newvec[newsize-1] = vec[osize-1]# * ith.to_f
133
+ for i in 0...(newsize-1)
134
+ im = i%ith
135
+ frac = im.to_f/ith.to_f
136
+ #iold = (i-im)/(new_shape[-1]-1)*(shape[-1]-1)
137
+ iold = (i-im)/ith
138
+ newvec[i] = (vec[iold] * (1.0-frac) + vec[iold+1] * frac)
139
+ end
140
+ vec = newvec
141
+ end
142
+ start = options[:thetamin]||0
143
+ endv = options[:thetamax]||vec.size-1
144
+ vec = vec.subvector(start, (endv-start+1)).dup
145
+ return vec
146
+ elsif name.to_sym == :t
147
+ #options.setup_time_window
148
+ t = GSL::Vector.alloc(netcdf_file.var(name.to_s).get('start' => [options[:begin_element]], 'end' => [options[:end_element]]).to_a)
149
+ t = t - t[0] if options[:sync_time]
150
+ return fix_norm(t, -1, options) # t is normalised to a/v_thi
151
+ end
152
+ options = eval(options) if options.class == String
153
+ if options[:saturated_time_average] or options[:sta]
154
+ raise "Not Saturated" unless @saturation_time_index
155
+ tmax = list(:t).keys.max
156
+ return ((@saturation_time_index..tmax).to_a.map do |t_index|
157
+ gsl_vector(name, options.dup.absorb({t_index: t_index, saturated_time_average: nil, sta: nil}))
158
+ end).sum / (list(:t).values.max - list(:t)[@saturation_time_index])
159
+ elsif options[:time_average] or options[:ta]
160
+ tmax = list(:t).keys.max
161
+ start_t = 2
162
+ return ((start_t..tmax).to_a.map do |t_index|
163
+ gsl_vector(name, options.dup.absorb({t_index: t_index, time_average: nil, ta: nil}))
164
+ end).sum / (list(:t).values.max - list(:t)[start_t])
165
+ end
166
+ if method = self.class.instance_methods.find{|meth| (name + '_gsl_vector').to_sym == meth}
167
+ options[:graphkit_name] = name
168
+ return send(method, options)
169
+ end
170
+ end
171
+ raise "GSL Vector #{name} not found"
172
+ end
173
+
174
+ module GSLVectors
175
+
176
+ # The square of the potential summed over all wave numbers, indexed by time, normalised to (e/T)(rho_1/a).
177
+
178
+ def phi2tot_over_time_gsl_vector(options)
179
+
180
+ Dir.chdir(@directory) do #Necessary options: ky
181
+ #log 'about to open netcdf file'
182
+ #options.setup_time_window
183
+ phis = netcdf_file.var('phi2').get('start'=>[options[:begin_element]], 'end'=>[options[:end_element]] ).to_a
184
+ log 'about to allocate gsl vector'
185
+ vec = GSL::Vector.alloc(phis)
186
+ log 'finished'
187
+ return fix_norm(vec, 1, options)
188
+ end
189
+ end
190
+ def apar2_over_time_gsl_vector(options)
191
+
192
+ Dir.chdir(@directory) do #Necessary options: ky
193
+ #log 'about to open netcdf file'
194
+ #options.setup_time_window
195
+ phis = netcdf_file.var('apar2').get('start'=>[options[:begin_element]], 'end'=>[options[:end_element]] ).to_a
196
+ log 'about to allocate gsl vector'
197
+ vec = GSL::Vector.alloc(phis)
198
+ log 'finished'
199
+ return fix_norm(vec, 1, options)
200
+ end
201
+ end
202
+
203
+ def transient_es_heat_flux_amplification_over_kx_gsl_vector(options)
204
+ options[:direction] = :kx
205
+ transient_es_heat_flux_amplification_over_kxy_gsl_vector(options)
206
+ end
207
+
208
+ def transient_es_heat_flux_amplification_over_ky_gsl_vector(options)
209
+ options[:direction] = :ky
210
+ transient_es_heat_flux_amplification_over_kxy_gsl_vector(options)
211
+ end
212
+ def transient_es_heat_flux_amplification_over_kxy_gsl_vector(options)
213
+ Dir.chdir(@directory) do # i.e. phi2_by_ky_vs_time or phi2_by_kx_vs_time
214
+ kxy = options[:direction].to_sym
215
+
216
+ # ep :growth_rate_at_ + kxy
217
+ p send(:transient_es_heat_flux_amplification_at_species_at_ + kxy)
218
+ return GSL::Vector.alloc(send(:transient_es_heat_flux_amplification_at_species_at_ + kxy)[options[:species_index]-1].values)
219
+
220
+ end
221
+ end
222
+
223
+ def transient_amplification_over_kx_gsl_vector(options)
224
+ options[:direction] = :kx
225
+ transient_amplification_over_kxy_gsl_vector(options)
226
+ end
227
+ def transient_amplification_over_kxy_gsl_vector(options)
228
+ options[:direction] = :ky
229
+ transient_amplification_over_kxy_gsl_vector(options)
230
+ end
231
+ def transient_amplification_over_kxy_gsl_vector(options)
232
+ Dir.chdir(@directory) do # i.e. phi2_by_ky_vs_time or phi2_by_kx_vs_time
233
+ kxy = options[:direction]
234
+ # ep :growth_rate_at_ + kxy
235
+ return GSL::Vector.alloc(send(:transient_amplification_at_ + kxy).values)
236
+
237
+ end
238
+ end
239
+ private :transient_amplification_over_kxy_gsl_vector
240
+
241
+ # The growth rate of the fluctuations, calculated from the potential, indexed by time and normalised to vth_1/a.
242
+ # :kx or :kx_index must be specified in options
243
+ #
244
+ def growth_rate_by_kx_over_time_gsl_vector(options)
245
+ options[:direction] = :kx
246
+ growth_rate_by_kxy_over_time_gsl_vector(options)
247
+ end
248
+
249
+ # The growth rate of the fluctuations, calculated from the potential, indexed by time and normalised to vth_1/a.
250
+ # :ky or :ky_index must be specified in options
251
+
252
+ def growth_rate_by_ky_over_time_gsl_vector(options)
253
+ options[:direction] = :ky
254
+ growth_rate_by_kxy_over_time_gsl_vector(options)
255
+ end
256
+ def growth_rate_by_kxy_over_time_gsl_vector(options)
257
+ # i.e. time_dependent_gr_by_ky_vs_time or phi2_by_kx_vs_time
258
+
259
+ kxy = options[:direction]
260
+
261
+ phi = gsl_vector("phi2_by_#{kxy}_over_time", options).log / 2.0
262
+
263
+ size = phi.size
264
+ dphi = phi.subvector(1, size - 1) - phi.subvector(0, size-1)
265
+ # NB dt already has norm fixed, dphi is dimensionless
266
+ return fix_norm(dphi/gsl_vector('dt'), 0, options)
267
+ end
268
+
269
+ # The size of each time step, indexed by time, normalised to a/v_th1.
270
+
271
+ def dt_gsl_vector(options)
272
+ t = gsl_vector('t', options)
273
+ size = t.size
274
+ # NB t already has norm fixed
275
+ return t.subvector(1, size - 1) - t.subvector(0, size-1)
276
+ end
277
+
278
+ # The growth rate, calculated from the potential, indexed by kx. Only makes sense in linear calculations.
279
+ def growth_rate_over_kx_gsl_vector(options)
280
+ options[:direction] = :kx
281
+ growth_rate_over_kxy_gsl_vector(options)
282
+ end
283
+ # The growth rate, calculated from the potential, indexed by ky. Only makes sense in linear calculations.
284
+ def growth_rate_over_ky_gsl_vector(options)
285
+ options[:direction] = :ky
286
+ growth_rate_over_kxy_gsl_vector(options)
287
+ end
288
+
289
+ def growth_rate_over_kxy_gsl_vector(options)
290
+ Dir.chdir(@directory) do # i.e. phi2_by_ky_vs_time or phi2_by_kx_vs_time
291
+ kxy = options[:direction]
292
+ # ep :growth_rate_at_ + kxy
293
+ return GSL::Vector.alloc(send(:growth_rate_at_ + kxy).values)
294
+
295
+ end
296
+ end
297
+ private :growth_rate_over_kxy_gsl_vector
298
+
299
+ def es_heat_by_kx_over_time_gsl_vector(options)
300
+ options[:direction] = :kx
301
+ es_heat_by_kxy_over_time_gsl_vector(options)
302
+ end
303
+ def es_heat_by_ky_over_time_gsl_vector(options)
304
+ options[:direction] = :ky
305
+ es_heat_by_kxy_over_time_gsl_vector(options)
306
+ end
307
+
308
+ def es_heat_by_kxy_over_time_gsl_vector(options)
309
+ Dir.chdir(@directory) do
310
+ kxy = options[:direction]
311
+ kxy_index = kxy + :_index
312
+ options.convert_to_index(self, kxy)
313
+ if kxy==:ky
314
+ lkx = list(:kx)
315
+ es_heat_av = (lkx.keys.map do |kx_index|
316
+ es_heat = netcdf_file.var('es_heat_by_k').get({'start' => [kx_index-1,options[:ky_index]-1,options[:species_index]-1, 0], 'end' => [kx_index-1,options[:ky_index]-1,options[:species_index]-1, -1]})
317
+ #ep phi.shape
318
+ es_heat.reshape(*es_heat.shape.values_at(3))
319
+ end).sum / lkx.size
320
+ return es_heat_av.to_gslv
321
+ else
322
+ lky = list(:ky)
323
+ es_heat_av = (lky.keys.map do |ky_index|
324
+ es_heat = netcdf_file.var('es_heat_by_k').get({'start' => [options[:kx_index]-1,ky_index-1,options[:species_index]-1, 0], 'end' => [options[:kx_index]-1,ky_index-1,options[:species_index]-1, -1]})
325
+ #ep phi.shape
326
+ es_heat.reshape(*es_heat.shape.values_at(3))
327
+ end).sum / lky.size
328
+ return es_heat_av.to_gslv
329
+ end
330
+
331
+ end
332
+ end
333
+ private :es_heat_by_kxy_over_time_gsl_vector
334
+
335
+ def phi2_by_kx_over_time_gsl_vector(options)
336
+ options[:direction] = :kx
337
+ phi2_by_kxy_over_time_gsl_vector(options)
338
+ end
339
+ def phi2_by_ky_over_time_gsl_vector(options)
340
+ options[:direction] = :ky
341
+ phi2_by_kxy_over_time_gsl_vector(options)
342
+ end
343
+ def phi2_by_kxy_over_time_gsl_vector(options)
344
+ Dir.chdir(@directory) do
345
+ # i.e. phi2_by_ky_vs_time or phi2_by_kx_vs_time
346
+
347
+ kxy = options[:direction]
348
+ if list(kxy).size == 1
349
+ return phi2tot_over_time_gsl_vector(options)
350
+ end
351
+ kxy_index = kxy + :_index
352
+
353
+
354
+ #Necessary options: :ky or :kx
355
+ #Optional options: :t_index_window
356
+ # eputs "got here"
357
+ #options[:begin_element], options[:end_element] = (options[:t_index_window] ? options[:t_index_window].map{|ind| ind -1} : [0, -1])
358
+ phi_t_array=nil
359
+ if @grid_option == "single"
360
+ phi_t_array = netcdf_file.var('phi2').get('start' => [options[:begin_element]], 'end' => [options[:end_element]]).to_a.flatten
361
+ else
362
+ # value = options[:ky]
363
+ # eputs value
364
+ # get_list_of(:ky)
365
+ # index = @ky_list.find{|index,val| (val-value).abs < Float::EPSILON}[0]
366
+ # ep options
367
+ options.convert_to_index(self, kxy)
368
+ #ep options
369
+ phi_t_array = netcdf_file.var("phi2_by_#{kxy}").get('start' => [options[kxy_index] - 1, options[:begin_element]], 'end' => [options[kxy_index] - 1, options[:end_element]]).to_a.flatten
370
+ # eputs 'phi_t_array.size', phi_t_array.size
371
+ end
372
+ return GSL::Vector.alloc(phi_t_array)
373
+
374
+ end
375
+ end
376
+ private :phi2_by_kxy_over_time_gsl_vector
377
+
378
+
379
+ def phi2_by_mode_over_time_gsl_vector(options)
380
+ Dir.chdir(@directory) do #Necessary options: :ky and :kx
381
+ #Optional options: :t_index_window
382
+ # eputs "got here"
383
+ #options[:begin_element], options[:end_element] = (options[:t_index_window] ? options[:t_index_window].map{|ind| ind -1} : [0, -1])
384
+ options.setup_time_window
385
+ phi_t_array=nil
386
+ if @grid_option == "single"
387
+ phi_t_array = netcdf_file.var('phi2').get('start' => [options[:begin_element]], 'end' => [options[:end_element]]).to_a.flatten
388
+ else
389
+ # value = options[:ky]
390
+ # eputs value
391
+ # get_list_of(:ky)
392
+ # index = @ky_list.find{|index,val| (val-value).abs < Float::EPSILON}[0]
393
+ options.convert_to_index(self, :kx, :ky)
394
+ # p options
395
+ phi_t_array = netcdf_file.var("phi2_by_mode").get('start' => [options[:kx_index] - 1, options[:ky_index] - 1, options[:begin_element]], 'end' => [options[:kx_index] - 1, options[:ky_index] - 1, options[:end_element]]).to_a.flatten
396
+ # eputs 'phi_t_array.size', phi_t_array.size
397
+ end
398
+ return GSL::Vector.alloc(phi_t_array)
399
+
400
+ end
401
+ end
402
+
403
+ def phi0_by_kx_by_ky_over_time_gsl_vector(options)
404
+ Dir.chdir(@directory) do
405
+ options.convert_to_index(self, :kx, :ky)
406
+ phi0_array = netcdf_file.var('phi0').get.to_a.map{|arr| arr[options[:kx_index] - 1][options[:ky_index] - 1][options[:ri]]}
407
+ return GSL::Vector.alloc(phi0_array)
408
+
409
+ end
410
+ end
411
+
412
+ def linked_kx_elements_gsl_vector(options)
413
+ Dir.chdir(@directory) do
414
+ return GSL::Vector.alloc([0]) if @grid_option == "single" or agk?
415
+ if agk? or (@s_hat_input or @shat).abs < 1.0e-5
416
+ #p 'op1', options
417
+ options.convert_to_index(self, :ky, :kx)
418
+ #p 'op2', options
419
+ #eputs "No Magnetic Shear"
420
+
421
+ # begin
422
+ # options.convert_to_index(:kx)
423
+ # rescue
424
+ # raise "Must specify kx or kx_index if no magnetics shear"
425
+ # end
426
+ # # theta0 = (options[:theta0] || 0)
427
+ # # theta0 += jump(options) if @g_exb
428
+
429
+ #theta0 = (options[:kx_index])
430
+ #if @g_exb and @g_exb.abs > 0.0
431
+ #theta0 += jump(options)
432
+ #theta0 = theta0%((list(:kx).size-1)/2) if list(:kx).size > 1
433
+ #end
434
+
435
+ return GSL::Vector.alloc([options[:kx_index] - 1])
436
+ end
437
+
438
+ options.convert_to_index(self, :ky, :kx)
439
+ nkx = netcdf_file.var('kx').dims[0].length
440
+ # p nkx
441
+ stride = @jtwist * (options[:ky_index] - 1)
442
+ #stride = 3
443
+ nlinks = [(nkx / stride).floor, 1].max
444
+ theta0 = options[:kx_index] % @jtwist #(options[:theta0] || 0)
445
+ log 'stride', stride, 'nlinks', nlinks, 'theta0', theta0
446
+ #if @g_exb and @jtwist > 1 #and options[:t_index]
447
+ # kx_shift = list(:ky)[options[:ky_index]] * @g_exb
448
+ # p list(:t)[options[:t_index]], options[:t_index], kx_shift
449
+
450
+ # kx_shift *= list(:t)[(options[:t_index] or list(:t).keys.max)]
451
+ # jump = (kx_shift / list(:kx)[2]).round
452
+ #theta0 += (@jtwist - jump(options) % @jtwist) % @jtwist
453
+
454
+ # else
455
+ # jump = 0
456
+ #end
457
+ ep 'stride', stride, 'nlinks', nlinks, 'theta0', theta0
458
+ p GSL::Vector.indgen(nlinks / 2, nkx + theta0 - nlinks / 2 * stride, stride).connect(GSL::Vector.indgen(nlinks / 2, theta0, stride)).reverse
459
+ #return [7,5,3,1,34].to_gslv
460
+ return GSL::Vector.alloc([theta0 % jtwist]) if nlinks ==1
461
+ return GSL::Vector.indgen(nlinks / 2, nkx + theta0 - nlinks / 2 * stride, stride).connect(GSL::Vector.indgen(nlinks / 2, theta0, stride)).reverse
462
+
463
+ end
464
+ end
465
+
466
+ def spectrum_over_kpar_gsl_vector(options)
467
+ Dir.chdir(@directory) do
468
+ # , /kpar_spectrum/
469
+ #ep 'zero?', (@s_hat_input||@shat)==0.0
470
+ unless (@s_hat_input||@shat||0.75).abs<1.0e-5
471
+ phi = gsl_vector_complex('phi_along_field_line', options)
472
+ #i = 0
473
+ #phi = phi.collect{|re,im|
474
+ #i+=1; GSL::Complex.alloc(Math.sin(0.1*i), Math.cos(0.1*i))+
475
+ #GSL::Complex.alloc(Math.sin(0.4*i), Math.cos(0.4*i))
476
+
477
+ #}
478
+ ##GraphKit.quick_create([phi.square]).gnuplot
479
+ phi_k = phi.forward
480
+ phi_kr = phi_k.square
481
+ case phi_kr.size%2
482
+ when 0
483
+ spec = phi_kr.subvector((phi_kr.size+2)/2, (phi_kr.size-2)/2).connect(phi_kr.subvector(0, (phi_kr.size+2)/2))
484
+ when 1
485
+ spec = phi_kr.subvector((phi_kr.size + 1)/2, (phi_kr.size-1)/2).connect(phi_kr.subvector(0, (phi_kr.size+1)/2))
486
+ end
487
+ ##spec = phi_kr
488
+ #ep 'spec.class', spec.class
489
+ return spec
490
+ else
491
+
492
+ gm = gsl_matrix('spectrum_over_ky_over_kpar', options)
493
+ vec = GSL::Vector.alloc(gm.shape[1])
494
+ vec.set_all(0.0)
495
+ for ky_element in 0...gm.shape[0]
496
+ vec+= gm.row(ky_element)
497
+ end
498
+ vec = vec/gm.shape[0]
499
+ return vec
500
+ end
501
+ end
502
+ end
503
+ def kpar_gsl_vector(options)
504
+
505
+ Dir.chdir(@directory) do
506
+ if agk? or (@s_hat_input||@shat).abs < 1.0e-5
507
+ dk = 1
508
+ phi = list(:theta).values
509
+ else
510
+ kxe = gsl_vector('linked_kx_elements', options)
511
+ dk = 1.0/kxe.size
512
+ phi = gsl_vector_complex('phi_along_field_line', options)
513
+ end
514
+ case phi.size%2
515
+ when 0
516
+ kpar = GSL::Vector.indgen(phi.size, -(phi.size-2)/2)*dk
517
+ when 1
518
+ kpar = GSL::Vector.indgen(phi.size, -(phi.size-1)/2)*dk
519
+ end
520
+
521
+ #ep 'kpar.class', kpar.class
522
+ return kpar
523
+
524
+ end
525
+ end
526
+
527
+ def phi_along_field_line_gsl_vector(options)
528
+ Dir.chdir(@directory) do
529
+ complex_phi_vector= gsl_vector_complex('phi_along_field_line', options)
530
+ case options[:imrc]
531
+ when :im
532
+ phi_vector = complex_phi_vector.imag
533
+ when :mag
534
+ mag = true
535
+ phi_vector = complex_phi_vector.abs2
536
+ when :corr
537
+ thetas = gsl_vector('theta_along_field_line', options)
538
+ min = thetas.abs.to_a.index(thetas.abs.min)
539
+ at_0 = complex_phi_vector[min]
540
+ # ep at_0.class
541
+ phi_vector = (complex_phi_vector * (at_0 / at_0.mag).conj).real
542
+ # gsl_complex('correcting_phase', options)).real
543
+ when :real
544
+ phi_vector = complex_phi_vector.real
545
+ else
546
+ raise CRError.new("options[:imrc] was: #{options[:irmc]}")
547
+ end
548
+ phi_vector *= -1.0 if options[:flip]
549
+ (phi_vector /= phi_vector.abs.max; phi_vector *= (options[:height] || 1.0)) if options[:norm]
550
+ phi_vector = phi_vector.reverse if options[:rev]
551
+ return phi_vector
552
+
553
+ end
554
+ end
555
+
556
+ def theta_along_field_line_gsl_vector(options)
557
+ Dir.chdir(@directory) do
558
+ case @grid_option
559
+ when "single"
560
+ theta_vector = gsl_vector(:theta)
561
+ when "box"
562
+ #eputs "Start theta_along_field_line"
563
+ kx_elements = gsl_vector('linked_kx_elements', options).to_a
564
+ ep 'kx_elements', kx_elements.to_a
565
+ # ep list(:kx).keys.max
566
+ # ep kx_elements[0], list(:kx)[(kx_elements[0] + 1).to_i]
567
+ # ep kx_elements[-1], list(:kx)[(kx_elements[-1] + 1).to_i]
568
+ thetas = gsl_vector(:theta)
569
+ # ep thetas
570
+ #eputs "End theta_along_field_line"
571
+ return thetas if agk? or (@s_hat_input or @shat).abs < 1.0e-5
572
+ theta_list = (kx_elements.map do |element|
573
+
574
+ kx = list(:kx)[(element + 1).to_i]
575
+ # ep element
576
+ #ep 'kx', kx, 'shat', (@s_hat_input or @shat), 'ky', list(:ky)[options[:ky_index]]
577
+ thetas - 1.0 / (@s_hat_input or @shat) / list(:ky)[options[:ky_index]] * kx
578
+ end).inject{|old, new| old.connect(new)}
579
+ # thetas = gsl_vector(:theta) - 1.0 / @shat / list(:ky)[options[:ky_index]] * list(:kx)[(kx_elements[0] + 1).to_i] #- Math::PI*(kx_elements.size - 1)
580
+ # get_list_of(:ky, :t)
581
+ # if @g_exb #and options[:t_index]
582
+
583
+ if options[:moving]
584
+ theta_list = theta_list - Math::PI * 2.0 * (jump(options) / @jtwist)
585
+ else
586
+ # ep 'jump % jtwist is!!', jump(options) % @jtwist
587
+ theta_list = theta_list - Math::PI * 2.0 / @nx.to_f * ((jump(options) % @jtwist).to_f / @jtwist.to_f)
588
+ end
589
+ # jump = 0
590
+ # end
591
+ # theta_list = thetas.dup #gsl_vector(:theta) - Math::PI*kx_elements.size
592
+ # (kx_elements.size - 1).times do
593
+ # thetas = thetas + Math::PI * 2.0
594
+ # theta_list = theta_list.connect(thetas)
595
+ # end
596
+ # pp theta_list.to_a.values_at(0, theta_list.size - 1)
597
+ # pp theta_list.to_a.max
598
+ theta_vector = theta_list
599
+ end
600
+ # theta_vector = theta_vector.reverse if options[:rev]
601
+ theta_vector *= (@shat) if options[:z]
602
+ return theta_vector
603
+
604
+ end
605
+ end
606
+
607
+ def phi_for_eab_movie_gsl_vector(options)
608
+ Dir.chdir(@directory) do #options required are x_index, y_index and tm_index (Time)
609
+ mvf_name = @run_name + '.movie.nc'
610
+ raise CRError.new("cannot find file #{mvf_name}") unless FileTest.exist? mvf_name
611
+ ncf = NumRu::NetCDF.open(mvf_name)
612
+ # p ncf.var('phi_by_xmode').get.to_a[0][0][0]
613
+ return GSL::Vector.alloc(ncf.var('phi_by_xmode').get.to_a[options[:tm_index] - 1].map{|xy_arr| xy_arr[options[:x_index] - 1][options[:y_index] - 1]})
614
+
615
+ end
616
+ end
617
+
618
+ def hflux_tot_over_time_gsl_vector(options)
619
+ Dir.chdir(@directory) do
620
+ options.setup_time_window
621
+ narr = netcdf_file.var('hflux_tot').get('start' => [options[:begin_element]], 'end' => [options[:end_element]])
622
+ #eputs 'Got narr'
623
+ #ep 'hflux_tot', hflux
624
+ #eputs "fixing norm"
625
+ return fix_heat_flux_norm(GSL::Vector.alloc(narr.to_a), options)
626
+ end
627
+ end
628
+ alias :hflux_tot_gsl_vector :hflux_tot_over_time_gsl_vector
629
+ def es_heat_flux_over_time_gsl_vector(options)
630
+ Dir.chdir(@directory) do
631
+
632
+ options.setup_time_window
633
+ return GSL::Vector.alloc(netcdf_file.var('es_heat_flux').get('start' => [options[:species_index].to_i - 1, options[:begin_element]], 'end' => [options[:species_index].to_i - 1, options[:end_element]]).to_a.flatten)
634
+ end
635
+ end
636
+ def es_mom_flux_over_time_gsl_vector(options)
637
+ Dir.chdir(@directory) do
638
+
639
+ options.setup_time_window
640
+ return GSL::Vector.alloc(netcdf_file.var('es_mom_flux').get('start' => [options[:species_index].to_i - 1, options[:begin_element]], 'end' => [options[:species_index].to_i - 1, options[:end_element]]).to_a.flatten)
641
+ end
642
+ end
643
+ # Velocity space diagnostics: fraction of dist func in higher
644
+ # pitch angle harmonics
645
+ def lpc_pitch_angle_gsl_vector(options)
646
+ raise "Velocity space lpc diagnostics not found" unless FileTest.exist? "#@directory/#@run_name.lpc"
647
+ lpc = GSL::Vector.filescan("#@directory/#@run_name.lpc")
648
+ return lpc[1]
649
+ end
650
+ # Velocity space diagnostics: fraction of dist func in higher
651
+ # energy harmonics
652
+ def lpc_energy_gsl_vector(options)
653
+ raise "Velocity space lpc diagnostics not found" unless FileTest.exist? "#@directory/#@run_name.lpc"
654
+ lpc = GSL::Vector.filescan("#@directory/#@run_name.lpc")
655
+ return lpc[2]
656
+ end
657
+ # Velocity space diagnostics: integral error due to
658
+ # pitch angle resolution
659
+ def vres_pitch_angle_gsl_vector(options)
660
+ raise "Velocity space vres diagnostics not found" unless FileTest.exist? "#@directory/#@run_name.vres"
661
+ vres = GSL::Vector.filescan("#@directory/#@run_name.vres")
662
+ return vres[1]
663
+ end
664
+ # Velocity space diagnostics: integral error due to
665
+ # energy resolution
666
+ def vres_energy_gsl_vector(options)
667
+ raise "Velocity space vres diagnostics not found" unless FileTest.exist? "#@directory/#@run_name.vres"
668
+ vres = GSL::Vector.filescan("#@directory/#@run_name.vres")
669
+ return vres[2]
670
+ end
671
+ def par_mom_flux_over_time_gsl_vector(options)
672
+ Dir.chdir(@directory) do
673
+
674
+ options.setup_time_window
675
+ # This is a hack... one day some one will put it in the NetCDF file (haha).
676
+ momlines = `grep parmom #@run_name.out`
677
+ mom = []
678
+ momlines.scan(Regexp.new("#{LongRegexen::FLOAT.to_s}$")) do
679
+ mom.push $~[:float].to_f
680
+ end
681
+ options[:end_element] = (mom.size + options[:end_element]) if options[:end_element] < 0
682
+ # p options
683
+ return GSL::Vector.alloc(mom).subvector(options[:begin_element], options[:end_element] - options[:begin_element] + 1)
684
+ end
685
+ end
686
+
687
+ def perp_mom_flux_over_time_gsl_vector(options)
688
+
689
+ Dir.chdir(@directory) do
690
+ options.setup_time_window
691
+ # This is a hack... one day some one will put it in the NetCDF file (haha).
692
+ momlines = `grep perpmom #@run_name.out`
693
+ mom = []
694
+ momlines.scan(Regexp.new("#{LongRegexen::FLOAT.to_s}$")) do
695
+ mom.push $~[:float].to_f
696
+ end
697
+ options[:end_element] = (mom.size + options[:end_element]) if options[:end_element] < 0
698
+ # p options
699
+ return GSL::Vector.alloc(mom).subvector(options[:begin_element], options[:end_element] - options[:begin_element] + 1)
700
+ end
701
+ end
702
+
703
+ def scan_parameter_value_gsl_vector(options)
704
+ return GSL::Vector.alloc(netcdf_file.var('scan_parameter_value').get.to_a)
705
+ end
706
+ def spectrum_over_kx_gsl_vector(options)
707
+ options[:direction] = :kx
708
+ spectrum_over_kxy_gsl_vector(options)
709
+ end
710
+ def spectrum_over_ky_gsl_vector(options)
711
+ options[:direction] = :ky
712
+ spectrum_over_kxy_gsl_vector(options)
713
+ end
714
+ def spectrum_over_kxy_gsl_vector(options)
715
+ Dir.chdir(@directory) do
716
+ # i.e. spectrum_over_ky or spectrum_over_kx
717
+ kxy = options[:direction]
718
+ # eputs options[:t_index]
719
+ raise "Spectrum makes no sense for single modes" if @grid_option == "single"
720
+
721
+ options.convert_to_index(:t) if options[:t] or options[:t_element]
722
+ # eputs options[:t_index]
723
+
724
+ options[:t_index] ||= list(:t).keys.max
725
+ # eputs options[:t_index]
726
+ phi_array = netcdf_file.var("phi2_by_#{kxy}").get('start' => [0, options[:t_index] - 1], 'end' => [-1, options[:t_index] - 1]).to_a.flatten
727
+ v = GSL::Vector.alloc(phi_array)
728
+ v = v.from_box_order if kxy == :kx
729
+ v = v.mul(gsl_vector(kxy).square) unless options[:phi2_only]
730
+ return v
731
+ end
732
+ end
733
+ def x_gsl_vector(options)
734
+ kx = gsl_vector(:kx)
735
+ lx = 2*Math::PI/kx.to_box_order[1]
736
+ nx = options[:nakx]||kx.size
737
+ GSL::Vector.indgen(nx, 0, lx/nx)
738
+ end
739
+ def y_gsl_vector(options)
740
+ ky = gsl_vector(:ky)
741
+ ly = 2*Math::PI/ky[1]
742
+ ny = options[:naky]||ky.size
743
+ ysize = ny*2-2+ny%2
744
+ GSL::Vector.indgen(ysize, 0, ly/ysize)
745
+ end
746
+ def zonal_spectrum_gsl_vector(options)
747
+ Dir.chdir(@directory) do
748
+
749
+ gmzf = gsl_matrix('spectrum_over_ky_over_kx',options)
750
+ veczf = GSL::Vector.alloc(gmzf.shape[1])
751
+ # p gmzf.get_row(0).size
752
+ # p gmzf.get_row(0)
753
+ gmzf.shape[1].times{|i| veczf[i] = gmzf[0,i]}
754
+ return veczf
755
+ #else
756
+ #raise CRError.new("Unknown gsl_vector requested: #{name}")
757
+ end
758
+ # eputs data; gets
759
+ end
760
+
761
+ end # module GSLVectors
762
+ include GSLVectors
763
+
764
+ def gsl_vector_complex(name, options={})
765
+ options = eval(options) if options.class == String
766
+
767
+ if method = self.class.instance_methods.find{|meth| (name + '_gsl_vector_complex').to_sym == meth}
768
+ options[:graphkit_name] = name
769
+ return send(method, options)
770
+ end
771
+ end
772
+
773
+ module GSLVectorComplexes
774
+
775
+ def phi_along_field_line_gsl_vector_complex(options)
776
+ Dir.chdir(@directory) do
777
+ # eputs options[:ky]
778
+ # eputs Dir.pwd
779
+ #eputs "Start phi_along_field_line"
780
+ options.convert_to_index(self, :ky)
781
+ if options[:t_index] or options[:t]
782
+ #extra option required is t_index
783
+ raise CRFatal.new("write_phi_over_time is not enabled so this function won't work") unless @write_phi_over_time
784
+
785
+ options.convert_to_index(self, :t)
786
+ case @grid_option
787
+ when "single"
788
+ temp = GSL::Vector.alloc(netcdf_file.var('phi_t').get({'start' => [0,0,0,0, options[:t_index] - 1], 'end' => [-1,-1,0,0, options[:t_index] - 1]}).to_a[0][0][0].flatten)
789
+ when "box"
790
+ options.convert_to_index(self, :ky, :kx)
791
+ kx_elements = gsl_vector('linked_kx_elements', options).to_a
792
+ # pp kx_elements
793
+ a = netcdf_file.var('phi_t').get({
794
+ 'start' => [0,0,0,options[:ky_index] - 1, options[:t_index] - 1],
795
+ 'end' => [-1,-1,-1, options[:ky_index] - 1, options[:t_index] - 1]
796
+ }).to_a[0][0].values_at(*kx_elements).flatten
797
+ # pp a.index(nil)
798
+ # temp = GSL::Vector.alloc(netcdf_file.var('phi').get.to_a[options[:ky_index] - 1 ].values_at(*kx_elements).flatten)
799
+ #ep a
800
+ temp = GSL::Vector.alloc(a)
801
+ end
802
+
803
+ #eputs "End phi_along_field_line"
804
+ return GSL::Vector::Complex.alloc(temp.subvector_with_stride(0, 2), temp.subvector_with_stride(1, 2))
805
+ else
806
+ case @grid_option
807
+ when "single"
808
+ temp = GSL::Vector.alloc(netcdf_file.var('phi').get({'start' => [0,0, 0, 0], 'end' => [-1,-1,0,0]}).to_a.flatten)
809
+ when "box"
810
+ ep 'kx_elements', kx_elements = gsl_vector('linked_kx_elements', options).to_a
811
+ a = netcdf_file.var('phi').get({'start' => [0, 0, 0, options[:ky_index] - 1], 'end' => [-1, -1, -1, options[:ky_index] - 1]})
812
+ temp = GSL::Vector.alloc(a.to_a[0].values_at(*kx_elements).flatten)
813
+ end
814
+ vector = GSL::Vector::Complex.alloc(temp.subvector_with_stride(0, 2), temp.subvector_with_stride(1, 2))
815
+ #ep 'vector', vector.real
816
+ return vector
817
+ end
818
+ end
819
+ # eputs data; gets
820
+ end
821
+
822
+ end
823
+ include GSLVectorComplexes
824
+
825
+ def gsl_matrix(name, options={})
826
+ options = eval(options) if options.class == String
827
+ if options[:saturated_time_average] or options[:sta]
828
+ raise "Not Saturated" unless @saturation_time_index
829
+ tmax = list(:t).keys.max
830
+ return ((@saturation_time_index..tmax).to_a.map do |t_index|
831
+ gsl_matrix(name, options.dup.absorb({t_index: t_index, saturated_time_average: nil, sta: nil}))
832
+ end).sum / (list(:t).values.max - list(:t)[@saturation_time_index])
833
+ end
834
+ if method = self.class.instance_methods.find{|meth| (name + '_gsl_matrix').to_sym == meth}
835
+ options[:graphkit_name] = name
836
+ return send(method, options)
837
+ end
838
+ end
839
+
840
+ module GSLMatrices
841
+ def growth_rate_over_ky_over_kx_gsl_matrix(options)
842
+ array = @growth_rate_at_ky_at_kx.values.map{|h| h.values}
843
+ return GSL::Matrix.alloc(array.flatten, array.size, array[0].size)
844
+ end
845
+ def transient_amplification_over_ky_over_kx_gsl_matrix(options)
846
+ array = @transient_amplification_at_ky_at_kx.values.map{|h| h.values}
847
+ return GSL::Matrix.alloc(array.flatten, array.size, array[0].size)
848
+ end
849
+ def es_heat_flux_over_ky_over_kx_gsl_matrix(options)
850
+ Dir.chdir(@directory) do
851
+ raise "Heat flux spectrum makes no sense for single modes" if @grid_option == "single"
852
+ options.convert_to_index(:t) if options[:t] or options[:t_element]
853
+ options[:t_index] ||= list(:t).keys.max
854
+ #es_heat_by_k index order (in Fortran) is kx, ky, t
855
+ es_heat_narray = netcdf_file.var("es_heat_by_k").get('start' => [0, 0, 0, options[:t_index] - 1], 'end' => [-1, -1, 0, options[:t_index] - 1])
856
+ es_heat_narray.reshape!(*es_heat_narray.shape.slice(0..1))
857
+
858
+ gm = es_heat_narray.to_gm.move_cols_from_box_order
859
+ if options[:limit]
860
+ for i in 0...gm.shape[0]
861
+ for j in 0...gm.shape[1]
862
+ # j+= extra if
863
+ gm[i, j] = [[gm[i,j], (options[:limit][0] or gm[i,j])].max, (options[:limit][1] or gm[i,j])].min
864
+ # mat[i, j+extra] = gm[i,-j] unless j==0
865
+ end
866
+ end
867
+ end
868
+ return gm
869
+ end
870
+ end
871
+ def spectrum_over_ky_over_kx_gsl_matrix(options)
872
+ Dir.chdir(@directory) do
873
+ raise "Spectrum makes no sense for single modes" if @grid_option == "single"
874
+ options.convert_to_index(:t) if options[:t] or options[:t_element]
875
+ options[:t_index] ||= list(:t).keys.max
876
+ #phi2_by_mode index order (in Fortran) is kx, ky, t
877
+ phi_narray = netcdf_file.var("phi2_by_mode").get('start' => [0, 0, options[:t_index] - 1], 'end' => [-1, -1, options[:t_index] - 1])
878
+ phi_narray.reshape!(*phi_narray.shape.slice(0..1))
879
+
880
+ gm = phi_narray.to_gm.move_cols_from_box_order
881
+ if options[:times_kx4] or options[:times_kx2]
882
+ # puts 'normalising'
883
+ vals = list(:kx).values.sort
884
+ for i in 0...gm.shape[0]
885
+ for j in 0...gm.shape[1]
886
+ # p vals[j]
887
+ gm[i,j] = gm[i,j] * (vals[j])**4 if options[:times_kx4]
888
+ gm[i,j] = gm[i,j] * (vals[j])**2 if options[:times_kx2]
889
+ end
890
+ end
891
+ end
892
+ if options[:no_zonal]
893
+
894
+ for i in 0...gm.shape[1]
895
+ gm[0,i] = 0.0
896
+ end
897
+ end
898
+ if options[:log]
899
+ gm = gm.log
900
+ end
901
+
902
+ return gm
903
+ end
904
+ end
905
+ def spectrum_over_ky_over_kpar_gsl_matrix(options)
906
+ Dir.chdir(@directory) do
907
+
908
+ #:re, :theta, :kx, :ky
909
+ lkx = list(:kx)
910
+
911
+ if options[:t_index] or options[:t]
912
+ #extra option required is t_index
913
+ raise CRFatal.new("write_phi_over_time is not enabled so this function won't work") unless @write_phi_over_time
914
+ options.convert_to_index(self, :t)
915
+ end
916
+ temp = phi_av = (lkx.keys.map do |kx_index|
917
+ if options[:t_index]
918
+ phi = netcdf_file.var('phi_t').get({'start' => [0,0,kx_index-1,0, options[:t_index] - 1], 'end' => [-1,-1,kx_index-1,-1, options[:t_index] - 1]})
919
+ else
920
+ phi = netcdf_file.var('phi').get({'start' => [0, 0, kx_index - 1, 0], 'end' => [-1, -1, kx_index-1, -1]})
921
+ end
922
+ #ep phi.shape
923
+ phi.reshape(*phi.shape.values_at(0,1,3))
924
+ end).sum / lkx.size
925
+
926
+ phi_t = phi_av.to_a #.map{|arr| arr.transpose}.transpose.map{|a| a.transpose}
927
+ #ep 'phi_t', phi_t.size, phi_t[0].size, phi_t[0][0].size
928
+ gvky = gsl_vector('ky')
929
+ gm = GSL::Matrix.alloc(gvky.size, gsl_vector('theta').size)
930
+ for ky_element in 0...gm.shape[0]
931
+ #p phi_t[ky_element].transpose[0]
932
+ spectrum = GSL::Vector::Complex.alloc(phi_t[ky_element]).forward.square
933
+ if options[:no_kpar0]
934
+ spectrum[0]=0.0
935
+ end
936
+ spectrum = spectrum.from_box_order
937
+ #ep spectrum.shape
938
+ spectrum = spectrum*gvky[ky_element]**2 unless options[:phi2_only]
939
+ gm.set_row(ky_element, spectrum)
940
+ end
941
+ if options[:no_zonal]
942
+ gm.row(0).set_all(0.0)
943
+ end
944
+ if options[:log]
945
+ gm = gm.log
946
+ end
947
+
948
+ return gm
949
+ end
950
+ end
951
+
952
+ def phi0_over_x_over_y_gsl_matrix(options)
953
+ Dir.chdir(@directory) do
954
+
955
+ options.convert_to_index(:t) if options[:t] or options[:t_element]
956
+ options[:t_index] ||= list(:t).keys.max
957
+ #phi2_by_mode index order (in Fortran) is kx, ky, t
958
+ phi_re_narray = netcdf_file.var("phi0").get('start' => [0, 0, 0, options[:t_index] - 1], 'end' => [0, -1, -1, options[:t_index] - 1])
959
+ # ep phi_re_narray.shape
960
+ phi_re_narray.reshape!(*phi_re_narray.shape.slice(1..2))
961
+ # The narray has index order ky, kx, but we want kx, ky for historical reasons, hence the transpose.
962
+ gm_re = phi_re_narray.to_gm
963
+ phi_im_narray = netcdf_file.var("phi0").get('start' => [1, 0, 0, options[:t_index] - 1], 'end' => [1, -1, -1, options[:t_index] - 1])
964
+ phi_im_narray.reshape!(*phi_im_narray.shape.slice(1..2))
965
+ # The narray has index order ky, kx, but we want kx, ky for historical imasons, hence the transpose.
966
+ gm_im = phi_im_narray.to_gm
967
+ gm = GSL::Matrix::Complex.re_im(gm_re, gm_im)
968
+ # ep gm.shape
969
+
970
+ if options[:no_zonal]
971
+
972
+ for i in 0...gm.shape[1]
973
+ gm[0,i] = GSL::Complex.alloc([0,0])
974
+ end
975
+ end
976
+ if xres = (options[:xres] or options[:x_resolution])
977
+ mat = GSL::Matrix::Complex.calloc(gm.shape[0], xres)
978
+ extra = ((xres - gm.shape[1])).floor
979
+ for i in 0...gm.shape[0]
980
+ for j in 0...((gm.shape[1] + 1) / 2 )
981
+ # j+= extra if
982
+ mat[i, j] = gm[i,j]
983
+ mat[i, j+extra] = gm[i,-j] unless j==0
984
+ end
985
+ end
986
+ gm = mat
987
+
988
+
989
+ # gm = mat.vertcat(gm).vertcat(mat)
990
+ end
991
+ if yres = (options[:yres] or options[:y_resolution])
992
+ mat = GSL::Matrix::Complex.calloc(yres, gm.shape[1])
993
+ extra = ((yres - gm.shape[0])).floor
994
+ for i in 0...gm.shape[0]
995
+ for j in 0...gm.shape[1]
996
+ # j+= extra if
997
+ mat[i, j] = gm[i,j]
998
+ # mat[i, j+extra] = gm[i,-j] unless j==0
999
+ end
1000
+ end
1001
+ gm = mat
1002
+
1003
+
1004
+ # gm = mat.vertcat(gm).vertcat(mat)
1005
+ end
1006
+ # ep gm_re, gm_im
1007
+ # re = GSL::Complex.alloc([1.0, 0.0])
1008
+ # gm = GSL::Matrix::Complex.calloc(*gm_re.shape)
1009
+ # gm = gm_re * re + gm_im * GSL::Complex.alloc([0.0, 1.0])
1010
+ # gm_re, gm_im = fourier_transform_gm_matrix_complex_rows(gm_re, gm_im)
1011
+
1012
+ gm = gm.backward_cols_c2c(true).backward_rows_cc2r(true)
1013
+ if options[:limit]
1014
+ for i in 0...gm.shape[0]
1015
+ for j in 0...gm.shape[1]
1016
+ # j+= extra if
1017
+ gm[i, j] = [[gm[i,j], options[:limit][0]].max, options[:limit][1]].min
1018
+ # mat[i, j+extra] = gm[i,-j] unless j==0
1019
+ end
1020
+ end
1021
+ end
1022
+ return gm
1023
+ end
1024
+ end
1025
+ end
1026
+
1027
+ include GSLMatrices
1028
+
1029
+ def kx_shift(options)
1030
+ # ep options
1031
+ return 0 unless @g_exb and @g_exb.abs > 0.0
1032
+ #p options
1033
+ return - list(:ky)[options[:ky_index]] * list(:t)[(options[:t_index] or list(:t).keys.max)] * @g_exb
1034
+ end
1035
+
1036
+ def jump(options)
1037
+ # ep 'kx_shift', kx_shift(options)
1038
+ jump = ((kx_shift(options) / list(:kx)[2]).round)
1039
+ case options[:t_index]
1040
+ when 1
1041
+ return jump
1042
+ else
1043
+ if @g_exb and @g_exb.abs > 0
1044
+ return jump + 1
1045
+ else
1046
+ return 0
1047
+ end
1048
+ end
1049
+ end
1050
+
1051
+ # This function is used in the presence of perpendicular flow shear. It returns the (Eulerian) GS2
1052
+ # kx_index as a function of the Lagrangian kx, which is the kx_index of the mode in a shearing
1053
+ # coordinate system, I.e. if you give it an Lagrangian kx (which is the same as the Eulerian
1054
+ # kx at t=0) it will tell you where it has now got to. It may have left the box, in which case
1055
+ # this function will return an error.
1056
+ #
1057
+ # A given Lagrangian kx moves through the GS2 box, and thus for such a kx the response matrix varies
1058
+ # in time. This is done because the effect of flow shear can be reduced by a shearing coordinate
1059
+ # transformation to become merely a time varying kx.
1060
+ #
1061
+ # At each timestep, phi(ikx_indexed(it)) is set equal to phi(ikx_indexed(it - jump(iky))
1062
+ # kx_indexed is defined in the following way.
1063
+ # do it=itmin(1), ntheta0
1064
+ # ikx_indexed (it+1-itmin(1)) = it
1065
+ # end do
1066
+ #
1067
+ # do it=1,itmin(1)-1
1068
+ # ikx_indexed (ntheta0 - itmin(1) + 1 + it)= it
1069
+ # end do
1070
+ #
1071
+ # In other words, what this means is that akx(ikx_indexed(0)) is the minimum kx,
1072
+ # and that akx(ikx_indexed(ntheta0)) gives the maximum kx, kx_indexed moves the
1073
+ # kxs out of box order.
1074
+ #
1075
+ # So. remembering that jump is negative, phi(kx) is set equal phi(kx - jump * dkx)
1076
+ # so the Lagrangian mode has moved to a lower kx. So get the Eulerian index, one
1077
+ # starts with the Lagrangian index, and adds jump (which is negative!). This, however,
1078
+ # must be done with indexes that are in the physical (not box) order. So this function
1079
+ # first moves the indexes out of box order, then adds jump, then moves them back
1080
+ # into box order so that the index returned will give the correct kx from the GS2
1081
+ # array.
1082
+
1083
+ def eulerian_kx_index(options)
1084
+ #eputs "Start eulerian_kx_index"
1085
+ lagrangian_kx_index = options[:kx_index]
1086
+ phys = physical_kx_index(lagrangian_kx_index)
1087
+ #ep 'jump', jump(options)
1088
+ index = phys + jump(options)
1089
+ raise ArgumentError.new("Lagrangian kx out of range") if index <= 0
1090
+ box= box_kx_index(index)
1091
+ #eputs "End eulerian_kx_index"
1092
+ return box
1093
+ end
1094
+
1095
+ def kx_indexed
1096
+ return cache[:kx_indexed] if cache[:kx_indexed]
1097
+ #kx = cache[:kx_array] ||= gsl_vector('kx').to_a
1098
+ #kxphys = kx.from_box_order
1099
+ #min_index = kx.min_index + 1
1100
+ #cache[:kx_indexed] ||= kx.size.times.inject({}) do |hash, kx_element|
1101
+ #hash[kx_element + 1] = kxphs
1102
+ kx = gsl_vector('kx')
1103
+ size = kx.size
1104
+ box = GSL::Vector::Int.indgen(size) + 1
1105
+ zero_element = kx.abs.min_index
1106
+ phys = box.subvector(zero_element, size-zero_element).connect(box.subvector(0, zero_element))
1107
+ cache[:kx_indexed] = [phys.to_a, box.to_a].transpose.inject({}){|hash, (phys, box)| hash[phys] = box; hash}
1108
+ end
1109
+
1110
+ def box_kx_index(physical_kx_index)
1111
+
1112
+ return kx_indexed[physical_kx_index]
1113
+ end
1114
+
1115
+ def physical_kx_index(box_kx_index)
1116
+ return kx_indexed.key(box_kx_index)
1117
+ kx = cache[:kx_gslv] ||= gsl_vector('kx')
1118
+ return kx.from_box_order.to_a.index(kx[box_kx_index-1]) + 1
1119
+ #kx = cache[:kx_gslv] ||= gsl_vector('kx')
1120
+ #index_of_min_kx = cache[:index_of_min_kx] ||= kx.min_index + 1 # kx.min_index returns a 0-based index
1121
+ #if box_kx_index < index_of_min_kx
1122
+ #box_kx_index + (1 + kx.size - index_of_min_kx)
1123
+ #else
1124
+ #box_kx_index - (index_of_min_kx - 1)
1125
+ #end
1126
+ end
1127
+
1128
+
1129
+
1130
+
1131
+ def gsl_complex(name, options={})
1132
+ options = eval(options) if options.class == String
1133
+ # p @directory
1134
+ Dir.chdir(@directory) do
1135
+ # eputs Dir.pwd
1136
+ case name
1137
+ when /correcting_phase/
1138
+ # options.convert_to_index(self, :ky)
1139
+ # theta0 = (options[:theta0] or 0)
1140
+ # # p 'options[:ky_index]', options[:ky_index]
1141
+ # phase_array = NumRu::NetCDF.open("#@directory/#@run_name.out.nc").var('phase').get({"start" => [0, options[:ky_index] - 1, theta0], 'end' => [1, options[:ky_index] - 1, theta0] }).to_a.flatten
1142
+ # p 'phase_array', phase_array
1143
+ # thetaelement0 = (list(:theta).key(0.0) - 1).to_i
1144
+ # p 'list(:theta)[thetaelement0 + 1]', list(:theta)[thetaelement0 + 1]
1145
+ # p 'thetaelement0', thetaelement0
1146
+ # p 'theta0 - jump(options)', theta0 - jump(options) % @jtwist
1147
+ # p 'list(:kx)[2] * (theta0 - jump(options)%@jtwist)', list(:kx)[2] * (theta0 - jump(options)%@jtwist)
1148
+ # kx_element = list(:kx).key(list(:kx)[2] * (theta0 - jump(options)%@jtwist)) - 1
1149
+ # at_0 = NumRu::NetCDF.open("#@directory/#@run_name.out.nc").var('phi').get({"start" => [0, thetaelement0, kx_element, options[:ky_index] - 1], 'end' => [1, thetaelement0, kx_element, options[:ky_index] - 1] }).to_a.flatten
1150
+ # p 'at_0', at_0
1151
+ # at_0 = GSL::Complex.alloc(at_0)
1152
+ # p 'at_0', at_0
1153
+ # return (at_0 / at_0.mag).conj
1154
+ # # pp 'theta0', theta0
1155
+ # # pp phase_array[5][theta0]
1156
+ # return GSL::Complex.alloc(phase_array)
1157
+ # # new_options = options.dup
1158
+ # new_options[:imrc] = :real
1159
+ # thetas = gsl_vector('theta_along_field_line', new_options)
1160
+ # at_0 = gsl_vector_complex('phi_along_field_line', new_options)[.to_a.index(0.0)]
1161
+ # p at_0
1162
+ exit
1163
+ else
1164
+ raise CRError.new("Unknown gsl_complex requested: #{name}")
1165
+ end
1166
+ # eputs data; gets
1167
+ end
1168
+ end
1169
+
1170
+ # def gsl_matrix(name, options={})
1171
+ # if options[:t_index] or options[:frame_index]
1172
+ # return get_gsl_matrix(name, options)
1173
+ # else
1174
+ # return cache[[:gsl_vector, name, options]] ||= get_gsl_matrix(name, options)
1175
+ # end
1176
+ # end
1177
+
1178
+
1179
+
1180
+ end
1181
+ end