gs2crmod 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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,1899 @@
1
+
2
+
3
+ class CodeRunner
4
+ class Gs2
5
+
6
+ # for backwards compatibility, and because I'm lazy
7
+ # one day someone should get rid of this!
8
+ AxisKit = GraphKit::AxisKit
9
+ DataKit = GraphKit::DataKit
10
+
11
+ def auto_axiskits(name, options)
12
+ hash = cache[:auto_axiskits] ||= {'t' => ['Time', ''],
13
+ 'phi2tot_over_time' => ['Phi^2 Total', ''],
14
+ 'apar2_over_time' => ['Apar^2 Total', ''],
15
+ 'growth_rate_by_ky_over_time' => ['Growth Rate by ky', ''],
16
+ 'growth_rate_by_kx_over_time' => ['Growth Rate by ky', ''],
17
+ 'growth_rate_by_mode_over_time' => ["Growth Rate by mode", ''],
18
+ 'phi2_by_ky_over_time' => ['Phi^2 by ky', ''],
19
+ 'phi2_by_kx_over_time' => ['Phi^2 by ky', ''],
20
+ 'es_heat_by_ky_over_time' => ['Phi^2 by ky', ''],
21
+ 'es_heat_by_kx_over_time' => ['Phi^2 by ky', ''],
22
+ 'phi2_by_mode_over_time' => ["Phi^2 by mode", ''],
23
+ 'hflux_tot' => ['Total Heat Flux', ''],
24
+ 'ky' => ['ky', "1/rho_#{species_letter}"],
25
+ 'kx' => ['kx', "1/rho_#{species_letter}"],
26
+ 'kpar' => ['kpar', "2 pi/qR"],
27
+ 'growth_rate_over_kx' => ['Growth Rate', "v_th#{species_letter}/a", 1],
28
+ 'growth_rate_over_ky' => ['Growth Rate', "v_th#{species_letter}/a", 1],
29
+ 'transient_es_heat_flux_amplification_over_kx' => ['Transient Electrostatic Heat Amplification', "", 1],
30
+ 'transient_es_heat_flux_amplification_over_ky' => ['Transient Electrostatic Heat Amplification', "", 1],
31
+ 'transient_amplification_over_kx' => ['Transient Amplification', "", 1],
32
+ 'transient_amplification_over_ky' => ['Transient Amplification', "", 1],
33
+ 'spectrum_over_kx' => ["Spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 1],
34
+ 'zonal_spectrum' => ["Zonal spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 1],
35
+ 'spectrum_over_ky' => ["Spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 1],
36
+ 'growth_rate_over_ky_over_kx' => ["Growth Rate", "v_th#{species_letter}/a", 2],
37
+ 'es_heat_flux_over_ky_over_kx' => ["Heat flux at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 2],
38
+ 'spectrum_over_kpar' => ["Spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 1],
39
+ 'spectrum_over_ky_over_kx' => ["Spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 2],
40
+ 'spectrum_over_ky_over_kpar' => ["Spectrum at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 2],
41
+ 'phi0_over_x_over_y' => ["Phi at t = #{sprintf("%.3f" ,(options[:t] or list(:t)[options[:t_index]] or list(:t).values.max))}", '', 2],
42
+ 'es_mom_flux_over_time' => ["#{species_type((options[:species_index] or 1)).capitalize} Momentum Flux", '', 1]
43
+
44
+
45
+ }
46
+ return hash[name]
47
+ end
48
+
49
+ def axiskit(name, options={})
50
+ logf :axiskit
51
+ if info = auto_axiskits(name, options)
52
+ if info[2] and info[2] == 2
53
+ axis = GraphKit::AxisKit.autocreate({data: gsl_matrix(name, options), title: info[0], units: info[1]})
54
+ elsif !info[2] or info[2] == 1
55
+ axis = GraphKit::AxisKit.autocreate({data: gsl_vector(name, options), title: info[0], units: info[1]})
56
+ log 'successfully created axis'
57
+ end
58
+ return axis
59
+ end
60
+ case name
61
+ when 'phi_along_field_line'
62
+ title = options[:imrc].to_s.capitalize + " Phi"
63
+ units = ""
64
+ return GraphKit::AxisKit.autocreate(data: gsl_vector(name, options), title: title, units: units)
65
+ when 'theta_along_field_line'
66
+ title = options[:z] ? "z/l_B" : 'Theta'
67
+ units = options[:z] ? '' : 'radians'
68
+ return GraphKit::AxisKit.autocreate(data: gsl_vector(name, options), title: title, units: units)
69
+ when 'es_heat_flux'
70
+ type = species_type(options[:species_index]).capitalize
71
+ units = ''
72
+ return GraphKit::AxisKit.autocreate(data: gsl_vector('es_heat_flux', options), title: "#{type} Heat Flux", units: units)
73
+ # when 'spectrum_by_ky'
74
+ # return AxisKit.autocreate(data: gsl_vector('spectrum_by_ky', options), title: "Phi^2 at t = #{list(:t)[options[:t_index]]}", units: '')
75
+ end
76
+ raise CRError.new("Unknown axis kit: #{name}")
77
+ end
78
+
79
+ def self.cache
80
+ @cache ||= {}
81
+ @cache
82
+ end
83
+
84
+ def self.generate_graphs_rdoc_file
85
+ File.open('graphs_rdoc.rb', 'w') do |file|
86
+ graphs = self.instance_methods.find_all{|m| m.to_s =~ /_graphkit$/}.sort_by{|m| m.to_s}
87
+ run = new(nil)
88
+ file.puts "class #{self.to_s}::GraphKits\n"
89
+ graphs.each do |graph|
90
+ help = run.send(graph, command: :help)
91
+ options = run.send(graph, command: :options)
92
+ file.puts "# #{help}"
93
+ if options and options.size > 0
94
+ file.puts "# Options:"
95
+ options.each do |op|
96
+ file.puts "#\n# #{op}: #{GRAPHKIT_OPTIONS_HELP[op]}"
97
+ end
98
+ end
99
+ file.puts "def #{graph}\nend"
100
+ end
101
+ file.puts "end"
102
+ end
103
+ end
104
+ def self.help_graphs
105
+ # @@runner ||= CodeRunner.fetch_runner(U: true,
106
+ graphs = self.instance_methods.find_all{|m| m.to_s =~ /_graphkit$/}.sort_by{|m| m.to_s}
107
+ run = new(nil)
108
+ puts "-------------------------------------------\n Available Graphs For #{self.to_s}\n-------------------------------------------\n"
109
+ graphs.each do |graph|
110
+ help = run.send(graph, command: :help)
111
+ options = run.send(graph, command: :options)
112
+ puts "\n------------------------------------\n#{graph.to_s.sub(/_graphkit/, '')}\n------------------------------------\n\n#{help}"
113
+ if options and options.size > 0
114
+ puts "\n\tOptions:"
115
+ options.each do |op|
116
+ puts "\t\t#{op}: #{GRAPHKIT_OPTIONS_HELP[op]}"
117
+ end
118
+ end
119
+
120
+ end
121
+ end
122
+
123
+ GRAPHKIT_OPTIONS_HELP = {
124
+ t_index_window: "[begin, end], window of time indices to plot (e.g. t_index_window: [0,10])",
125
+ t_index: "integer, index of time at which to plot (e.g. t_index: 20)",
126
+ t: "float, value of time at which to plot (e.g. t: 2.45)",
127
+ ky_index: "integer, index of ky at which to plot (e.g. ky_index: 20)",
128
+ ky: "float, value of ky at which to plot (e.g. ky: 0.1)",
129
+ kx_index: "integer, index of kx at which to plot (e.g. kx_index: 20)",
130
+ kx: "float, value of kx at which to plot (e.g. kx: 0.1)",
131
+ with: "Gnuplot Option (may not apply when using other packages), e.g. with: 'lp' or with 'pm3d palette'",
132
+ rgbformulae: "Gnuplot Option (may not apply when using other packages), sets colour mapping. See gnuplot help set rgbformulae",
133
+ limit: "Limit the range of quantity begin plotted - any values of the quantity outside the limits will be set to the limit: eg. limit: [0,80]",
134
+ flip: 'Flip the y axis, e.g. flip: true',
135
+ rev: 'Reverse the x axis, e.g. rev: true',
136
+ z: 'Plot quantities vs z = theta/shat rather than theta. See Beer, Cowley Hammet 1996, eg. z: true',
137
+ norm: 'Normalise the graph so that its maximum is 1, e.g. norm: true',
138
+ mag: 'Plot the magnitude, e.g. mag: true',
139
+ species_index: "Which GS2 species to plot the graph for (1-based).",
140
+ strongest_non_zonal_mode: "Plot the graph requested for the mode with the highest value of phi^2. Overrides ky, kx, ky_index, kx_index. Can be set true or false; e.g. strongest_non_zonal_mode: true",
141
+ no_zonal: "Don't plot the ky=0 part (boolean, e.g. no_zonal: true)",
142
+ no_kpar0: "Don't plot the kpar=0 part (boolean, e.g. no_kpar0: true)",
143
+ log: "Plot the log of a given quantity (exact meaning varies). boolean",
144
+ Rmaj: "The major radius in metres. This has no effect on the shape of the graph: it merely multiplies every length",
145
+ n0: " The toroidal mode number of the longest y mode. In effect it is the number of periodic copies of the flux tube that will fit in the torus. Periodicity requires that n0 q is also an integer. If you specify :n0 where this is not the case, q will automatically be adjusted until it is",
146
+ rho_star: " The ratio of the reference Lamour radius to the GS2 normalising length a. Cannot be specified at the same time as n0. If specified, both n0 and q will be adjusted to ensure periodicity",
147
+ t_index: "The (1-based) time index",
148
+ nakx: "The number of radial wave numbers to include in the plot. In effect, it is a low pass filter which reduces the resolution in the radial direction without changing the shape of the final surface. Minimum value is 4",
149
+ naky: "The number of kys to include in the plot. In effect, it is a low pass filter which reduces the resolution in the y direction without changing the shape of the final surface. Minimum value is 4",
150
+ gs2_coordinate_factor: "When set to 1, plot the graph in GS2 coordinates. When set to 0 plot the graph in real space. Can be set at any value between 0 and 1: the graph will smoothly distort between the two limits",
151
+ xmax: "The (0-based) index of the maximum value of x to include in the plot",
152
+ xmin: "The (0-based) index of the minimum value of x to include in the plot",
153
+ ymax: "The (0-based) index of the maximum value of y to include in the plot",
154
+ ymin: "The (0-based) index of the minimum value of y to include in the plot",
155
+ thetamax: "The (0-based) index of the maximum value of theta to include in the plot",
156
+ thetamin: "The (0-based) index of the minimum value of theta to include in the plot",
157
+ ncopies: " The number of periodic copies of the flux tube to include",
158
+ torphi_values: "An array of two values of the toroidal angle. The graph will be plotted in between those two values with poloidal cross sections at either end",
159
+ magnify: " The magnification factor of the small section. It can take any value greater than or equal to 1",
160
+
161
+ }
162
+
163
+
164
+ # def graphkit(name, options={})
165
+ # unless [:Failed, :Complete].include? status
166
+ # return get_graphkit(name, options)
167
+ # else
168
+ # return cache[[:graphkit, name, options]] ||= get_graphkit(name, options)
169
+ # end
170
+ # end
171
+
172
+
173
+ def graphkit(name, options={})
174
+ logf :graphkit
175
+ # If an array of t, kx or ky values is provided, plot one graph for each value and then sum the graphs together
176
+ [:t, :kx, :ky].each do |var|
177
+ #ep 'index', var
178
+ if options[var].class == Symbol and options[var] == :all
179
+ options[var] = list(var).values
180
+ elsif options[var+:_index].class == Symbol and options[var+:_index] == :all
181
+ #ep 'Symbol'
182
+ options[var+:_index] = list(var).keys
183
+ end
184
+ if options[var].class == Array
185
+ return options[var].map{|value| graphkit(name, options.dup.absorb({var => value}))}.sum
186
+ elsif options[var+:_index].class == Array
187
+ #ep 'Array'
188
+ return options[var+:_index].map{|value| graphkit(name, options.dup.absorb({var+:_index => value}))}.sum
189
+ end
190
+ if options[var].class == Symbol and options[var] == :max
191
+ options[var] = list(var).values.max
192
+ elsif options[var+:_index].class == Symbol and options[var+:_index] == :max
193
+ ep 'Symbol'
194
+ options[var+:_index] = list(var).keys.max
195
+ end
196
+ end
197
+ options[:t_index] ||= options[:frame_index] if options[:frame_index]
198
+
199
+
200
+
201
+
202
+ # If a method from the new GraphKits module can generate this graphkit use it
203
+ #ep name + '_graphkit'
204
+ #ep self.class.instance_methods.find{|meth| (name + '_graphkit').to_sym == meth}
205
+
206
+ if method = self.class.instance_methods.find{|meth| (name + '_graphkit').to_sym == meth}
207
+ options[:graphkit_name] = name
208
+ return send(method, options)
209
+ end
210
+
211
+ raise "Graph #{name} not found"
212
+
213
+ end
214
+
215
+ module GraphKits
216
+
217
+ def apar2_by_mode_vs_time_graphkit(options={})
218
+ options[:direction] = :mode
219
+ apar2_by_kxy_or_mode_vs_time_graphkit(options)
220
+ end
221
+
222
+ def apar2_by_kx_vs_time_graphkit(options={})
223
+ options[:direction] = :kx
224
+ apar2_by_kxy_or_mode_vs_time_graphkit(options)
225
+ end
226
+
227
+ def apar2_by_ky_vs_time_graphkit(options={})
228
+ options[:direction] = :ky
229
+ apar2_by_kxy_or_mode_vs_time_graphkit(options)
230
+ end
231
+
232
+ def apar2_by_kxy_or_mode_vs_time_graphkit(options={})
233
+ case options[:command]
234
+ when :help
235
+ return "'apar2_by_ky_vs_time' or 'apar2_by_kx_vs_time' or 'apar2_by_mode_vs_time': Apar^2 over time for a given kx or ky, integrated over the other direction, or apar^2 vs time for a given kx and ky"
236
+ when :options
237
+ return [:ky, :ky_index, :kx, :kx_index]
238
+ else
239
+ kxy = options[:direction]
240
+
241
+ # i.e. apar2_by_ky_vs_time or apar2_by_kx_vs_time or apar2_by_mode_vs_time
242
+
243
+ nt_options = options.dup # 'no time' options
244
+ nt_options.delete(:t_index) if nt_options[:t_index]
245
+ nt_options.delete(:frame_index) if nt_options[:frame_index]
246
+ phiax = axiskit("apar2_by_#{kxy}_over_time", nt_options)
247
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: phiax})
248
+ kit.data[0].title = "Phi^2 total: #{kxy} = #{options[kxy]}"
249
+ if options[:t_index]
250
+ # p 'hello'
251
+ array_element = options[:t_index_window] ? options[:t_index] - options[:t_index_window][0] : options[:t_index] - 1
252
+ # p phiax.data.size, array_element
253
+ # p options[:t_index], options[:t_index_window]
254
+ time = DataKit.autocreate({x: {data: GSL::Vector.alloc([list(:t)[options[:t_index]]])}, y: {data: GSL::Vector.alloc([phiax.data[array_element]]) } })
255
+ time.pointsize = 3.0
256
+ # p time
257
+ # kit.data[0].axes[:x].data = -kit.data[0].axes[:x].data
258
+ kit.data.push time
259
+ if options[:with_moving_efn] and kxy==:ky
260
+ tmax = kit.data[0].axes[:x].data[-1]
261
+ # p 'tmax', tmax
262
+
263
+ theta_max = @g_exb * tmax * options[:ky] * 2 * Math::PI / list(:kx)[2]
264
+ kit.each_axiskit(:x) do |axiskit|
265
+ # p axiskit
266
+ axiskit.data = axiskit.data / tmax * theta_max - theta_max
267
+ end
268
+ end
269
+ end
270
+ if options[:norm]
271
+ xrange, yrange = kit.plot_area_size
272
+ kit.each_axiskit(:y) do |axiskit|
273
+ axiskit.data /= yrange[1] / (options[:height] or 1.0)
274
+ end
275
+ end
276
+ kit.log_axis = 'y'
277
+ #kit.data[0].title = "gs2:#@run_name"
278
+ kit.data[0].with = "l" #"linespoints"
279
+ kit.file_name = options[:graphkit_name]
280
+ kit
281
+ end
282
+ end
283
+ def efnim_graphkit(options={})
284
+ options[:imrc] = :im
285
+ efn_graphkit(options)
286
+ end
287
+
288
+
289
+ def efnmag_graphkit(options={})
290
+ options[:imrc] = :mag
291
+ efn_graphkit(options)
292
+ end
293
+
294
+ def efn_graphkit(options={})
295
+ case options[:command]
296
+ when :help
297
+ return "Plot the eigenfunction along the extended domain. Options mag, norm, z can be specified by using a short hand in the name of the graph, eg. efnmagnormz, efnmag, efnnorm etc. If the range is set to 0, it plots the whole eigenfunction. Otherwise it plot a small bit of it. Only specify kx or kx_index if magnetic shear is 0."
298
+ when :options
299
+ return [:mag, :norm, :z, :flip, :range, :kx_index, :ky_index, :kx, :ky, :strongest_non_zonal_mode]
300
+ when :plot, nil
301
+ eputs "Starting efn, this can take a while..."
302
+ options[:imrc] ||= :real
303
+ ep options
304
+ options.convert_to_index(self, :ky)
305
+ #ep 'converted options: ', options
306
+
307
+ #decode naming scheme
308
+ #mag = nil
309
+ #options[:imrc] = :real
310
+ #case name
311
+ #when /im/
312
+ #options[:imrc] = :im
313
+ #when /mag/
314
+ #options[:imrc] = :mag
315
+ #options[:mag] = true
316
+ #when /corr/
317
+ #options[:imrc] = :corr
318
+ #end
319
+ #options[:flip] = true if name =~ /flip/
320
+ #options[:norm] = true if name =~ /norm/
321
+ #options[:rev] = true if name =~ /rev/
322
+ #options[:z] = true if name =~ /z/
323
+
324
+
325
+ kit = GraphKit.autocreate({x: axiskit('theta_along_field_line', options), y: axiskit('phi_along_field_line', options)})
326
+ # ep kit
327
+ kit.data[0].title = "gs2:efn#{options[:imrc]}:#@run_name"
328
+ kit.title = "#{options[:mag] ? "Magnitude of" : ""} Eigenfunction for ky=#{list(:ky)[options[:ky_index]]}, g_exb=#{@g_exb.to_f.to_s}, shat=#{@shat.to_s}"
329
+ kit.file_name = "efn_for_#@run_name"
330
+ # kit.pointsize = 1.0
331
+ kit.modify(options)
332
+ kit.title += sprintf(" time = %3.1f", list(:t)[options[:t_index]]) if options[:t_index]
333
+ kit.data[0].with = "linespoints"
334
+ # kit.data[0].axes[:x].data *= -1 #if options[:rev]
335
+ #(eputs 'reversing'; gets)
336
+ if (@s_hat_input||@shat).abs >= 1.0e-5
337
+ range = options[:range] == 0 ? nil : (options[:range] or options[:z] ? 1 / (@s_hat_input||@shat) : 2 * Math::PI / (@s_hat_input||@shat))
338
+ kit.xrange = [-range, range] if range
339
+ end
340
+ return kit
341
+ end
342
+ end
343
+
344
+ alias :eigenfunction_graphkit :efn_graphkit
345
+
346
+ def es_heat_flux_vs_ky_vs_kx_graphkit(options={})
347
+ case options[:command]
348
+ when :help
349
+ return "Graph of electrostatic contribution to heat flux at a given time vs kx and ky"
350
+ when :options
351
+ return [:with]
352
+ else
353
+ zaxis = axiskit('es_heat_flux_over_ky_over_kx', options)
354
+ zaxis.data = zaxis.data.transpose
355
+ kit = GraphKit.autocreate({y: axiskit('ky', options), x: axiskit('kx', options), z: zaxis})
356
+ kit.title = "Heat flux"
357
+ kit.data[0].with = (options[:with] or 'pm3d palette')
358
+ kit.file_name = options[:graphkit_name]
359
+ return kit
360
+ end
361
+ end
362
+
363
+ def es_heat_flux_vs_time_graphkit(options={})
364
+ case options[:command]
365
+ when :help
366
+ return "Heat flux vs time for each species."
367
+ when :options
368
+ return [:t_index_window, :species_index]
369
+ else
370
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: axiskit('es_heat_flux', options)})
371
+ kit.data[0].title = "#{species_type(options[:species_index])} hflux: #@run_name"
372
+ kit.data[0].with = "l" #"lines"
373
+ kit.file_name = options[:graphkit_name]
374
+ kit
375
+ end
376
+ end
377
+
378
+ def es_mom_flux_vs_time_graphkit(options={})
379
+ case options[:command]
380
+ when :help
381
+ return "Momentum flux vs time for each species."
382
+ when :options
383
+ return [:t_index_window, :species_index]
384
+ else
385
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: axiskit('es_mom_flux_over_time', options)})
386
+ kit.data[0].title = "#{species_type(options[:species_index])} momflux: #@run_name"
387
+ kit.data[0].with = "l" #"lines"
388
+ kit.file_name = options[:graphkit_name]
389
+ # kit.log_axis = 'y'
390
+ return kit
391
+ end
392
+ end
393
+
394
+ def transient_es_heat_flux_amplification_vs_kx_graphkit(options={})
395
+ options[:kxy] = :kx
396
+ transient_es_heat_flux_amplification_vs_kxy_graphkit(options)
397
+ end
398
+
399
+ def transient_es_heat_flux_amplification_vs_ky_graphkit(options={})
400
+ options[:kxy] = :ky
401
+ transient_es_heat_flux_amplification_vs_kxy_graphkit(options)
402
+ end
403
+
404
+ def transient_es_heat_flux_amplification_vs_kxy_graphkit(options={})
405
+ case options[:command]
406
+ when :help
407
+ return "transient_es_heat_flux_amplification_vs_ky or transient_es_heat_flux_amplification_vs_kx. Growth rates vs either ky or kx for phi^2 integrated over the other direction. For growth rates at a specific kx AND ky, see /transient_es_heat_flux_amplification_vs_kx_vs_ky/. "
408
+ when :options
409
+ return []
410
+ else
411
+ #raise "Growth Rates are not available in non-linear mode" if @nonlinear_mode == "on"
412
+ kxy = options[:kxy]
413
+ kit = GraphKit.autocreate({x: axiskit(kxy.to_s, options), y: axiskit("transient_es_heat_flux_amplification_over_#{kxy}", options)})
414
+ kit.title = "Transient Amplification of the ES Heat flux for species #{options[:species_index]} by #{kxy}"
415
+ kit.data[0].with = "lp"
416
+ kit.data[0].title = @run_name
417
+ kit.file_name = options[:graphkit_name]
418
+ kit
419
+ end
420
+ end
421
+
422
+ def transient_amplification_vs_kx_graphkit(options={})
423
+ options[:kxy] = :kx
424
+ transient_amplification_vs_kxy_graphkit(options)
425
+ end
426
+
427
+ def transient_amplification_vs_ky_graphkit(options={})
428
+ options[:kxy] = :ky
429
+ transient_amplification_vs_kxy_graphkit(options)
430
+ end
431
+
432
+ def transient_amplification_vs_kxy_graphkit(options={})
433
+ case options[:command]
434
+ when :help
435
+ return "transient_amplification_vs_ky or transient_amplification_vs_kx. Growth rates vs either ky or kx for phi^2 integrated over the other direction. For growth rates at a specific kx AND ky, see /transient_amplification_vs_kx_vs_ky/. "
436
+ when :options
437
+ return []
438
+ else
439
+ #raise "Growth Rates are not available in non-linear mode" if @nonlinear_mode == "on"
440
+ kxy = options[:kxy]
441
+ kit = GraphKit.autocreate({x: axiskit(kxy.to_s, options), y: axiskit("transient_amplification_over_#{kxy}", options)})
442
+ kit.title = "Transient Amplification by #{kxy}"
443
+ kit.data[0].with = "lp"
444
+ kit.data[0].title = @run_name
445
+ kit.file_name = options[:graphkit_name]
446
+ kit
447
+ end
448
+ end
449
+
450
+
451
+ def growth_rate_vs_kx_graphkit(options={})
452
+ options[:kxy] = :kx
453
+ growth_rate_vs_kxy_graphkit(options)
454
+ end
455
+
456
+ def growth_rate_vs_ky_graphkit(options={})
457
+ options[:kxy] = :ky
458
+ growth_rate_vs_kxy_graphkit(options)
459
+ end
460
+
461
+ def growth_rate_vs_kxy_graphkit(options={})
462
+ case options[:command]
463
+ when :help
464
+ return "growth_rate_vs_ky or growth_rate_vs_kx. Growth rates vs either ky or kx for phi^2 integrated over the other direction. For growth rates at a specific kx AND ky, see /growth_rate_vs_kx_vs_ky/. "
465
+ when :options
466
+ return []
467
+ else
468
+ raise "Growth Rates are not available in non-linear mode" if @nonlinear_mode == "on"
469
+ kxy = options[:kxy]
470
+ kit = GraphKit.autocreate({x: axiskit(kxy.to_s, options), y: axiskit("growth_rate_over_#{kxy}", options)})
471
+ kit.title = "Growth Rates by #{kxy}"
472
+ kit.data[0].with = "lp"
473
+ kit.data[0].title = @run_name
474
+ kit.file_name = options[:graphkit_name]
475
+ kit
476
+ end
477
+ end
478
+
479
+ def growth_rate_vs_kx_vs_ky_graphkit(options={})
480
+ case options[:command]
481
+ when :help
482
+ return "3D plot of growth rates vs ky and kx for phi^2"
483
+ when :options
484
+ return [:with]
485
+ else
486
+ zaxis = axiskit('growth_rate_over_ky_over_kx', options)
487
+ zaxis.data = zaxis.data.transpose
488
+ kit = GraphKit.autocreate({y: axiskit('ky', options), x: axiskit('kx', options), z: zaxis})
489
+ kit.title = "Growth Rate by kx and ky"
490
+ kit.data[0].with = (options[:with] or 'pm3d palette')
491
+ kit.file_name = options[:graphkit_name]
492
+ kit
493
+ end
494
+ end
495
+
496
+ def hflux_tot_vs_time_graphkit(options={})
497
+ case options[:command]
498
+ when :help
499
+ return "Graph of total heat flux vs time. No options"
500
+ when :options
501
+ return []
502
+ else
503
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: axiskit('hflux_tot', options)})
504
+ kit.data[0].title = "hflux tot:#@run_name"
505
+ kit.data[0].with = "l" #"lines"
506
+ kit.file_name = options[:graphkit_name]
507
+ # kit.log_axis = 'y'
508
+ kit
509
+ end
510
+ end
511
+
512
+ def kpar_spectrum_graphkit(options={})
513
+ case options[:command]
514
+ when :help
515
+ return "Graph of the k_parallel at a given kx and ky"
516
+ when :options
517
+ return [:kx, :ky, :strongest_non_zonal_mode]
518
+ else
519
+ kit = GraphKit.autocreate({x: axiskit('kpar', options), y: axiskit('spectrum_over_kpar', options)})
520
+ kit.data[0].title = "Spectrum at t = #{list(:t).values.max}"
521
+ kit.file_name = options[:graphkit_name]
522
+ kit.data[0].with = 'lp'
523
+ kit
524
+ end
525
+ end
526
+
527
+ def kx_spectrum_graphkit(options={})
528
+ options[:kxy] = :kx
529
+ kxy_spectrum_graphkit(options)
530
+ end
531
+
532
+ def ky_spectrum_graphkit(options={})
533
+ options[:kxy] = :ky
534
+ kxy_spectrum_graphkit(options)
535
+ end
536
+
537
+ def kxy_spectrum_graphkit(options={})
538
+ case options[:command]
539
+ when :help
540
+ return "ky_spectrum or kx_spectrum: Graph of phi^2 vs kx or ky"
541
+ when :options
542
+ return [:t, :t_index]
543
+ else
544
+ # ie ky_spectrum or kx_spectrum
545
+ kxy = options[:kxy]
546
+ kit = GraphKit.autocreate({x: axiskit(kxy.to_s, options), y: axiskit("spectrum_over_#{kxy}", options)})
547
+ kit.title = "#{kxy} Spectrum"
548
+ kit.file_name = options[:graphkit_name] + options[:t_index].to_s
549
+ kit.data[0].with = 'lp'
550
+ kit.ylabel = "Phi^2 #{kxy}^2"
551
+ kit.pointsize = 2.0
552
+ kit
553
+ end
554
+ end
555
+ def lagrangian_kx_graphkit(options={})
556
+ case options[:command]
557
+ when :help
558
+ return "A graph of the evolution of a single Lagrangian kx vs Eulerian kx and ky. Principally for debugging purposes"
559
+ when :options
560
+ return []
561
+ else
562
+ kyax = axiskit('ky', options)
563
+ kyk = list(:ky).keys
564
+ kx_list = list(:kx)
565
+ begin
566
+ kx_data = kyk.map do |ky_index|
567
+ options[:ky_index] = ky_index
568
+ options[:kx_index] =1
569
+ ekx_index = eulerian_kx_index(options)
570
+ kx_list[ekx_index]
571
+ end
572
+ rescue #ArgumentError
573
+ kyk.pop
574
+ retry
575
+ end
576
+ lky = list(:ky)
577
+ kyax.data = kyk.map{|k| lky[k]}
578
+ kit = GraphKit.autocreate(x: {data: kx_data, title: 'Eulerian kx (i.e. location on the GS2 grid)'}, y: kyax )
579
+ kit.data[0].title = 'Lagrangian kx=0'
580
+ kit.xrange = [kx_list.values.min, 0]
581
+ kit.yrange = [0, lky.values.max]
582
+
583
+ kit.title = 'Evolution of a Single Lagrangian kx vs ky'
584
+ kit.file_name = 'lagrangian_kx_graphkit'
585
+ return kit
586
+
587
+
588
+
589
+ end
590
+ end
591
+
592
+ def phi_flux_tube_boundary_surface_graphkit(options={})
593
+ case options[:command]
594
+ when :help
595
+ return "The potential as a function of cartesian coordinates, on one specified side of the flux tube (specified using the options :coordinate (:x, :y, :theta) and :side (:min, :max))"
596
+ when :options
597
+ return [:Rgeo, :n0, :rho_star, :t_index, :nakx, :naky, :gs2_coordinate_factor, :xmax, :xmin, :ymax, :ymin, :thetamax, :thetamin, :ncopies, :side, :coordinate, :torphi_values]
598
+ else
599
+ phi = options[:phi] || phi_real_space_gsl_tensor(options)
600
+ if options[:ncopies]
601
+ ops = options.dup
602
+ ops.delete(:ncopies)
603
+ return (options[:ncopies].times.map do |n|
604
+ ops[:ncopy] = n
605
+ phi_flux_tube_boundary_surface_graphkit(ops)
606
+ end).sum
607
+ end
608
+ side = options[:side]
609
+ coord = options[:coordinate]
610
+ shp = phi.shape
611
+ #raise " asdfal" unless shp
612
+ opside = side == :max ? :min : :max
613
+ ops = options.dup
614
+ ops[coord+opside] = ops[coord+side] ||
615
+ case side
616
+ when :max
617
+ case coord
618
+ when :y
619
+ shp[0]-1
620
+ when :x
621
+ shp[1]-1
622
+ when :theta
623
+ shp[2]-1
624
+ end
625
+
626
+
627
+ when :min
628
+ 0
629
+ end
630
+ opscut = ops.dup
631
+ opscut[:ymin] = ((opscut[:ymin]||0) - (options[:ymin]||0))
632
+ opscut[:ymax] = ((opscut[:ymax]||shp[0]-1) - (options[:ymin]||0))
633
+ #ep 'opscut', opscut, (opscut[:xmax]||shp[1]-1), shp
634
+ opscut[:xmin] = ((opscut[:xmin]||0) - (options[:xmin]||0))
635
+ opscut[:xmax] = ((opscut[:xmax]||shp[1]-1) - (options[:xmin]||0))
636
+ #ep 'opscut', opscut
637
+ #ep 'opscut', opscut
638
+ opscut[:thetamin] = ((opscut[:thetamin]||0) - (options[:thetamin]||0))
639
+ opscut[:thetamax] = ((opscut[:thetamax]||shp[2]-1) - (options[:thetamin]||0))
640
+ #p opscut;#gets
641
+ if options[:cyl]
642
+ coords = cylindrical_coordinates_gsl_tensor(ops) #.transpose(0,1,2,3)
643
+ else
644
+ coords = cartesian_coordinates_gsl_tensor(ops)
645
+ end
646
+ #ep ['coords', coords.shape, phi.shape]; gets
647
+ newshape = coords.shape.slice(1..3)
648
+ x = coords[0, false]; x.reshape!(*newshape)
649
+ y = coords[1, false]; y.reshape!(*newshape)
650
+ z = coords[2, false]; z.reshape!(*newshape)
651
+ #ep shp , '...'
652
+ range = [
653
+ opscut[:ymin]||0..opscut[:ymax]||shp[0]-1,
654
+ opscut[:xmin]||0..opscut[:xmax]||shp[1]-1,
655
+ opscut[:thetamin]..opscut[:thetamax]
656
+
657
+ #((ops[:thetamin]||0) - (options[:thetamin]||0))..((ops[:thetamax]||shp[2]-1) - (options[:thetamin]||0))
658
+ ]
659
+
660
+ #ep ['range', range, 'phi.shape', phi.shape]
661
+ phiside = phi[*range ]
662
+ #ep ['coords', x.shape, phiside.shape]; gets
663
+ kit = GraphKit.quick_create([x,y,z,phiside])
664
+
665
+ # Create a map of this surface onto a continuous surface between two poloidal planes if ops[:torphi_values] is specified
666
+ if torphi_values = ops[:torphi_values]
667
+ raise "Can't take a poloidal cut at constant y or theta" if coord == :y #or coord == :theta
668
+ raise "Can't take a poloidal cut with a limited y range (Remove :ymin and :ymax from ops)" if options[:ymin] or options[:ymax]
669
+
670
+ torphi_values = torphi_values.sort
671
+ cyls = cylindrical_coordinates_gsl_tensor(ops.absorb(extra_points: true))
672
+ torphi_const0 = constant_torphi_surface_gsl_tensor(ops.absorb(torphi: torphi_values[0]))
673
+ #ep torphi_const0, ops
674
+ #torphi_const1 = constant_torphi_surface_gsl_tensor(ops.absorb(torphi: torphi_values[1]))
675
+ raise "torphi_should be of rank 1: #{torphi_const0.shape}" unless torphi_const0.shape.include? 1
676
+
677
+ #Get the number of points in the y direction between the two poloidal planes
678
+ deltorphi = cyls[2,-1,0,0] - cyls[2,0,0,0]
679
+ i = i1 = istart = torphi_const0[0,0]
680
+ displacement = torphi_values[0] - cyls[2,i,0,0] # which copy of the flux tube are we in?
681
+ #ep 'displacement', displacement
682
+ shpc = cyls.shape
683
+ ny = shpc[1]-1 # remove extra point
684
+ while cyls[2,i%ny,0,0] + displacement < torphi_values[1]
685
+ #ep ['displacement', displacement, 'torphi', torphi = cyls[2,i%ny,0,0] + displacement, 'i', i]
686
+ displacement=(cyls[2,i%ny+1,0,0]+displacement-cyls[2,0,0,0]) if (i+1)%ny == 0
687
+ i+=1
688
+ end
689
+ ysize = i - i1
690
+ #ep ['torphil', torphi = cyls[2,i%ny,0,0] + displacement, 'ysize', ysize]
691
+ #exit
692
+
693
+
694
+
695
+ #ysize = (torphi_const0[-1] - torphi_const1[0] ).abs + 1
696
+ #case coord
697
+ #when :x
698
+ shpside = phiside.shape
699
+ phicut = GSL::Tensor.float(ysize, shpside[1], shpside[2])
700
+ xcut = GSL::Tensor.float(ysize, shpside[1], shpside[2])
701
+ ycut = GSL::Tensor.float(ysize, shpside[1], shpside[2])
702
+ zcut = GSL::Tensor.float(ysize, shpside[1], shpside[2])
703
+ #ep shpside
704
+ shpcut = phicut.shape
705
+ for k in 0...shpcut[2] # 1 of these 2 loops
706
+ for j in 0...shpcut[1] # will have size 1
707
+
708
+ istart = torphi_const0[j,k]
709
+ displacement = torphi_values[0] - cyls[2,istart,j,k] # where in the torus does this copy of the flux tube start compared to where we want to be?
710
+
711
+ #p torphi_const0[i,j], torphi_const1[i,j]
712
+ for n in 0...shpcut[0] # index along our cut surface
713
+ i = istart + n
714
+ #icut = i%ysize
715
+ #cyls = cylindrical_coordinates_gsl_tensor(ops.absorb(extra_points: true)) #.transpose(0,1,2,3)
716
+ #ep ['displacement', displacement, n, i, ny, 'torphi', torphi = cyls[2,i%ny,j,k] +displacement]
717
+ # We chop off the surface
718
+ # between two y gridpoints
719
+ # Hence we must interpolate
720
+ # the field between those
721
+ # gridpoints
722
+ if n == 0
723
+ torphi0 = torphi_values[0]
724
+ s = Math.sin(torphi0)
725
+ c = Math.cos(torphi0)
726
+ d2 = cyls[2,(i+1)%ny,j,k] + displacement - torphi0
727
+ d1 = torphi0 - (cyls[2,i%ny,j,k] + displacement)
728
+ dfac = d1 / (d1+d2)
729
+ elsif n == ysize-1
730
+ torphi1 = torphi_values[1]
731
+ s = Math.sin(torphi1)
732
+ c = Math.cos(torphi1)
733
+ d2 = cyls[2,(i+1)%ny,j,k] + displacement - torphi1
734
+ d1 = torphi1 - (cyls[2,i%ny,j,k] + displacement)
735
+ dfac = d1 / (d1+d2)
736
+ else
737
+ s = Math.sin(cyls[2,i%ny,j,k] + displacement)
738
+ c = Math.cos(cyls[2,i%ny,j,k] + displacement)
739
+ dfac = 0
740
+ end
741
+
742
+ #ep [(phiside[i%ny,j,k] * (1-dfac) + phiside[(i+1)%ny,j,k] * dfac).class, i,j,k, phiside.shape, ny ]
743
+
744
+ phicut[n,j,k] = phiside[i%ny,j,k] * (1-dfac) + phiside[((i+1)%ny),j,k] * dfac
745
+
746
+ rad = cyls[0,i%ny,j,k]
747
+ xcut[n,j,k] = rad * c
748
+ ycut[n,j,k] = rad *s
749
+ zcut[n,j,k] = cyls[1,i%ny,j,k]
750
+ displacement=(cyls[2,i%ny+1,j,k]+displacement-cyls[2,0,j,k]) if (i+1)%ny == 0
751
+ #displacement+=cyls[2,i,j,k] if (i+1)%ny == 0
752
+ end
753
+ #exit
754
+ end
755
+ end
756
+
757
+ kit = GraphKit.quick_create([xcut,ycut,zcut,phicut])
758
+ end
759
+
760
+
761
+
762
+
763
+
764
+
765
+ kit.data[0].gp.with = "pm3d"
766
+ return kit
767
+ end
768
+
769
+ end
770
+ def phi_real_space_standard_representation_graphkit(options={})
771
+ case options[:command]
772
+ when :help
773
+ return "The potential as a function of cartesian coordinates showing showing the standard way of representing the turbulence, with two poloidal cuts and the inner and outer radial surfaces. Multiple copies of the flux tube are used to fill the space."
774
+ when :options
775
+ return [:Rgeo, :n0, :rho_star, :t_index, :nakx, :naky, :xmax, :xmin, :thetamax, :thetamin, :torphi_values]
776
+ else
777
+ phi = phi_real_space_gsl_tensor(options)
778
+ options[:phi] = phi
779
+ poloidal_planes = options[:torphi_values]
780
+ #ep poloidal_planes; gets
781
+ raise "Please set options[:torphi_values] to an array of two values" unless poloidal_planes.kind_of? Array and poloidal_planes.size==2
782
+ options[:torphi] = poloidal_planes[0]
783
+ kit1 = phi_real_space_poloidal_plane_graphkit(options)
784
+ options[:torphi] = poloidal_planes[1]
785
+ kit2 = phi_real_space_poloidal_plane_graphkit(options)
786
+ options[:coordinate] = :x
787
+ options[:side] = :min
788
+ kit3 = phi_flux_tube_boundary_surface_graphkit(options)
789
+ options[:side] = :max
790
+ kit4 = phi_flux_tube_boundary_surface_graphkit(options)
791
+ #kit= kit1+kit2
792
+ #kit = kit3 +kit4
793
+ kit = kit1+kit2+kit3+kit4
794
+ if options[:thetamax] or options[:thetamin]
795
+ options[:coordinate] = :theta
796
+ options[:side] = :min
797
+ kit5 = phi_flux_tube_boundary_surface_graphkit(options)
798
+ options[:side] = :max
799
+ kit6 = phi_flux_tube_boundary_surface_graphkit(options)
800
+ kit += kit5+kit6
801
+ end
802
+ kit.gp.pm3d = "depthorder"
803
+ kit.xlabel = 'X (m)'
804
+ kit.ylabel = 'Y (m)'
805
+ kit.zlabel = "'Z (m)' rotate by 90"
806
+ kit.title = "3-D Potential"
807
+ return kit
808
+ end
809
+ end
810
+ def phi_real_space_poloidal_plane_graphkit(options={})
811
+ case options[:command]
812
+ when :help
813
+ return "The potential as a function of cartesian coordinates showing a cut at one toroidal angle, with multiple periodic copies of the flux tube used to fill the whole circle.."
814
+ when :options
815
+ return [:Rgeo, :n0, :rho_star, :t_index, :nakx, :naky, :xmax, :xmin, :thetamax, :thetamin, :torphi]
816
+ else
817
+ #if options[:ncopies]
818
+ #ops = options.dup
819
+ #ops.delete(:ncopies)
820
+ #return (options[:ncopies].times.map do |n|
821
+ #ops[:ncopy] = n
822
+ #phi_real_space_surface_graphkit(ops)
823
+ #end).sum
824
+ #end
825
+ #zaxis = axiskit('phi0_over_x_over_y', options)
826
+ #zaxis.data = zaxis.data.transpose
827
+ #shape = zaxis.data.shape
828
+ #carts = cartesian_coordinates_gsl_tensor(options)
829
+ #torphiout = 2.6
830
+ torphiout = options[:torphi]
831
+ phi = options[:phi] || phi_real_space_gsl_tensor(options)
832
+ torphi_const = constant_torphi_surface_gsl_tensor(options)
833
+ cyls = cylindrical_coordinates_gsl_tensor(options.absorb({extra_points: true}))
834
+ #p torphi_const[0,true].to_a;
835
+ #p 'sh', cyls.shape[1], '','','','';
836
+ #exit
837
+ #carts = cartesian_coordinates_gsl_tensor(options)
838
+ shp = phi.shape
839
+ shpc = cyls.shape
840
+ #ep 'shapes', shp, cyls.shape
841
+ new_phi = GSL::Tensor.alloc(shp[1], shp[2])
842
+ new_X = GSL::Tensor.alloc(shp[1], shp[2])
843
+ new_Y = GSL::Tensor.alloc(shp[1], shp[2])
844
+ new_Z = GSL::Tensor.alloc(shp[1], shp[2])
845
+ #y = gsl_vector('y', options)
846
+ #y = y.connect([2*y[-1] - y[-2]].to_gslv).dup
847
+ #c = Math.cos(torphiout)
848
+ #s = Math.sin(torphiout)
849
+ #theta_vec = gsl_vector('theta', options)
850
+ #x_vec = gsl_vector('x', options)
851
+ #y_vec = gsl_vector('y', options)
852
+ #phi.iterate do |i,j,k|
853
+ #lastbracketed = nil
854
+ #lastj = -1
855
+ #phi.iterate_row_maj do |i,j,k|
856
+ for k in 0...shp[2] #theta loop
857
+ for j in 0...shp[1] #xloop
858
+ #raise "Missed #{[j,k].inspect}, #{lastj}" unless lastj == j-1
859
+ #ep [i,j,k], cyls.shape
860
+ i = torphi_const[j,k]
861
+ torphi1 = cyls[2,i,j,k]
862
+ torphi2 = cyls[2,i+1,j,k]
863
+ #ep cyls[2,true,j,k].to_a
864
+ deltorphi = cyls[2,shpc[1]-1,j,k] - cyls[2,0,j,k]
865
+ #raise "Periodicity not satisfied: #{(2*Math::PI/deltorphi+1.0e-8)%1.0}, #{(2*Math::PI/deltorphi+1.0e-5)}" unless ((2*Math::PI/deltorphi)+1.0e-8)%1.0 < 1.0e-5
866
+ m1 = (torphi1 )%deltorphi
867
+ m2 = (torphi2 )%deltorphi
868
+ m3 = (torphiout)%deltorphi
869
+ #bracketed = ((m1-m3).abs < 1.0e-4) || (
870
+ #(m2-m3.abs) > 1.0e-4 &&
871
+ #(m2 - m3) *
872
+ #(m1 - m3) *
873
+ #(m2 - m1) *
874
+ #(torphi2 - torphi1) < 0)
875
+ ##p 'n0', (2*Math::PI/deltorphi).round
876
+ #bracketed2 = (2*Math::PI/deltorphi + 1).round.times.inject(false) do |b,n|
877
+ #epsn = 1.0e-4
878
+ #eps2 = 1.0e-4
879
+ #upp = torphiout + deltorphi * n
880
+ #lwr = torphiout - deltorphi * n
881
+ ##measure = ((torphi1 < upp or (torphi1 - upp).abs < epsn) and upp+epsn < torphi2) or ((torphi1 < lwr or (torphi1-lwr).abs < eps) and lwr + eps < torphi2)
882
+ #a1 = a2 = a3 = b1 = b2 = b3 = 'q'
883
+ ##measure = ((
884
+ ###a1=((torphi1-upp).abs < (torphi2-upp).abs) and
885
+ ##(a1=((torphi2-upp).abs > 1.0e-7)) and
886
+ ##(a2=((torphi1 < upp or (torphi1 - upp).abs < epsn))) and
887
+ ##(a3=(upp < torphi2))
888
+ ##) or (
889
+ ###b1=((torphi1-lwr).abs < (torphi2-lwr).abs) and
890
+ ##(b1=((torphi2-lwr).abs > 1.0e7)) and
891
+ ##(b2=(torphi1 < lwr or (torphi1-lwr).abs < epsn)) and
892
+ ##(b3 = (lwr < torphi2))
893
+ ##))
894
+ #a1=((torphi2-upp).abs > eps2)
895
+ #a2=((torphi1 < upp or (torphi1 - upp).abs < epsn))
896
+ #a3=(upp < torphi2)
897
+ #b1=(torphi2-lwr).abs > eps2
898
+ #b2=(torphi1 < lwr or (torphi1-lwr).abs < epsn)
899
+ #b3 = (lwr < torphi2)
900
+ #measure = ((a1 and a2 and a3) or (b1 and b2 and b3))
901
+ ##ep 'measure', measure, [torphi1, torphi2, upp, lwr , n, deltorphi, a1, a2, a3, b1, b2, b3, (torphi2-lwr).abs, (torphi2-lwr).abs > eps2] if measure #; gets if [j,k] == [5,8] # if measure
902
+ #b or measure
903
+ #end
904
+ ##bracketed = bracketed2
905
+ #raise "Measures don't agree #{bracketed}, #{bracketed2}" unless bracketed2 == bracketed
906
+ #
907
+ #
908
+ ##d2 = torphi2 - torphiout
909
+ ##d1 = torphiout - torphi1
910
+ #if bracketed
911
+ #y1 =
912
+ d2 = m2 - m3
913
+ d1 = m3 - m1
914
+ if torphi2 > torphi1
915
+ d1+=deltorphi if d1 < 0
916
+ else
917
+ d2-=deltorphi if d2 > 0
918
+ end
919
+ dfac = d1 / (d1+d2)
920
+
921
+ #n = 0
922
+ #loop do
923
+
924
+ #ep [torphi1, torphi2, cyls[2,shpc[1]-1,j,k] , cyls[2,0,j,k], deltorphi, m1, m2, m3]
925
+ #ep (mod2 - mod3)/(mod1 - mod3) < 0,"********"
926
+ #raise "Doubled up" if lastbracketed == [j,k]
927
+ #raise "Missed: #{i},#{j}, #{lastbracketed.inspect} " unless lastbracketed == [j-1,k] or lastbracketed == [shp[1]-1, k-1] if lastbracketed
928
+ #ep bracketed,"********"
929
+ #ep ['bracketed', i, j, k]
930
+ #ep ['phi', phi[i,j,k]]
931
+ #new_phi[j,k] = theta_vec[k]
932
+ new_phi[j,k] = phi[i,j,k] * (1-dfac) + phi[(i+1)%shp[0],j,k] * dfac
933
+ #raise "Mismatched radii" unless
934
+ #new_X[j,k] = cyls[0,i,j,k] * Math.cos(cyls[2,i,j,k])
935
+ #new_X[j,k] = x_vec[j]
936
+ new_X[j,k] = cyls[0,i,j,k] * Math.cos(torphiout)
937
+ #new_Y[j,k] = cyls[0,i,j,k] * Math.sin(cyls[2,i,j,k])
938
+ #new_Y[j,k] = y_vec[i]
939
+ new_Y[j,k] = cyls[0,i,j,k] * Math.sin(torphiout)
940
+ #new_Z[j,k] = theta_vec[k]
941
+ new_Z[j,k] = cyls[1,i,j,k]
942
+ #lastbracketed = [j,k]
943
+ #lastj = j
944
+ #end
945
+ end # xloop
946
+ end # theta loop
947
+ #exit
948
+ kit = GraphKit.quick_create([new_X, new_Y, new_Z, new_phi])
949
+ kit.xlabel = 'X'
950
+ kit.ylabel = 'Y'
951
+ kit.data[0].gp.with = "pm3d"
952
+ return kit
953
+
954
+
955
+
956
+
957
+
958
+
959
+
960
+
961
+ #end
962
+
963
+ sides = [:max, :min]
964
+ kits = []
965
+ #[].each_with_index do |coord,i|
966
+ #sides.each_with_index do |side,j|
967
+ [[:y, :min, 0], [:y, :max, Math::PI]].each do |coord, side, toroidalphi|
968
+ #[0].each do |toroidalphi|
969
+ #raise unless i.kind_of? Integer
970
+ #return kit if coord + side == :xmax
971
+ options[:phi] = phi
972
+ options[:side] = side
973
+ options[:coordinate] = coord
974
+ options[:toroidal_projection] = coord == :x ? nil : toroidalphi
975
+ next if coord == :x and toroidalphi == Math::PI
976
+ kit = phi_flux_tube_boundary_surface_graphkit(options)
977
+ kits.push kit
978
+ end
979
+ #end
980
+ #end
981
+ k = kits.sum
982
+ #k = kits[5] + kits[4] + kits[3] + kits[2] + kits[1] + kits[0]
983
+ #k = kits[5] + kits[4] + kits[1] + kits[0]
984
+ k.gp.pm3d = "depthorder"
985
+ #k.compress_datakits = true
986
+ return k
987
+
988
+ end
989
+ end
990
+ #def phi_flux_tube_poloidal_cut_graphkit(options={})
991
+ ######case options[:command]
992
+ ######when :help
993
+ ######return "The potential as a function of cartesian coordinates, cut at two toroidal angles."
994
+ ######when :options
995
+ ######return [:rgbformulae, :limit, :t_index]
996
+ ######end
997
+ #poloidal_planes = options[:torphi_values]
998
+ ##ep poloidal_planes; gets
999
+ #raise "Please set options[:torphi_values] to an array of two values" unless poloidal_planes.kind_of? Array and poloidal_planes.size==2
1000
+ #field = options[:phi] || phi_real_space_gsl_tensor(options)
1001
+ #options[:torphi] = poloidal_planes[0]
1002
+ #torphi_const1 = constant_torphi_surface_gsl_tensor(options.dup.absorb(no_copies: true))
1003
+ #options[:torphi] = poloidal_planes[1]
1004
+ #torphi_const2 = constant_torphi_surface_gsl_tensor(options.dup.absorb(no_copies: true))
1005
+ #x1 = SparseTensor.new(2) # First poloidal face
1006
+ #y1 = SparseTensor.new(2)
1007
+ #z1 = SparseTensor.new(2)
1008
+ #field1 = SparseTensor.new(2)
1009
+
1010
+ #x2 = SparseTensor.new(2) # Second poloidal
1011
+ #y2 = SparseTensor.new(2) # face
1012
+ #z2 = SparseTensor.new(2)
1013
+ #field2 = SparseTensor.new(2)
1014
+
1015
+ #xmaxx = SparseTensor.new(2) # Connecting
1016
+ #ymaxx = SparseTensor.new(2) # surface of the
1017
+ #zmaxx = SparseTensor.new(2) # flux tube
1018
+ #fieldmaxx = SparseTensor.new(2) # max x
1019
+ #xminx = SparseTensor.new(2) # Connecting
1020
+ #yminx = SparseTensor.new(2) # surface of the
1021
+ #zminx = SparseTensor.new(2) # flux tube
1022
+ #fieldminx = SparseTensor.new(2)
1023
+ #xmaxth = SparseTensor.new(2) # Connecting
1024
+ #ymaxth = SparseTensor.new(2) # surface of the
1025
+ #zmaxth = SparseTensor.new(2) # flux tube
1026
+ #fieldmaxth = SparseTensor.new(2)
1027
+ #xminth = SparseTensor.new(2) # Connecting
1028
+ #yminth = SparseTensor.new(2) # surface of the
1029
+ #zminth = SparseTensor.new(2) # flux tube
1030
+ #fieldminth = SparseTensor.new(2)
1031
+
1032
+ #xsurf = [xmaxx, xminx, xmaxth, xminth]
1033
+ #ysurf = [ymaxx, yminx, ymaxth, yminth]
1034
+ #zsurf = [zmaxx, zminx, zmaxth, zminth]
1035
+ #fieldsurf = [fieldmaxx, fieldminx, fieldmaxth, fieldminth]
1036
+
1037
+ #cyls = cylindrical_coordinates_gsl_tensor(options)
1038
+ #shp = cyls.shape
1039
+ #ysize = shp[1]
1040
+
1041
+ ## Find out how far each cut
1042
+ ## poloidal face of the flux
1043
+ ## tube extends in theta and x
1044
+ #k1min = GSL::Tensor.int(shp[2])
1045
+ #k1max = GSL::Tensor.int(shp[2])
1046
+ #k2min = GSL::Tensor.int(shp[2])
1047
+ #k2max = GSL::Tensor.int(shp[2])
1048
+ #k1min[true] = shp[3]; k1max[true] = 0
1049
+ #k2min[true] = shp[3]; k2max[true] = 0
1050
+ #j1min = GSL::Tensor.int(shp[3])
1051
+ #j1max = GSL::Tensor.int(shp[3])
1052
+ #j2min = GSL::Tensor.int(shp[3])
1053
+ #j2max = GSL::Tensor.int(shp[3])
1054
+ #j1min[true] = shp[2]; j1max[true] = 0
1055
+ #j2min[true] = shp[2]; j2max[true] = 0
1056
+ ##ep j1max;gets
1057
+ #for j in 0...shp[2]
1058
+ #for k in 0...shp[3]
1059
+ #i1 = torphi_const1[j,k]
1060
+ #i2 = torphi_const2[j,k]
1061
+ #i1 = 0 if i1==-1
1062
+ #i2 = 0 if i2==-1
1063
+ #i1 = ysize-1 if i1==ysize
1064
+ #i2 = ysize-1 if i2==ysize
1065
+ #if i1%ysize==i1
1066
+ #k1min[j] = [k, k1min[j]].min
1067
+ #k1max[j] = [k, k1max[j]].max
1068
+ #j1min[k] = [j, j1min[k]].min
1069
+ #j1max[k] = [j, j1max[k]].max
1070
+ #end
1071
+ #if i2%ysize==i2
1072
+ #k2min[j] = [k, k2min[j]].min
1073
+ #k2max[j] = [k, k2max[j]].max
1074
+ #j2min[k] = [j, j2min[k]].min
1075
+ #j2max[k] = [j, j2max[k]].max
1076
+ #end
1077
+ #end
1078
+ #end
1079
+ #lineorder = SparseTensor.new(2)
1080
+ #surfaces = SparseTensor.new(2)
1081
+ ##Now we generate the order of the line
1082
+ ##scans between one cross section and
1083
+ ##the other (the lines have to be in order
1084
+ ## around the cross section)
1085
+ ## We also specify which surface(s) the
1086
+ ## line lies on
1087
+ #o = 0
1088
+ ##min x surface
1089
+ #j=0
1090
+ #for k in ([k1min[0],k2min[0]].min)..([k1max[0], k2max[0]].max)
1091
+ #lineorder[j,k] = o
1092
+ #surfaces[j,k]||=[]
1093
+ #surfaces[j,k].push 1
1094
+ #o+=1
1095
+ #end
1096
+ ## max theta surface
1097
+ #for j in 0...shp[2]
1098
+ #lineorder[j,[k1max[j],k2max[j]].max]=o
1099
+ #surfaces[j,[k1max[j],k2max[j]].max]||=[]
1100
+ #surfaces[j,[k1max[j],k2max[j]].max].push 2
1101
+ #o+=1
1102
+ #end
1103
+ #j = shp[2]-1
1104
+ ## max x surface
1105
+ #ep ([k1max[j], k2max[j]].max)..([k1min[j],k2min[j]].min)
1106
+ #for k in (-[k1max[j], k2max[j]].max)...(-[k1min[j],k2min[j]].min)
1107
+ #ep 'k', k
1108
+ #lineorder[j,-k] = o
1109
+ #surfaces[j,-k]||=[]
1110
+ #surfaces[j,-k].push 0
1111
+ #o+=1
1112
+ #end
1113
+ ## max theta surface
1114
+ #for j in -(shp[2]-1)..0
1115
+ #lineorder[-j,[k1min[j],k2min[j]].min]=o
1116
+ #surfaces[-j,[k1min[j],k2min[j]].min]||=[]
1117
+ #surfaces[-j,[k1min[j],k2min[j]].min].push 3
1118
+ #o+=1
1119
+ #end
1120
+ #ep lineorder, surfaces;gets
1121
+
1122
+ ##ep j1max.to_a;gets
1123
+ #for j in 0...shp[2]
1124
+ #for k in 0...shp[3]
1125
+ #i10 = i1 = torphi_const1[j,k]
1126
+ #i20 = i2 = torphi_const2[j,k]
1127
+ #ep ['i1', i1, 'i2', i2]
1128
+
1129
+ ## Include extra points just outside
1130
+ ## if necessary
1131
+ #i10 = 0 if i1==-1 #
1132
+ #i20 = 0 if i2==-1
1133
+ #i10 = ysize - 1 if i1 == ysize
1134
+ #i20 = ysize - 1 if i2 == ysize
1135
+ ##if i1%ysize==i1 || i1==-1
1136
+ #if i10%ysize==i10
1137
+ ## First assign all the points on the first cut poloidal face
1138
+ #r = cyls[0,i10,j,k]
1139
+ #z = cyls[1,i10,j,k]
1140
+ #tphi = poloidal_planes[0]
1141
+ ##tphi = cyls[2,i1,j,k]
1142
+ ##ep ['tphi', tphi, 'i1', i1, cyls[2,i1,j,k]%(2*Math::PI), cyls[2,(i1+1)%ysize,j,k]%(2*Math::PI)]
1143
+ #s = Math.sin(tphi)
1144
+ #c = Math.cos(tphi)
1145
+ #x1p = x1[j,k] = r*c# X (not gs2 x!)
1146
+ #y1p = y1[j,k] = r*s# Y (not gs2 y!)
1147
+ #z1p = z1[j,k] = z# Z
1148
+ ##ep [2,(i1+1)%ysize,j,k, cyls.shape]
1149
+ ## I think this bit will be wrong
1150
+ ## when i1 = -1 or ysize - 1
1151
+ ## but it won't be a big error
1152
+ ## --- need to fix
1153
+ ##d2 = cyls[2,(i1+1)%ysize,j,k] - tphi
1154
+ ##d1 = tphi - cyls[2,i1,j,k]
1155
+ ##dfac = d1 / (d1+d2)
1156
+ ##f1p = field1[j,k] = field[i1,j,k] * (1-dfac) + field[i1%ysize,j,k] * dfac
1157
+ #f1p = (field1[j,k] = field[i1%ysize,j,k] + field[(i1+1)%ysize,j,k])/2.0
1158
+ #end
1159
+ #if i20%ysize==i20
1160
+ #r = cyls[0,i20,j,k]
1161
+ #z = cyls[1,i20,j,k]
1162
+ #tphi = poloidal_planes[1]
1163
+ #s = Math.sin(tphi)
1164
+ #c = Math.cos(tphi)
1165
+ #x2[j,k] = r*c# X (not gs2 x!)
1166
+ #y2[j,k] = r*s# Y (not gs2 y!)
1167
+ #z2[j,k] = z# Z
1168
+ ##ep [2,(i2+1)%ysize,j,k, cyls.shape]
1169
+ ##d2 = cyls[2,(i2+1)%ysize,j,k] - tphi
1170
+ ##d1 = tphi - cyls[2,i2,j,k]
1171
+ ##dfac = d1 / (d1+d2)
1172
+ #field2[j,k] = (field[i2%ysize,j,k] + field[(i2+1)%ysize,j,k])/2.0
1173
+ ##field2[j,k] = field[i2,j,k] * (1-dfac) + field[i2%ysize,j,k] * dfac
1174
+ #end
1175
+ #end
1176
+ #end
1177
+ #for j in 0...shp[2]
1178
+ #for k in 0...shp[3]
1179
+ #i10 = i1 = torphi_const1[j,k]
1180
+ #i20 = i2 = torphi_const2[j,k]
1181
+ ##ep ['i1', i1, 'i2', i2]
1182
+
1183
+ ## Include extra points just outside
1184
+ ## if necessary
1185
+ #i10 = 0 if i1==-1 #
1186
+ #i20 = 0 if i2==-1
1187
+ #i10 = ysize - 1 if i1 == ysize
1188
+ #i20 = ysize - 1 if i2 == ysize
1189
+ #if lineorder[j,k]
1190
+ #n=0
1191
+ #sign21 = ((i2-i1)/(i2-i1).abs).round
1192
+ ## Go from y on the first surface to
1193
+ ## y on the next surface
1194
+ #ep ['jk',j,k, (i10+n*sign21)*sign21 < i20*sign21]
1195
+ #while (i10+n*sign21)*sign21 < i20*sign21
1196
+ #ka = k
1197
+ #ia10 = i10
1198
+ #ia20 = i20
1199
+ #while (ia10+n*sign21)%ysize != ia10+n*sign21
1200
+ #ep [j,k,ka, 'ia10', ia10, ia10+n*sign21, lineorder[j,k], surfaces[j,k], 'n', n, 'ni', ia10 + n * sign21, 'ysize', ysize, 'max', k1max[j], k2max[j], 'min', k1min[j], k2min[j] ]
1201
+ ## We have left the flux surface...
1202
+ ## increase/decrease theta to get back in
1203
+ #if k > k1max[j] or k > k2max[j] # thetamax
1204
+ #ka-=1
1205
+ #elsif k < k1min[j] or k < k2min[j] # thetamin
1206
+ #ka+=1
1207
+ #else
1208
+ #raise "Got lost!"
1209
+ #end
1210
+ #ia10 = torphi_const1[j,ka]
1211
+ #ia10 = 0 if ia10==1
1212
+ #ia10 = ysize - 1 if ia10 == ysize
1213
+ #ia20 = torphi_const2[j,ka]
1214
+ #ia20 = 0 if ia20==1
1215
+ #ia20 = ysize - 1 if ia20 == ysize
1216
+ #end
1217
+ #ni = n*sign21+ia10
1218
+ ## First end
1219
+ #if ni==ia10
1220
+ #xs = x1[j,ka]
1221
+ #ys = y1[j,ka]
1222
+ #zs = z1[j,ka]
1223
+ #fs = field1[j,ka]
1224
+ ## Second ed
1225
+ #elsif ni*sign21 == ia20*sign21 - 1
1226
+ #xs = x2[j,ka]
1227
+ #ys = y2[j,ka]
1228
+ #zs = z2[j,ka]
1229
+ #fs = field2[j,ka]
1230
+ ## Connecting line
1231
+ #else
1232
+ #tphi = cyls[2,ni,j,ka]
1233
+ #s = Math.sin(tphi)
1234
+ #c = Math.cos(tphi)
1235
+ #r = cyls[0,ni,j,ka]
1236
+ #xs = r*c
1237
+ #ys = r*s
1238
+ #zs = cyls[1,ni,j,ka]
1239
+ #fs = field[ni,j,ka]
1240
+ #end
1241
+
1242
+
1243
+ #surfaces[j,k].each do |m|
1244
+ #o = lineorder[j,k]
1245
+ #xsurf[m][o,n] = xs
1246
+ #ysurf[m][o,n] = ys
1247
+ #zsurf[m][o,n] = zs
1248
+ #fieldsurf[m][o,n] = fs
1249
+ #end
1250
+
1251
+ #n+=1
1252
+ #end
1253
+ #end
1254
+
1255
+
1256
+ #next
1257
+
1258
+ ## Fill in from the first poloidal plane to the second poloidal plane or the edge of the box, which ever is closer
1259
+ #if [j1min[k], j1max[k]].include? j or (false and [k1min[j],k1max[j]].include? k)
1260
+ #m = (j==j1min[k] ? 1 : 0)
1261
+
1262
+ #xsurf[m][j,k,0] = r*c# X (not gs2 x!)
1263
+ #ysurf[m][j,k,0] = r*s# Y (not gs2 y!)
1264
+ #zsurf[m][j,k,0] = z# Z
1265
+ #fieldsurf[m][j,k,0] = field[i1,j,k]
1266
+ #sign21 = ((i2-i1)/(i2-i1).abs).round
1267
+ ##ep sign21; gets
1268
+ #n=1
1269
+ ##while (i1+n*sign21)%ysize==i1+n*sign21 and (i1+n*sign21)*sign21 < i2*sign21
1270
+ #while (i10+n*sign21)%ysize==i10+n*sign21 and (i10+n*sign21)*sign21 < i20*sign21
1271
+ #ni = n*sign21+i10
1272
+ ##ep [[2,ni,j,k], cyls.shape]
1273
+ #tphi = cyls[2,ni,j,k]
1274
+ #s = Math.sin(tphi)
1275
+ #c = Math.cos(tphi)
1276
+ #r = cyls[0,ni,j,k]
1277
+ #z = cyls[1,ni,j,k]
1278
+ #xsurf[m][j,k,n] = r*c# X (not gs2 x!)
1279
+ #ysurf[m][j,k,n] = r*s# Y (not gs2 y!)
1280
+ #zsurf[m][j,k,n] = z# Z
1281
+ #fieldsurf[m][j,k,n] = field[ni,j,k]
1282
+ #n+=1
1283
+ #end
1284
+ #end
1285
+ ##end
1286
+ ##if i2%ysize==i2 || i2==-1
1287
+ #if i20%ysize==i20
1288
+ #r = cyls[0,i2,j,k]
1289
+ #z = cyls[1,i2,j,k]
1290
+ #tphi = poloidal_planes[1]
1291
+ #s = Math.sin(tphi)
1292
+ #c = Math.cos(tphi)
1293
+ #x2[j,k] = r*c# X (not gs2 x!)
1294
+ #y2[j,k] = r*s# Y (not gs2 y!)
1295
+ #z2[j,k] = z# Z
1296
+ ##ep [2,(i2+1)%ysize,j,k, cyls.shape]
1297
+ #d2 = cyls[2,(i2+1)%ysize,j,k] - tphi
1298
+ #d1 = tphi - cyls[2,i2,j,k]
1299
+ #dfac = d1 / (d1+d2)
1300
+ #field2[j,k] = field[i2,j,k] * (1-dfac) + field[i2%ysize,j,k] * dfac
1301
+ #end
1302
+ #next
1303
+ ##if (i1%ysize==i1 || i1==-1) and ( [0,shp[2]-1].include? j or (false and [k1min[j],k1max[j]].include? k))
1304
+ #if i10%ysize==i10 and ( [j1min[k], j1max[k]].include? j or (false and [k1min[j],k1max[j]].include? k))
1305
+ #m = (j==j1min[k] ? 1 : 0)
1306
+ #xsurf[m][j,k,n] = x2[j,k]
1307
+ #ysurf[m][j,k,n] = y2[j,k]
1308
+ #zsurf[m][j,k,n] = z2[j,k]
1309
+ #fieldsurf[m][j,k,n] = field2[j,k]
1310
+ #elsif false
1311
+ #if [0,shp[2]-1].include? j or [k2min[j],k2max[j]].include? k
1312
+ #sign12 = ((i1-i2)/(i1-i2).abs).round
1313
+ #xouter[j,k,0] = x2[j,k]
1314
+ #youter[j,k,0] = y2[j,k]
1315
+ #zouter[j,k,0] = z2[j,k]
1316
+ #fieldouter[j,k,0] = field2[j,k]
1317
+ ##ep sign12; gets
1318
+
1319
+ ## Fill in from the first poloidal plane to the second poloidal plane or the edge of the box, which ever is closer
1320
+ #n=1
1321
+ #while (i2+n*sign12)%ysize==i2+n*sign12 and (i2+n*sign12)*sign12 < i1*sign12
1322
+ #ni = n*sign12+i2
1323
+ ##ep [[1,ni,j,k], cyls.shape]
1324
+ #tphi = cyls[2,ni,j,k]
1325
+ #s = Math.sin(tphi)
1326
+ #c = Math.cos(tphi)
1327
+ #r = cyls[0,ni,j,k]
1328
+ #z = cyls[1,ni,j,k]
1329
+ #xouter[j,k,n] = r*c# X (not gs2 x!)
1330
+ #youter[j,k,n] = r*s# Y (not gs2 y!)
1331
+ #zouter[j,k,n] = z# Z
1332
+ #fieldouter[j,k,n] = field[ni,j,k]
1333
+ #n+=1
1334
+ #end
1335
+ #end
1336
+
1337
+ ##end
1338
+ #end
1339
+ #end
1340
+ #end
1341
+ #ep xsurf[3]
1342
+ #ep xsurf[2]
1343
+ #kit1 = GraphKit.quick_create([x1,y1,z1,field1])
1344
+ #kit2 = GraphKit.quick_create([x2,y2,z2,field2])
1345
+ #kits = 4.times.map{|i| GraphKit.quick_create([xsurf[i],ysurf[i],zsurf[i],fieldsurf[i]])}
1346
+ #return kit1 + kit2 + kits.sum
1347
+ #end
1348
+
1349
+
1350
+
1351
+
1352
+
1353
+ def phi_magnifying_glass_graphkit(options={})
1354
+ case options[:command]
1355
+ when :help
1356
+ return "The potential as a function of cartesian coordinates, plus a close up section."
1357
+ when :options
1358
+ return [:Rgeo, :n0, :rho_star, :t_index, :nakx, :naky, :xmax, :xmin, :thetamax, :thetamin, :magnify]
1359
+ end
1360
+
1361
+ ops = options.dup
1362
+ ops.delete(:thetamin)
1363
+ ops.delete(:thetamax)
1364
+ flux_tube = phi_real_space_surface_graphkit(ops)
1365
+ options[:thetamin] #= options[:theta_magnify]
1366
+ options[:thetamax] #= options[:theta_magnify] + 4
1367
+ #options[:torphi_values] = [:options
1368
+ #correct_3d_options(options)
1369
+ #factors = geometric_factors_gsl_tensor(options)
1370
+ #xfac = 1.0 / options[:rho_star_actual]
1371
+ #yfac = options[:rhoc_actual] / options[:q_actual] / options[:rho_star_actual]
1372
+ #y = gsl_vector('y', options)
1373
+ #x = gsl_vector('x', options)
1374
+ #kmin = 0 #options[:thetamin]
1375
+ #kmax = -1 #options[:thetamax]
1376
+
1377
+ #ep 'factors.shape', factors.shape
1378
+ #torphi1 = y[-1]/yfac - factors[2,kmin] - x[-1]/xfac * factors[5,kmin]
1379
+ #torphi2 = factors[2,kmax]
1380
+ cyls = cylindrical_coordinates_gsl_tensor(options)
1381
+ #torphi1 = cyls[2,0,true,0].max
1382
+ torphi1 = cyls[2,0,true,-1].max
1383
+ torphi2 = cyls[2,-1,true,-1].min
1384
+ torphi3 = cyls[2,0,true,-1].max
1385
+ torphi4 = cyls[2,-1,true,0].min
1386
+ delta = 0.5
1387
+ if torphi1 > torphi3
1388
+ tv = [torphi1, [torphi1 + delta, torphi4].min]
1389
+ else
1390
+ tv = [torphi3, [torphi3 + delta, torphi2].min]
1391
+ end
1392
+
1393
+ ep 'torphiVaues', options[:torphi_values] = tv;
1394
+
1395
+
1396
+ #ep options; gets
1397
+ section = phi_real_space_standard_representation_graphkit(options)
1398
+ #dR1 = (section.data.map{|dk|
1399
+ #(dk.x.data.max**2 + dk.y.data.max**2)**0.5
1400
+ #}.max +
1401
+ #section.data.map{|dk|
1402
+ #(dk.x.data.min**2 + dk.y.data.min**2)**0.5
1403
+ #}.min)/2
1404
+ #z1max = section.data.map{|dk| dk.z.data.max}.max
1405
+ #z1min = section.data.map{|dk| dk.z.data.min}.min )/2
1406
+
1407
+ magnify = options[:magnify]
1408
+
1409
+ #p section; gets
1410
+ blacked_out = section.dup
1411
+ fmin = section.data.map{|dk| dk.f.data.min}.min
1412
+ if magnify > 2
1413
+ blacked_out.data.each{|dk|
1414
+ dk.x.data *= 1.05
1415
+ dk.y.data *= 1.05
1416
+ dk.z.data *= 1.05
1417
+ dk.f.data.fill!(fmin)
1418
+ #dk.gp.with = 'p lc rgb "#000000" ps 3.0 '
1419
+ }
1420
+ end
1421
+ section.data.each do |dk|
1422
+ magnify = options[:magnify]
1423
+ #ep dk.x.data.shape
1424
+ dk.x.data *= magnify
1425
+ dk.y.data *= magnify
1426
+ dk.z.data *= magnify
1427
+ end
1428
+ dR = (section.data.map{|dk|
1429
+ (dk.x.data.max**2 + dk.y.data.max**2)**0.5
1430
+ }.max +
1431
+ section.data.map{|dk|
1432
+ (dk.x.data.min**2 + dk.y.data.min**2)**0.5
1433
+ }.min)/2
1434
+
1435
+ #xmag = (section.data.map{|dk| dk.x.data.max}.max +
1436
+ #section.data.map{|dk| dk.x.data.min}.min)/2
1437
+ #ymag = (section.data.map{|dk| dk.y.data.max}.max +
1438
+ #section.data.map{|dk| dk.y.data.min}.min)/2
1439
+
1440
+ #ep 'dR', dR; gets
1441
+ #dy = (section.data.map{|dk| dk.y.data.max}.max +
1442
+ #section.data.map{|dk| dk.y.data.min}.min)/2
1443
+ dz = (section.data.map{|dk| dk.z.data.max}.max +
1444
+ section.data.map{|dk| dk.z.data.min}.min )/2
1445
+ section.data.each do |dk|
1446
+ #dk.x.data -= options[:Rgeo]*(magnify* (1.0-Math.exp(-(magnify-1)**2)))*c/1.2
1447
+ #dk.x.data -= (options[:Rgeo]-options[:rhoc_actual])*([magnify-2, 0].max)*c* (1.0-Math.exp(-(magnify-1)**2))
1448
+ ep 'rhoc', options[:rhoc_actual]
1449
+ #dR = options[:Rgeo]*(0.75*magnify - magnify * (1.0 - options[:rhoc_actual]/options[:Rgeo]))* (1.0-Math.exp(-(magnify-1)**2))
1450
+ c = Math.cos(tv[0])
1451
+ s = Math.sin(tv[0])
1452
+ #dR = options[:Rgeo]*(1.5 - magnify * (1.0 - options[:rhoc_actual]))* (1.0-Math.exp(-(magnify-1)**2))
1453
+
1454
+ rout = 2.0
1455
+ dk.x.data -= (dR - options[:Rgeo] * rout) * c* (1.0-Math.exp(-(magnify-1)**2))
1456
+ #ep dk.x.data.shape; gets
1457
+ #dk.y.data -= (options[:Rgeo]-options[:rhoc_actual])*([magnify-2, 0].max)*s* (1.0-Math.exp(-(magnify-1)**2))
1458
+ dk.y.data -= (dR - options[:Rgeo] * rout) * s* (1.0-Math.exp(-(magnify-1)**2))
1459
+ dk.z.data-=dz* (1.0-Math.exp(-(magnify-1)**2))
1460
+ end
1461
+ #return section
1462
+ kit = flux_tube + section
1463
+ kit.data.each{|dk| dk.gp.with = "pm3d"}
1464
+ kit += blacked_out
1465
+ kit.data.each{|dk| dk.gp.with = "pm3d"}
1466
+ kit.xlabel = 'X'
1467
+ ep phideg = tv[0]/Math::PI * 180
1468
+ kit.gp.view = [",#{(180-phideg)%360},2.0", "equal xyz"]
1469
+ kit.gp.hidden3d = ""
1470
+ kit.gp.pm3d = "depthorder"
1471
+ kit.xlabel = 'X (m)'
1472
+ kit.ylabel = 'Y (m)'
1473
+ kit.zlabel = "'Z (m)' rotate by 90"
1474
+ kit.title = "3-D Potential"
1475
+
1476
+ kit
1477
+ end
1478
+
1479
+
1480
+ def phi_real_space_surface_graphkit(options={})
1481
+ case options[:command]
1482
+ when :help
1483
+ return "The potential as a function of cartesian coordinates, plotted on the six outer surfaces of constant x, y and theta."
1484
+ when :options
1485
+ return [:Rgeo, :n0, :rho_star, :t_index, :nakx, :naky, :gs2_coordinate_factor, :xmax, :xmin, :ymax, :ymin, :thetamax, :thetamin, :ncopies]
1486
+ else
1487
+ if options[:ncopies]
1488
+ ops = options.dup
1489
+ ops.delete(:ncopies)
1490
+ return (options[:ncopies].times.map do |n|
1491
+ ops[:ncopy] = n
1492
+ phi_real_space_surface_graphkit(ops)
1493
+ end).sum
1494
+ end
1495
+ #zaxis = axiskit('phi0_over_x_over_y', options)
1496
+ #zaxis.data = zaxis.data.transpose
1497
+ #shape = zaxis.data.shape
1498
+ #carts = cartesian_coordinates_gsl_tensor(options)
1499
+ phi = options[:phi] || phi_real_space_gsl_tensor(options)
1500
+ sides = [:max, :min]
1501
+ kits = []
1502
+ [:y, :x, :theta].each_with_index do |coord,i|
1503
+ sides.each_with_index do |side,j|
1504
+ raise unless i.kind_of? Integer
1505
+ #return kit if coord + side == :xmax
1506
+ options[:phi] = phi
1507
+ options[:side] = side
1508
+ options[:coordinate] = coord
1509
+ kit = phi_flux_tube_boundary_surface_graphkit(options)
1510
+ kits.push kit
1511
+ end
1512
+ end
1513
+ k = kits.reverse.sum
1514
+ #k = kits[5] + kits[4] + kits[3] + kits[2] + kits[1] + kits[0]
1515
+ #k = kits[5] + kits[4] + kits[1] + kits[0]
1516
+ k.gp.pm3d = "depthorder"
1517
+ kit = k
1518
+ kit.data.each{|dk| dk.title = "notitle"}
1519
+ #k.compress_datakits = true
1520
+ if options[:gs2_coordinate_factor] and options[:gs2_coordinate_factor] == 1.0
1521
+ kit.xlabel = 'x (rho_i)'
1522
+ kit.ylabel = 'y (rho_i)'
1523
+ kit.zlabel = "'theta' rotate by 90"
1524
+ else
1525
+ kit.xlabel = 'X (m)'
1526
+ kit.ylabel = 'Y (m)'
1527
+ kit.zlabel = "'Z (m)' rotate by 90"
1528
+ end
1529
+ kit.title = "3-D Potential"
1530
+ return k
1531
+
1532
+ end
1533
+ end
1534
+ def phi_real_space_graphkit(options={})
1535
+ case options[:command]
1536
+ when :help
1537
+ return "The potential as a function of cartesian coordinates"
1538
+ when :options
1539
+ return [:rgbformulae, :limit, :t_index]
1540
+ else
1541
+ if options[:ncopies]
1542
+ ops = options.dup
1543
+ ops.delete(:ncopies)
1544
+ return (options[:ncopies].times.map do |n|
1545
+ ops[:ncopy] = n
1546
+ phi_real_space_graphkit(ops)
1547
+ end).sum
1548
+ end
1549
+ #zaxis = axiskit('phi0_over_x_over_y', options)
1550
+ #zaxis.data = zaxis.data.transpose
1551
+ #shape = zaxis.data.shape
1552
+ #carts = cartesian_coordinates_gsl_tensor(options)
1553
+ phi = phi_real_space_gsl_tensor(options)
1554
+ if options[:cyl]
1555
+ carts = cylindrical_coordinates_gsl_tensor(options) #.transpose(0,1,2,3)
1556
+ else
1557
+ carts = cartesian_coordinates_gsl_tensor(options)
1558
+ end
1559
+
1560
+ newshape = carts.shape.slice(1..3)
1561
+
1562
+ x = carts[0, false]; x.reshape!(*newshape)
1563
+ y = carts[1, false]; y.reshape!(*newshape)
1564
+ z = carts[2, false]; z.reshape!(*newshape)
1565
+
1566
+ unless options[:cyl]
1567
+ #x = x.transpose(2,1,0)
1568
+ #y = y.transpose(2,1,0)
1569
+ #z = z.transpose(2,1,0)
1570
+ #phi = phi.transpose(2,1,0)
1571
+ end
1572
+
1573
+
1574
+ kit = GraphKit.autocreate({
1575
+ x: GraphKit::AxisKit.autocreate({data: x, title: "X", units: "m"}),
1576
+ y: GraphKit::AxisKit.autocreate({data: y, title: "Y", units: "m"}),
1577
+ z: GraphKit::AxisKit.autocreate({data: z, title: "Z", units: "m"}),
1578
+ f: GraphKit::AxisKit.autocreate({data: phi, title: "Phi"})
1579
+ })
1580
+ # kit.xrange = [0,shape[0]]
1581
+ # kit.yrange = [0,shape[1]]
1582
+ kit.cbrange = options[:limit] if options[:limit]
1583
+ kit.title = "Phi"
1584
+ #kit.palette = "rgbformulae #{(options[:rgbformulae] or "-3,3,0")}"
1585
+ #kit.view = "map"
1586
+ kit.data[0].with = "pm3d"
1587
+ #kit.gp.pm3d = "interpolate 2,2"
1588
+ #kit.title = "Phi at the outboard midplane"
1589
+ # kit.data[0].with = (options[:with] or 'pm3d palette')
1590
+ kit.file_name = options[:graphkit_name]
1591
+ kit
1592
+ end
1593
+ end
1594
+ def phi_gs2_space_graphkit(options={})
1595
+ case options[:command]
1596
+ when :help
1597
+ return "The potential as a function of y, x and theta"
1598
+ when :options
1599
+ return [:rgbformulae, :limit, :t_index]
1600
+ else
1601
+ #zaxis = axiskit('phi0_over_x_over_y', options)
1602
+ #zaxis.data = zaxis.data.transpose
1603
+ #shape = zaxis.data.shape
1604
+ kit = GraphKit.autocreate({
1605
+ x: GraphKit::AxisKit.autocreate({data: gsl_vector('y',options), title: "y", units: "rho_#{species_letter}"}),
1606
+ y: AxisKit.autocreate({data: gsl_vector('x',options), title: "x", units: "rho_#{species_letter}"}),
1607
+ z: GraphKit::AxisKit.autocreate({data: gsl_vector('theta',options), title: "theta"}),
1608
+ f: GraphKit::AxisKit.autocreate({data: phi_real_space_gsl_tensor(options), title: "Phi"})
1609
+ })
1610
+ # kit.xrange = [0,shape[0]]
1611
+ # kit.yrange = [0,shape[1]]
1612
+ kit.cbrange = options[:limit] if options[:limit]
1613
+ kit.title = "Phi"
1614
+ #kit.palette = "rgbformulae #{(options[:rgbformulae] or "-3,3,0")}"
1615
+ #kit.view = "map"
1616
+ kit.data[0].with = "pm3d"
1617
+ #kit.title = "Phi at the outboard midplane"
1618
+ # kit.data[0].with = (options[:with] or 'pm3d palette')
1619
+ kit.file_name = options[:graphkit_name]
1620
+ kit
1621
+ end
1622
+ end
1623
+ def phi0_vs_x_vs_y_graphkit(options={})
1624
+ case options[:command]
1625
+ when :help
1626
+ return "The potential at the outboard midplane"
1627
+ when :options
1628
+ return [:rgbformulae, :limit]
1629
+ else
1630
+ zaxis = axiskit('phi0_over_x_over_y', options)
1631
+ zaxis.data = zaxis.data.transpose
1632
+ shape = zaxis.data.shape
1633
+ kit = GraphKit.autocreate({x: GraphKit::AxisKit.autocreate({data: (GSL::Vector.alloc((0...shape[0]).to_a)/shape[0] - 0.5) * (@x0 or @y0 * @jwist / 2 / Math::PI / @shat), title: "x", units: "rho_#{species_letter}"}), y: AxisKit.autocreate({data: (GSL::Vector.alloc((0...shape[1]).to_a)/shape[1] - 0.5) * @y0, title: "y", units: "rho_#{species_letter}"}), z: zaxis})
1634
+ # kit.xrange = [0,shape[0]]
1635
+ # kit.yrange = [0,shape[1]]
1636
+ kit.zrange = options[:limit] if options[:limit]
1637
+ kit.title = "Spectrum"
1638
+ kit.palette = "rgbformulae #{(options[:rgbformulae] or "-3,3,0")}"
1639
+ kit.view = "map"
1640
+ kit.style = "data pm3d"
1641
+ kit.title = "Phi at the outboard midplane"
1642
+ # kit.data[0].with = (options[:with] or 'pm3d palette')
1643
+ kit.file_name = options[:graphkit_name]
1644
+ kit
1645
+ end
1646
+ end
1647
+
1648
+ def growth_rate_by_mode_vs_time_graphkit(options={})
1649
+ options[:direction] = :mode
1650
+ growth_rate_by_kxy_or_mode_vs_time_graphkit(options)
1651
+ end
1652
+
1653
+ def growth_rate_by_kx_vs_time_graphkit(options={})
1654
+ options[:direction] = :kx
1655
+ growth_rate_by_kxy_or_mode_vs_time_graphkit(options)
1656
+ end
1657
+
1658
+ def growth_rate_by_ky_vs_time_graphkit(options={})
1659
+ options[:direction] = :ky
1660
+ growth_rate_by_kxy_or_mode_vs_time_graphkit(options)
1661
+ end
1662
+
1663
+ def growth_rate_by_kxy_or_mode_vs_time_graphkit(options={})
1664
+ case options[:command]
1665
+ when :help
1666
+ return "'growth_rate_by_ky_vs_time' or 'growth_rate_by_kx_vs_time': Growth rate vs time for a given kx or ky, integrated over the other direction"
1667
+ when :options
1668
+ return [:ky, :ky_index, :kx, :kx_index]
1669
+ else
1670
+ kxy = options[:direction]
1671
+ phiax = axiskit("growth_rate_by_#{kxy}_over_time", options)
1672
+ x = axiskit('t', options)
1673
+ x.data = x.data.subvector(0, x.data.size-1)
1674
+ kit = GraphKit.autocreate({x: x , y: phiax})
1675
+ kit.data[0].title = "Growth Rate: #{kxy} = #{options[kxy]}"
1676
+ kit.data[0].title = "gs2:#@run_name"
1677
+ kit.data[0].with = "l" #"linespoints"
1678
+ kit.file_name = options[:graphkit_name]
1679
+ kit
1680
+ end
1681
+ end
1682
+
1683
+ def es_heat_by_mode_vs_time_graphkit(options={})
1684
+ options[:direction] = :mode
1685
+ es_heat_by_kxy_or_mode_vs_time_graphkit(options)
1686
+ end
1687
+
1688
+ def es_heat_by_kx_vs_time_graphkit(options={})
1689
+ options[:direction] = :kx
1690
+ es_heat_by_kxy_or_mode_vs_time_graphkit(options)
1691
+ end
1692
+
1693
+ def es_heat_by_ky_vs_time_graphkit(options={})
1694
+ options[:direction] = :ky
1695
+ es_heat_by_kxy_or_mode_vs_time_graphkit(options)
1696
+ end
1697
+
1698
+ def es_heat_by_kxy_or_mode_vs_time_graphkit(options={})
1699
+ case options[:command]
1700
+ when :help
1701
+ return "'es_heat_by_ky_vs_time' or 'es_heat_by_kx_vs_time': Electrostatic Heat Flux vs Time for a given kx or ky, integrated over the other direction"
1702
+ when :options
1703
+ return [:ky, :ky_index, :kx, :kx_index, :species_index]
1704
+ else
1705
+ kxy = options[:direction]
1706
+ nt_options = options.dup # 'no time' options
1707
+ #nt_options.delete(:t_index) if nt_options[:t_index]
1708
+ #nt_options.delete(:frame_index) if nt_options[:frame_index]
1709
+ phiax = axiskit("es_heat_by_#{kxy}_over_time", nt_options)
1710
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: phiax})
1711
+ kit.data[0].title = "ES Heat Flux: #@run_name #{kxy} = #{options[kxy]}"
1712
+ kit.log_axis = 'y'
1713
+ #kit.data[0].title = "gs2:#@run_name"
1714
+ kit.data[0].with = "l" #"linespoints"
1715
+ kit.file_name = options[:graphkit_name]
1716
+ kit
1717
+ end
1718
+ end
1719
+ def phi2_by_mode_vs_time_graphkit(options={})
1720
+ options[:direction] = :mode
1721
+ phi2_by_kxy_or_mode_vs_time_graphkit(options)
1722
+ end
1723
+
1724
+ def phi2_by_kx_vs_time_graphkit(options={})
1725
+ options[:direction] = :kx
1726
+ phi2_by_kxy_or_mode_vs_time_graphkit(options)
1727
+ end
1728
+
1729
+ def phi2_by_ky_vs_time_graphkit(options={})
1730
+ options[:direction] = :ky
1731
+ phi2_by_kxy_or_mode_vs_time_graphkit(options)
1732
+ end
1733
+
1734
+ def phi2_by_kxy_or_mode_vs_time_graphkit(options={})
1735
+ case options[:command]
1736
+ when :help
1737
+ return "'phi2_by_ky_vs_time' or 'phi2_by_kx_vs_time': Phi^2 over time for a given kx or ky, integrated over the other direction"
1738
+ when :options
1739
+ return [:ky, :ky_index, :kx, :kx_index]
1740
+ else
1741
+ kxy = options[:direction]
1742
+
1743
+ # i.e. phi2_by_ky_vs_time or phi2_by_kx_vs_time or phi2_by_mode_vs_time
1744
+
1745
+ nt_options = options.dup # 'no time' options
1746
+ nt_options.delete(:t_index) if nt_options[:t_index]
1747
+ nt_options.delete(:frame_index) if nt_options[:frame_index]
1748
+ phiax = axiskit("phi2_by_#{kxy}_over_time", nt_options)
1749
+ kit = GraphKit.autocreate({x: axiskit('t', options), y: phiax})
1750
+ kit.data[0].title = "Phi^2 total: #{kxy} = #{options[kxy]}"
1751
+ if options[:t_index]
1752
+ # p 'hello'
1753
+ array_element = options[:t_index_window] ? options[:t_index] - options[:t_index_window][0] : options[:t_index] - 1
1754
+ # p phiax.data.size, array_element
1755
+ # p options[:t_index], options[:t_index_window]
1756
+ time = DataKit.autocreate({x: {data: GSL::Vector.alloc([list(:t)[options[:t_index]]])}, y: {data: GSL::Vector.alloc([phiax.data[array_element]]) } })
1757
+ time.pointsize = 3.0
1758
+ # p time
1759
+ # kit.data[0].axes[:x].data = -kit.data[0].axes[:x].data
1760
+ kit.data.push time
1761
+ if options[:with_moving_efn] and kxy==:ky
1762
+ tmax = kit.data[0].axes[:x].data[-1]
1763
+ # p 'tmax', tmax
1764
+
1765
+ theta_max = @g_exb * tmax * options[:ky] * 2 * Math::PI / list(:kx)[2]
1766
+ kit.each_axiskit(:x) do |axiskit|
1767
+ # p axiskit
1768
+ axiskit.data = axiskit.data / tmax * theta_max - theta_max
1769
+ end
1770
+ end
1771
+ end
1772
+ if options[:norm]
1773
+ xrange, yrange = kit.plot_area_size
1774
+ kit.each_axiskit(:y) do |axiskit|
1775
+ axiskit.data /= yrange[1] / (options[:height] or 1.0)
1776
+ end
1777
+ end
1778
+ kit.log_axis = 'y'
1779
+ #kit.data[0].title = "gs2:#@run_name"
1780
+ kit.data[0].with = "l" #"linespoints"
1781
+ kit.file_name = options[:graphkit_name]
1782
+ kit
1783
+ end
1784
+ end
1785
+ def apar2_vs_time_graphkit(options={})
1786
+ case options[:command]
1787
+ when :help
1788
+ return "Graph of apar^2 vs time integrated over all space. No options"
1789
+ when :options
1790
+ return []
1791
+ else
1792
+ kit = GraphKit.autocreate({x: axiskit('t'), y: axiskit('apar2_over_time', options)})
1793
+ kit.data[0].with = "l" #"linespoints"
1794
+ kit.data[0].title = "Apar^2 total:#@run_name"
1795
+ kit.file_name = options[:graphkit_name]
1796
+ kit.log_axis = 'y'
1797
+ kit
1798
+ end
1799
+ end
1800
+ def phi2tot_vs_time_graphkit(options={})
1801
+ case options[:command]
1802
+ when :help
1803
+ return "Graph of phi^2 vs time integrated over all space. No options"
1804
+ when :options
1805
+ return []
1806
+ else
1807
+ kit = GraphKit.autocreate({x: axiskit('t'), y: axiskit('phi2tot_over_time', options)})
1808
+ kit.data[0].with = "l" #"linespoints"
1809
+ kit.data[0].title = "Phi^2 total:#@run_name"
1810
+ kit.file_name = options[:graphkit_name]
1811
+ kit.log_axis = 'y'
1812
+ kit
1813
+ end
1814
+ end
1815
+ def spectrum_graphkit(options={})
1816
+ case options[:command]
1817
+ when :help
1818
+ return "Graph of phi^2 at a given time vs kx and ky"
1819
+ when :options
1820
+ return [:with]
1821
+ else
1822
+ # p @name_match
1823
+ #options[:times_kx4] = true if @name_match[:kxsq]
1824
+ zaxis = axiskit('spectrum_over_ky_over_kx', options)
1825
+ zaxis.data = zaxis.data.transpose
1826
+ kit = GraphKit.autocreate({y: axiskit('ky', options), x: axiskit('kx', options), z: zaxis})
1827
+ kit.title = "#{options[:log] ? "Log ": ""}Spectrum (phi^2#{options[:times_kx2] ? " * kx^2" : ""}#{options[:times_kx4] ? " * kx^4" : ""})"
1828
+ kit.data[0].with = (options[:with] or 'pm3d palette')
1829
+ kit.file_name = options[:graphkit_name]
1830
+ kit
1831
+ end
1832
+ end
1833
+ def spectrum_vs_kpar_vs_ky_graphkit(options={})
1834
+ case options[:command]
1835
+ when :help
1836
+ return "Graph of phi^2 * ky^2 at a given time vs kpar and ky"
1837
+ when :options
1838
+ return [:with, :log, :no_zonal, :no_kpar0]
1839
+ else
1840
+ # p @name_match
1841
+ #options[:times_kx4] = true if @name_match[:kxsq]
1842
+ zaxis = axiskit('spectrum_over_ky_over_kpar', options)
1843
+ zaxis.data = zaxis.data.transpose
1844
+ kit = GraphKit.autocreate({y: axiskit('ky', options), x: axiskit('kpar', options.modify({ky_index: 1, kx_index: 1})), z: zaxis})
1845
+ kit.title = "#{options[:log] ? "Log ": ""}Spectrum (phi^2 ky^2)"
1846
+ kit.data[0].with = (options[:with] or 'pm3d palette')
1847
+ kit.gp.view = "map" if options[:map]
1848
+ kit.file_name = options[:graphkit_name]
1849
+ kit
1850
+ end
1851
+ end
1852
+ def vspace_diagnostics_graphkit(options={})
1853
+ case options[:command]
1854
+ when :help
1855
+ return "Plots vspace diagnostics. All lines shouldn't stray much above 0.1 - otherwise large amounts of the distribution function is in the higher k velocity space and velocity space is probably unresolved. (NB This graph is here temporarily (ha ha) until I add the vspace diagnostics to the NetCDF file (or the apocalypse, whichever is sooner) EGH)"
1856
+ when :options
1857
+ return []
1858
+ else
1859
+ raise "Velocity space diagnostics not found" unless FileTest.exist? "#@directory/#@run_name.lpc" or FileTest.exist? "#@directory/#@run_name.vres"
1860
+ lpc = GSL::Vector.filescan("#@directory/#@run_name.lpc") rescue [[0], [0], [0]]
1861
+ vres = GSL::Vector.filescan("#@directory/#@run_name.vres") rescue [[0], [0], [0]]
1862
+ xaxis = AxisKit.autocreate({data: lpc[0], title: "Time"})
1863
+ data = [[lpc[0], lpc[1], "Pitch Angle Harmonics (lpc)"], [lpc[0], lpc[2], "Energy Harmonics (lpc)"], [vres[0], vres[1], "Pitch Angle Harmonics (vres)"], [vres[0], vres[2], "Energy Harmonics (vres)"]]
1864
+ kits = data.inject([]) do |arr, (x, vector, title)|
1865
+ arr + [GraphKit.autocreate({x: AxisKit.autocreate({data: x, title: "Time"}), y: AxisKit.autocreate({data: vector, title: title})})]
1866
+ end
1867
+ kit = kits.sum
1868
+ # exit
1869
+ kit.title = "Velocity Space Diagnostics"
1870
+ kit.ylabel = "Fraction of Dist Func Contained"
1871
+ kit.file_name = options[:graphkit_name]
1872
+ # kit.log_axis = 'y'
1873
+ kit
1874
+ end
1875
+ end
1876
+ def zonal_spectrum_graphkit(options={})
1877
+ case options[:command]
1878
+ when :help
1879
+ return "zonal_spectrum: Graph of kx^4 phi^2 vs kx for ky=0"
1880
+ when :options
1881
+ return [:t, :t_index]
1882
+ else
1883
+ options[:times_kx4] = true
1884
+ kit = GraphKit.autocreate({x: axiskit('kx', options), y: axiskit("zonal_spectrum", options)})
1885
+ kit.title = "Zonal Spectrum"
1886
+ kit.file_name = options[:graphkit_name] + options[:t_index].to_s
1887
+ kit.data[0].with = 'lp'
1888
+ kit.pointsize = 2.0
1889
+ kit
1890
+ end
1891
+ end
1892
+
1893
+
1894
+ end
1895
+
1896
+ include GraphKits
1897
+
1898
+ end
1899
+ end