gs2crmod 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/README.rdoc +19 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/ext/extconf.rb +9 -0
- data/ext/gs2crmod_ext.c +366 -0
- data/gs2crmod.gemspec +98 -0
- data/include/gs2crmod_ext.h +58 -0
- data/lib/gs2crmod/astrogk/astrogk.rb +201 -0
- data/lib/gs2crmod/astrogk/calculations.rb +57 -0
- data/lib/gs2crmod/astrogk/check_convergence.rb +7 -0
- data/lib/gs2crmod/astrogk/deleted_variables.rb +76 -0
- data/lib/gs2crmod/astrogk/graphs.rb +13 -0
- data/lib/gs2crmod/astrogk/gsl_data.rb +13 -0
- data/lib/gs2crmod/astrogk/gsl_tools.rb +182 -0
- data/lib/gs2crmod/astrogk/ingen.rb +18 -0
- data/lib/gs2crmod/astrogk/input_file_tools.rb +7 -0
- data/lib/gs2crmod/astrogk/namelist_tools.rb +14 -0
- data/lib/gs2crmod/astrogk/namelists.rb +2800 -0
- data/lib/gs2crmod/astrogk/properties.rb +17 -0
- data/lib/gs2crmod/astrogk/species_dependent_namelists.rb +228 -0
- data/lib/gs2crmod/astrogk/test_gs2.rb +231 -0
- data/lib/gs2crmod/astrogk.rb +200 -0
- data/lib/gs2crmod/calculations.rb +780 -0
- data/lib/gs2crmod/check_convergence.rb +179 -0
- data/lib/gs2crmod/deleted_variables.rb +916 -0
- data/lib/gs2crmod/graphs.rb +1899 -0
- data/lib/gs2crmod/graphs_rdoc.rb +556 -0
- data/lib/gs2crmod/gs2.rb +1143 -0
- data/lib/gs2crmod/gsl_data.rb +1181 -0
- data/lib/gs2crmod/gsl_data_3d.rb +705 -0
- data/lib/gs2crmod/gsl_tools.rb +187 -0
- data/lib/gs2crmod/ingen.rb +218 -0
- data/lib/gs2crmod/namelists.rb +5142 -0
- data/lib/gs2crmod/properties.rb +22 -0
- data/lib/gs2crmod/species_dependent_namelists.rb +228 -0
- data/lib/gs2crmod/test_gs2.rb +231 -0
- data/lib/gs2crmod.rb +2 -0
- data/lib/gs2crmod_extension.rb +1 -0
- data/test/helper.rb +18 -0
- data/test/test_gs2crmod.rb +7 -0
- 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
|