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,705 @@
|
|
1
|
+
require 'narray'
|
2
|
+
class NArray
|
3
|
+
def _dump *ignored
|
4
|
+
Marshal.dump :typecode => typecode, :shape => shape, :data => to_s
|
5
|
+
end
|
6
|
+
def self._load buf
|
7
|
+
h = Marshal.load buf
|
8
|
+
typecode = h[:typecode]
|
9
|
+
shape = h[:shape]
|
10
|
+
data = h[:data]
|
11
|
+
to_na data, typecode, *shape
|
12
|
+
end
|
13
|
+
def inspect
|
14
|
+
#ep "called inspect"
|
15
|
+
"#{self.class}.to_narray(#{self.to_a.inspect})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class GSL::Tensor
|
20
|
+
class << self
|
21
|
+
def method_missing(meth, *args)
|
22
|
+
#ep 'calling... ', meth, args
|
23
|
+
ans = new(NArray.send(meth, *args.reverse))
|
24
|
+
#ep 'got', ans
|
25
|
+
ans
|
26
|
+
end
|
27
|
+
end
|
28
|
+
attr_reader :narray
|
29
|
+
def self.alloc(*args)
|
30
|
+
new(NArray.float(*args.reverse))
|
31
|
+
end
|
32
|
+
def initialize(narray)
|
33
|
+
@narray = narray
|
34
|
+
end
|
35
|
+
def inspect
|
36
|
+
"GSL::Tensor.new(#{@narray.inspect})"
|
37
|
+
end
|
38
|
+
def [](*args)
|
39
|
+
#if args.inject(true){|b,i| b and i.kind_of? Integer}
|
40
|
+
#@narray[*args.reverse]
|
41
|
+
#else
|
42
|
+
#self.class.new(@narray[*args.reverse])
|
43
|
+
#end
|
44
|
+
case ans = @narray[*args.reverse]
|
45
|
+
when Numeric
|
46
|
+
ans
|
47
|
+
else
|
48
|
+
self.class.new(@narray[*args.reverse])
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
def []=(*args, value)
|
53
|
+
#def []=(*args)
|
54
|
+
#ep 'args', args, value
|
55
|
+
@narray[*args.reverse] = value
|
56
|
+
end
|
57
|
+
def shape
|
58
|
+
@narray.shape.reverse
|
59
|
+
end
|
60
|
+
def reshape!(*args)
|
61
|
+
#ep 'rags', args
|
62
|
+
@narray.reshape!(*args.reverse)
|
63
|
+
end
|
64
|
+
def to_a
|
65
|
+
@narray.transpose(*(0...@narray.shape.size).to_a.reverse).to_a
|
66
|
+
end
|
67
|
+
def transpose(*args)
|
68
|
+
self.class.new(@narray.transpose(*args))
|
69
|
+
end
|
70
|
+
def method_missing(meth, *args)
|
71
|
+
result = @narray.send(meth, *args.reverse)
|
72
|
+
if result.kind_of? NArray
|
73
|
+
self.class.new(result)
|
74
|
+
else
|
75
|
+
result
|
76
|
+
end
|
77
|
+
rescue NoMethodError
|
78
|
+
self.class.new(NMath.send(meth, @narray))
|
79
|
+
end
|
80
|
+
def iterate(&block)
|
81
|
+
shp = shape
|
82
|
+
cumul = 1
|
83
|
+
cumulshp = []
|
84
|
+
for i in 1..shape.size
|
85
|
+
cumulshp[shp.size-i] = cumul
|
86
|
+
cumul *= shp[shp.size-i]
|
87
|
+
end
|
88
|
+
#= shape.reverse.map{|dim| cumul*=(dim); cumul.to_i}.reverse
|
89
|
+
#ep cumulshp; gets
|
90
|
+
(cumulshp[0]*shp[0]).times do |n|
|
91
|
+
#indexes = cumulshp.reverse.map{|cumul| rem = n%cumul; n-=rem; rem}.reverse
|
92
|
+
indexes = cumulshp.map{|cumul| idx = (n/cumul).floor; n -= idx*cumul; idx}
|
93
|
+
yield(*indexes)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
def iterate_row_maj(&block)
|
97
|
+
shp = shape
|
98
|
+
cumul = 1
|
99
|
+
cumulshp = []
|
100
|
+
for i in 0...shape.size
|
101
|
+
cumulshp[i] = cumul
|
102
|
+
cumul *= shp[i]
|
103
|
+
end
|
104
|
+
#= shape.reverse.map{|dim| cumul*=(dim); cumul.to_i}.reverse
|
105
|
+
#ep cumulshp; gets
|
106
|
+
(cumulshp[-1]*shp[-1]).times do |n|
|
107
|
+
#indexes = cumulshp.reverse.map{|cumul| rem = n%cumul; n-=rem; rem}.reverse
|
108
|
+
indexes = cumulshp.reverse.map{|cumul| idx = (n/cumul).floor; n -= idx*cumul; idx}.reverse
|
109
|
+
yield(*indexes)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
end
|
116
|
+
class GSL::TensorComplex < GSL::Tensor
|
117
|
+
attr_reader :narray
|
118
|
+
def self.alloc(*args)
|
119
|
+
new(NArray.complex(*args.reverse))
|
120
|
+
end
|
121
|
+
def real
|
122
|
+
GSL::Tensor.new(@narray.real)
|
123
|
+
end
|
124
|
+
def abs
|
125
|
+
GSL::Tensor.new(@narray.abs)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
class CodeRunner::Gs2
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
def gsl_tensor(name, options)
|
133
|
+
tensor = send((name.to_s+"_gsl_tensor").to_sym , options)
|
134
|
+
end
|
135
|
+
module GSLTensors
|
136
|
+
def field_gsl_tensor(options)
|
137
|
+
if options[:t_index]
|
138
|
+
#ep options; gets
|
139
|
+
raise CRFatal.new("write_phi_over_time is not enabled so this function won't work") unless @write_phi_over_time
|
140
|
+
arr = GSL::Tensor.new(netcdf_file.var(options[:field_name].to_s + '_t').get({'start' => [0,(options[:thetamin]||0),0,0, options[:t_index] - 1], 'end' => [-1,(options[:thetamax]||-1),(options[:nakx]||0)-1,(options[:naky]||0)-1, options[:t_index] - 1]}))
|
141
|
+
#ep 'arr.shape', arr.shape
|
142
|
+
arr.reshape!(*arr.shape.slice(1...arr.shape.size))
|
143
|
+
|
144
|
+
else
|
145
|
+
arr = GSL::Tensor.new(netcdf_file.var(options[:field_name]).get({'start' => [0,(options[:thetamin]||0),0,0], 'end' => [-1,(options[:thetamax]||-1),(options[:nakx]||0)-1,(options[:naky]||0)-1]}))
|
146
|
+
#ep 'arr.shape', arr.shape
|
147
|
+
end
|
148
|
+
arr[0, true, true, true] = 0.0 if options[:no_zonal]
|
149
|
+
#arr = arr[options[:nakx] ? 0...options[:nakx] : true, options[:naky] ? 0...options[:naky] : true, true, true] if options[:nakx] or options[:naky]
|
150
|
+
return arr
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns a rank 3 tensor which is the real potential (i.e. Fourier transformed from the GS2 output) as a function of the y index, the x index and the theta index.
|
155
|
+
|
156
|
+
def phi_real_space_gsl_tensor(options)
|
157
|
+
return field_real_space_gsl_tensor(options.absorb(field_name: :phi))
|
158
|
+
end
|
159
|
+
|
160
|
+
def field_real_space_gsl_tensor(options)
|
161
|
+
fieldc = field_gsl_tensor_complex(options)
|
162
|
+
shape = fieldc.shape
|
163
|
+
workspacex = GSL::Vector::Complex.alloc(shape[1])
|
164
|
+
workspacey = GSL::Vector.alloc(shape[0]*2-2+shape[0]%2)
|
165
|
+
field_real_space = GSL::Tensor.alloc(workspacey.size, shape[1], shape[2])
|
166
|
+
for j in 0...shape[2] #theta
|
167
|
+
for i in 0...shape[0] #ky
|
168
|
+
#narr = fieldc[i, true, j]
|
169
|
+
for k in 0...shape[1]
|
170
|
+
workspacex[k] = GSL::Complex.alloc(fieldc[i,k,j].real, fieldc[i,k,j].imag)
|
171
|
+
end
|
172
|
+
workspacex = workspacex.backward
|
173
|
+
for k in 0...shape[1]
|
174
|
+
fieldc[i,k,j] = Complex(*workspacex[k].to_a)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
for k in 0...shape[1] #kx
|
178
|
+
m = 0
|
179
|
+
for i in 0...shape[0] #ky
|
180
|
+
workspacey[m] = fieldc[i,k,j].real
|
181
|
+
m+=1
|
182
|
+
next if i==0 or (shape[0]%2==0 and i == shape[0]/2 + 1)
|
183
|
+
workspacey[m] = fieldc[i,k,j].imag
|
184
|
+
m+=1
|
185
|
+
end
|
186
|
+
workspacey = workspacey.backward
|
187
|
+
for i in 0...workspacey.size
|
188
|
+
field_real_space[i,k,j] = workspacey[i]
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
shp = field_real_space.shape
|
193
|
+
#ep options
|
194
|
+
field_real_space = field_real_space[options[:ymin]||0..options[:ymax]||(shp[0]-1), options[:xmin]||0..options[:xmax]||(shp[1]-1), true]
|
195
|
+
if kint = options[:interpolate_theta]
|
196
|
+
shape = field_real_space.shape
|
197
|
+
new_shape = shape.dup
|
198
|
+
new_shape[-1] = ((shape[-1]-1)*kint+1)
|
199
|
+
field_real_space_new = GSL::Tensor.float(*new_shape)
|
200
|
+
#p shape,new_shape
|
201
|
+
for i in 0...(new_shape[0])
|
202
|
+
for j in 0...(new_shape[1])
|
203
|
+
field_real_space_new[i,j, new_shape[-1]-1] = field_real_space[i,j,shape[-1]-1] # set the endpoint
|
204
|
+
for k in 0...(new_shape[-1]-1)
|
205
|
+
km = k%kint
|
206
|
+
frac = km.to_f/kint.to_f
|
207
|
+
#kold = (k-km)/(new_shape[-1]-1)*(shape[-1]-1)
|
208
|
+
kold = (k-km)/kint
|
209
|
+
#ep ['k', k, 'kold', kold]
|
210
|
+
field_real_space_new[i,j, k] = field_real_space[i,j, kold] * (1.0-frac) + field_real_space[i,j, kold+1] * frac
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
field_real_space = field_real_space_new
|
215
|
+
end
|
216
|
+
|
217
|
+
return field_real_space
|
218
|
+
|
219
|
+
end
|
220
|
+
def field_real_space_gsl_tensor_2(options)
|
221
|
+
field = field_gsl_tensor(options)
|
222
|
+
field_narray = field.narray
|
223
|
+
shape = field.shape
|
224
|
+
workspacex = GSL::Vector::Complex.alloc(shape[1])
|
225
|
+
workspacey = GSL::Vector.alloc(shape[0]*2-2+shape[0]%2)
|
226
|
+
field_real_space = GSL::Tensor.alloc(workspacey.size, shape[1], shape[2])
|
227
|
+
field_real_space_narray = field_real_space.narray
|
228
|
+
for j in 0...shape[2] #theta
|
229
|
+
for i in 0...shape[0] #ky
|
230
|
+
#narr = fieldc[i, true, j]
|
231
|
+
for k in 0...shape[1]
|
232
|
+
workspacex[k] = GSL::Complex.alloc(field_narray[0,j,k,i], field_narray[1,j,k,i])
|
233
|
+
end
|
234
|
+
workspacex = workspacex.backward
|
235
|
+
for k in 0...shape[1]
|
236
|
+
field_narray[0,j,k,i] = workspacex[k].real
|
237
|
+
field_narray[1,j,k,i] = workspacex[k].imag
|
238
|
+
end
|
239
|
+
end
|
240
|
+
for k in 0...shape[1] #kx
|
241
|
+
m = 0
|
242
|
+
for i in 0...shape[0] #ky
|
243
|
+
workspacey[m] = field_narray[0,j,k,i]
|
244
|
+
m+=1
|
245
|
+
next if i==0 or (shape[0]%2==0 and i == shape[0]/2 + 1)
|
246
|
+
workspacey[m] = field_narray[1,j,k,i]
|
247
|
+
m+=1
|
248
|
+
end
|
249
|
+
workspacey = workspacey.backward
|
250
|
+
for i in 0...workspacey.size
|
251
|
+
field_real_space_narray[j,k,i] = workspacey[i]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
shp = field_real_space.shape
|
256
|
+
#p 'test', field_real_space[0,2,3]
|
257
|
+
#ep options
|
258
|
+
field_real_space = field_real_space[options[:ymin]||0..options[:ymax]||(shp[0]-1), options[:xmin]||0..options[:xmax]||(shp[1]-1), true]
|
259
|
+
#p 'test2', field_real_space[0,2,3]
|
260
|
+
if kint = options[:interpolate_theta]
|
261
|
+
shape = field_real_space.shape
|
262
|
+
new_shape = shape.dup
|
263
|
+
new_shape[-1] = ((shape[-1]-1)*kint+1)
|
264
|
+
field_real_space_new = GSL::Tensor.float(*new_shape)
|
265
|
+
field_real_space_new_narray = field_real_space_new.narray
|
266
|
+
#p shape,new_shape
|
267
|
+
for i in 0...(new_shape[0])
|
268
|
+
for j in 0...(new_shape[1])
|
269
|
+
field_real_space_new_narray[new_shape[-1]-1, j, i] = field_real_space_narray[shape[-1]-1, j, i] # set the endpoint
|
270
|
+
for k in 0...(new_shape[-1]-1)
|
271
|
+
km = k%kint
|
272
|
+
frac = km.to_f._orig_div(kint.to_f)
|
273
|
+
#kold = (k-km)/(new_shape[-1]-1)*(shape[-1]-1)
|
274
|
+
kold = (k-km)._orig_div(kint)
|
275
|
+
#ep ['k', k, 'kold', kold]
|
276
|
+
field_real_space_new_narray[k,j,i] = field_real_space_narray[kold,j,i]._orig_mul(1.0-frac) + field_real_space_narray[kold+1,j,i]._orig_mul(frac)
|
277
|
+
#if (i==0 and j==2 and k==3)
|
278
|
+
#p ['frac', frac]
|
279
|
+
#end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
field_real_space = field_real_space_new
|
284
|
+
end
|
285
|
+
#p field_real_space_new.shape;
|
286
|
+
|
287
|
+
return field_real_space
|
288
|
+
|
289
|
+
end
|
290
|
+
def apar_gsl_tensor(options)
|
291
|
+
return GSL::Tensor.new(netcdf_file.var('apar').get)
|
292
|
+
end
|
293
|
+
def bpar_gsl_tensor(options)
|
294
|
+
return GSL::Tensor.new(netcdf_file.var('bpar').get)
|
295
|
+
end
|
296
|
+
# Order is R0,Z0,a0,Rprim,Zprim,aprim
|
297
|
+
def geometric_factors_gsl_tensor(options)
|
298
|
+
#ops = options.dup; ops.delete :phi
|
299
|
+
#ep ops; gets
|
300
|
+
case @equilibrium_option
|
301
|
+
when "s-alpha"
|
302
|
+
return geometric_factors_salpha_gsl_tensor(options)
|
303
|
+
else
|
304
|
+
theta_vec = gsl_vector(:theta, options)
|
305
|
+
factors = GSL::Tensor.alloc(6,theta_vec.size)
|
306
|
+
values = File.read("#@directory/#@run_name.g").split(/\s*\n\s*/)
|
307
|
+
3.times{values.shift}
|
308
|
+
values = values.map{|str| str.split(/\s+/).map{|s| s.to_f}}.transpose
|
309
|
+
#ep values
|
310
|
+
shape = factors.shape
|
311
|
+
for i in 0...shape[0]
|
312
|
+
unless options[:interpolate_theta]
|
313
|
+
for j in 0...shape[1]
|
314
|
+
factors[i,j] = values[i+1][j]
|
315
|
+
end
|
316
|
+
else
|
317
|
+
opts = options.dup
|
318
|
+
opts[:interpolate_theta] = nil
|
319
|
+
theta_vec_short = gsl_vector(:theta, {})
|
320
|
+
p 'sizes', [theta_vec_short.size, values[i+1].to_gslv.size]
|
321
|
+
interp = GSL::ScatterInterp.alloc(:linear, [theta_vec_short, values[i+1].to_gslv], true)
|
322
|
+
for j in 0...shape[1]
|
323
|
+
factors[i,j] = interp.eval(theta_vec[j])
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
#ep factors
|
328
|
+
return factors
|
329
|
+
end
|
330
|
+
end
|
331
|
+
# Order is R0,Z0,a0,Rprim,Zprim,aprim
|
332
|
+
def geometric_factors_salpha_gsl_tensor(options)
|
333
|
+
raise "Please specify options[:Rgeo]" unless options[:Rgeo]
|
334
|
+
theta_vec = gsl_vector(:theta, options)
|
335
|
+
factors = GSL::Tensor.alloc(6,theta_vec.size)
|
336
|
+
q_actual = options[:q_actual]
|
337
|
+
pka = epsl/q_actual
|
338
|
+
#pka = @pk||2*@kp
|
339
|
+
for i in 0...theta_vec.size
|
340
|
+
theta = theta_vec[i]
|
341
|
+
c = Math.cos(theta)
|
342
|
+
s = Math.sin(theta)
|
343
|
+
factors[0,i] = options[:Rgeo]*(1.0 + eps * c + eps * (shift||0))
|
344
|
+
factors[1,i] = options[:Rgeo] * eps * s
|
345
|
+
factors[2,i] = -epsl/pka * theta - eps * epsl/pka * s
|
346
|
+
factors[3,i] = c * options[:Rgeo] * eps / 2
|
347
|
+
factors[4,i] = s * options[:Rgeo] * eps / 2
|
348
|
+
factors[5,i] = - theta * epsl**2 / 2 / pka / eps * (shat||0) - epsl**2 / 2 / pka * s
|
349
|
+
end
|
350
|
+
return factors
|
351
|
+
end
|
352
|
+
private :geometric_factors_salpha_gsl_tensor
|
353
|
+
|
354
|
+
# Returns a rank 2 tensor, which gives, as a function of the x index j and the theta index k, the y index nearest to a poloidal plane at angle options[:torphi] is the torus was filled with periodic copies of the flux surface. Used for making cross sections at a constant toroidal angle.
|
355
|
+
|
356
|
+
def constant_torphi_surface_gsl_tensor(options)
|
357
|
+
ops = options.dup
|
358
|
+
IRRELEVANT_INDICES.each{|v| ops.delete(v)}
|
359
|
+
return cache[[:constant_torphi_surface_gsl_tensor, ops]] if cache[[:constant_torphi_surface_gsl_tensor, ops]]
|
360
|
+
correct_3d_options(options)
|
361
|
+
torphiout = options[:torphi]
|
362
|
+
cyls = cylindrical_coordinates_gsl_tensor(options.absorb({extra_points: :y}))
|
363
|
+
shpc = cyls.shape
|
364
|
+
factors = geometric_factors_gsl_tensor(options)
|
365
|
+
#ep shpc, 'shpc'
|
366
|
+
#xsize = case shpc[2]
|
367
|
+
|
368
|
+
yvec = gsl_vector('y', options)
|
369
|
+
#ep yvec.to_a ; gets
|
370
|
+
x = gsl_vector('x', options)
|
371
|
+
dy = yvec[1] - yvec[0]
|
372
|
+
torphi_const = GSL::Tensor.int(shpc[2], shpc[3]) # don't include extra x point
|
373
|
+
xfac = 1.0 / options[:rho_star_actual]
|
374
|
+
yfac = options[:rhoc_actual] / options[:q_actual] / options[:rho_star_actual]
|
375
|
+
#coordinates[2,i,j,k] = y[i] / yfac - factors[2,k] - x[j]/xfac*factors[5,k] # phi
|
376
|
+
twopi = Math::PI*2
|
377
|
+
for j in 0...shpc[2]
|
378
|
+
for k in 0...shpc[3]
|
379
|
+
y = yfac * (torphiout + factors[2,k] + x[j]/xfac*factors[5,k])
|
380
|
+
if options[:no_copies]
|
381
|
+
i = (y/dy).floor
|
382
|
+
else
|
383
|
+
i = (y/dy).floor % yvec.size
|
384
|
+
end
|
385
|
+
torphi_const[j,k] = i
|
386
|
+
end
|
387
|
+
end
|
388
|
+
return torphi_const
|
389
|
+
|
390
|
+
#ep torphi_const; gets
|
391
|
+
end
|
392
|
+
#def constant_torphi_surface_gsl_tensor2(options)
|
393
|
+
#ops = options.dup
|
394
|
+
#IRRELEVANT_INDICES.each{|v| ops.delete(v)}
|
395
|
+
#return cache[[:constant_torphi_surface_gsl_tensor, ops]] if cache[[:constant_torphi_surface_gsl_tensor, ops]]
|
396
|
+
#torphiout = options[:torphi]
|
397
|
+
#correct_3d_options(options)
|
398
|
+
#cyls = cylindrical_coordinates_gsl_tensor(options.absorb({extra_points: :y}))
|
399
|
+
#shpc = cyls.shape
|
400
|
+
##ep shpc, 'shpc'
|
401
|
+
##xsize = case shpc[2]
|
402
|
+
|
403
|
+
#torphi_const = GSL::Tensor.int(shpc[2], shpc[3]) # don't include extra x point
|
404
|
+
##ep torphi_const; gets
|
405
|
+
#y = gsl_vector('y', options)
|
406
|
+
#lastbracketed = nil
|
407
|
+
#lastj = -1
|
408
|
+
#for k in 0...shpc[3] # theta index
|
409
|
+
#for j in 0...(shpc[2]) # x index
|
410
|
+
#deltorphi = cyls[2,shpc[1]-1,j,k] - cyls[2,0,j,k]
|
411
|
+
#raise "Periodicity not satisfied: #{(2*Math::PI/deltorphi+1.0e-8)%1.0}, #{(2*Math::PI/deltorphi+1.0e-5)}" unless ((2.0*Math::PI/deltorphi)+1.0e-8)%1.0 < 1.0e-5
|
412
|
+
#m3 = (torphiout)%deltorphi
|
413
|
+
#for i in 0...shpc[1]-1 # y index, excluding periodic extra point
|
414
|
+
##p i
|
415
|
+
#torphi1 = cyls[2,i,j,k]
|
416
|
+
#torphi2 = cyls[2,i+1,j,k]
|
417
|
+
##ep cyls[2,true,j,k].to_a
|
418
|
+
#m1 = (torphi1 )%deltorphi
|
419
|
+
#m2 = (torphi2 )%deltorphi
|
420
|
+
#bracketed = ((m1-m3).abs < 1.0e-4) || (
|
421
|
+
#(m2-m3.abs) > 1.0e-4 &&
|
422
|
+
#(m2 - m3) *
|
423
|
+
#(m1 - m3) *
|
424
|
+
#(m2 - m1) *
|
425
|
+
#(torphi2 - torphi1) < 0)
|
426
|
+
##p 'n0', (2*Math::PI/deltorphi).round
|
427
|
+
#bracketed2 = (2*Math::PI/deltorphi + 1).round.times.inject(false) do |b,n|
|
428
|
+
#epsn = 1.0e-4
|
429
|
+
#eps2 = 1.0e-4
|
430
|
+
#upp = torphiout + deltorphi * n
|
431
|
+
#lwr = torphiout - deltorphi * n
|
432
|
+
##measure = ((torphi1 < upp or (torphi1 - upp).abs < epsn) and upp+epsn < torphi2) or ((torphi1 < lwr or (torphi1-lwr).abs < eps) and lwr + eps < torphi2)
|
433
|
+
#a1 = a2 = a3 = b1 = b2 = b3 = 'q'
|
434
|
+
##measure = ((
|
435
|
+
###a1=((torphi1-upp).abs < (torphi2-upp).abs) and
|
436
|
+
##(a1=((torphi2-upp).abs > 1.0e-7)) and
|
437
|
+
##(a2=((torphi1 < upp or (torphi1 - upp).abs < epsn))) and
|
438
|
+
##(a3=(upp < torphi2))
|
439
|
+
##) or (
|
440
|
+
###b1=((torphi1-lwr).abs < (torphi2-lwr).abs) and
|
441
|
+
##(b1=((torphi2-lwr).abs > 1.0e7)) and
|
442
|
+
##(b2=(torphi1 < lwr or (torphi1-lwr).abs < epsn)) and
|
443
|
+
##(b3 = (lwr < torphi2))
|
444
|
+
##))
|
445
|
+
#a1=((torphi2-upp).abs > eps2)
|
446
|
+
#a2=((torphi1 < upp or (torphi1 - upp).abs < epsn))
|
447
|
+
#a3=(upp < torphi2)
|
448
|
+
#b1=(torphi2-lwr).abs > eps2
|
449
|
+
#b2=(torphi1 < lwr or (torphi1-lwr).abs < epsn)
|
450
|
+
#b3 = (lwr < torphi2)
|
451
|
+
#measure = ((a1 and a2 and a3) or (b1 and b2 and b3))
|
452
|
+
##p 'measure', measure, [torphi1, torphi2, upp, lwr , i,j,k, y[i], y[(i+1)%y.size], deltorphi, n, a1, a2, a3, b1, b2, b3] if measure and j==0 #; gets if [j,k] == [5,8] # if measure
|
453
|
+
#b or measure
|
454
|
+
#end
|
455
|
+
##bracketed = bracketed2
|
456
|
+
#raise "Measures don't agree #{bracketed}, #{bracketed2}" unless bracketed2 == bracketed
|
457
|
+
|
458
|
+
|
459
|
+
##d2 = torphi2 - torphiout
|
460
|
+
##d1 = torphiout - torphi1
|
461
|
+
#if bracketed
|
462
|
+
#raise "Doubled up" if lastbracketed == [j,k]
|
463
|
+
#raise "Missed: #{j},#{k}, #{lastbracketed.inspect} #{[j-1,k].inspect} #{[shpc[2]-1, k-1].inspect}" unless lastbracketed == [j-1,k] or lastbracketed == [shpc[2]-1, k-1] if lastbracketed
|
464
|
+
#torphi_const[j,k] = i
|
465
|
+
#lastbracketed = [j,k]
|
466
|
+
#lastj = j
|
467
|
+
#end
|
468
|
+
#end # y loop
|
469
|
+
#end # x loop
|
470
|
+
#end # theta loop
|
471
|
+
##torphi_const2 = constant_torphi_surface_gsl_tensor2(options)
|
472
|
+
##p 'the same? ', torphi_const2.to_a, torphi_const.to_a, torphi_const2 == torphi_const
|
473
|
+
##exit
|
474
|
+
##exit
|
475
|
+
#cache[[:constant_torphi_surface_gsl_tensor, ops]] = torphi_const
|
476
|
+
## save the run to save the hard_cache
|
477
|
+
#return torphi_const
|
478
|
+
#end
|
479
|
+
|
480
|
+
FIELD_VALUES = [:phi]
|
481
|
+
TRIVIAL_INDICES = [:graphkit_name]
|
482
|
+
TIME_VARYING_INDICES = [:t_index, :begin_element, :end_element, :frame_index, :t_index_window]
|
483
|
+
IRRELEVANT_INDICES = FIELD_VALUES + TRIVIAL_INDICES + TIME_VARYING_INDICES
|
484
|
+
|
485
|
+
# Adjust n0, rho_star_actual and q_actual to ensure periodicity
|
486
|
+
#
|
487
|
+
def correct_3d_options(options)
|
488
|
+
raise "Please specify options[:rho_star] or options[:n0]" unless options[:rho_star] or options[:n0]
|
489
|
+
case @equilibrium_option
|
490
|
+
when "s-alpha"
|
491
|
+
qinp = epsl / (pk||2*kp)
|
492
|
+
#xfac = @epsl**4/options[:rho_star]/4/pka**2/@eps**2
|
493
|
+
#xfac_geo = 1
|
494
|
+
#yfac = 1/options[:rho_star]/@epsl*2*pka*@eps
|
495
|
+
#yfac_geo = 2*pka*@eps/@epsl**2
|
496
|
+
#yfac_geo = 2*pka*@eps/@epsl**2
|
497
|
+
options[:rhoc_actual] =rhoc = 2 * eps / epsl
|
498
|
+
else
|
499
|
+
options[:rhoc_actual] = rhoc = @rhoc
|
500
|
+
qinp = @qinp
|
501
|
+
end
|
502
|
+
#eputs "Checking that rho_star and q satisfy periodicity..."
|
503
|
+
rho_star_inp = options[:rho_star]
|
504
|
+
y = gsl_vector('y', options)
|
505
|
+
ly = (y[1]-y[0]) * (y.size)
|
506
|
+
n0_fac = 2.0*Math::PI * rhoc / ly
|
507
|
+
n0_inp = options[:n0] || n0_fac / qinp / rho_star_inp
|
508
|
+
if n0_inp%1.0==0.0
|
509
|
+
n0 = n0_inp
|
510
|
+
else
|
511
|
+
#eputs "Input n0 is equal to #{n0_inp}..."
|
512
|
+
n0 = n0_inp.ceil
|
513
|
+
#eputs "Set n0 to #{n0}..."
|
514
|
+
end
|
515
|
+
|
516
|
+
if (qinp*n0)%1.0==0.0
|
517
|
+
q_actual = qinp
|
518
|
+
else
|
519
|
+
q_actual = (qinp*n0).round.to_f/n0
|
520
|
+
#eputs "Set q to #{q_actual}..."
|
521
|
+
end
|
522
|
+
options[:q_actual] = q_actual
|
523
|
+
unless options[:rho_star_actual] and options[:rho_star_actual] == n0_fac/n0/q_actual
|
524
|
+
#eputs "Adjusting rho_star to satisfy periodicity ..."
|
525
|
+
options[:rho_star_actual] = n0_fac/n0/q_actual
|
526
|
+
#eputs "Set rhostar to #{options[:rho_star_actual]}..."
|
527
|
+
#eputs "Note... to avoid adjustment of q specify n0 as an input rather than rho_star. Make sure that n0 is an integer and n0 * q is an integer."
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
|
532
|
+
# Return a rank 4 tensor which give
|
533
|
+
# cylindrical coordinates R,Z,torphi as a function
|
534
|
+
# of gs2 coordinates y, x, theta.
|
535
|
+
#
|
536
|
+
# a = cylindrical_coordinates_gsl_tensor(options)
|
537
|
+
#
|
538
|
+
# # pseudocode
|
539
|
+
# R(y[i], x[j], theta[k]) = a[0,i,j,k]
|
540
|
+
# Z(y[i], x[j], theta[k]) = a[1,i,j,k]
|
541
|
+
# torphi(y[i], x[j], theta[k]) = a[2,i,j,k]
|
542
|
+
def cylindrical_coordinates_gsl_tensor(options)
|
543
|
+
ops = options.dup
|
544
|
+
(IRRELEVANT_INDICES + [:torphi, :torphi_values]).each{|v| ops.delete(v)}
|
545
|
+
return cache[[:cylindrical_coordinates_gsl_tensor, ops]] if cache[[:cylindrical_coordinates_gsl_tensor, ops]]
|
546
|
+
#ep ops; gets
|
547
|
+
#options = options.dup
|
548
|
+
x = gsl_vector('x', options)
|
549
|
+
y = gsl_vector('y', options)
|
550
|
+
ly = 2*Math::PI*y0#(y[1]-y[0]) * (y.size)
|
551
|
+
if [true,:x].include? options[:extra_points]
|
552
|
+
ep "Extending x..."
|
553
|
+
x = x.connect([2*x[-1] - x[-2]].to_gslv).dup
|
554
|
+
end
|
555
|
+
if [true,:y].include? options[:extra_points]
|
556
|
+
ep "Extending y..."
|
557
|
+
y = y.connect([2*y[-1] - y[-2]].to_gslv).dup
|
558
|
+
raise "ly corrected incorrectly #{ly},#{y[-1]},#{y[0]},#{y[-1]-y[0]}" unless (ly-(y[-1] - y[0])).abs / ly.abs < 1.0e-8
|
559
|
+
end
|
560
|
+
|
561
|
+
|
562
|
+
#if options[:xmax]
|
563
|
+
#if options[:xmin]
|
564
|
+
#x = x.subvector(options[:xmin], options[:xmax] - options[:xmin])
|
565
|
+
#else
|
566
|
+
#x = x[options[:xmax]].to_gslv
|
567
|
+
#end
|
568
|
+
#elsif options[:xmin]
|
569
|
+
#x = x[options[:xmin]].to_gslv
|
570
|
+
#end
|
571
|
+
#if options[:ymax]
|
572
|
+
#if options[:ymin]
|
573
|
+
#y = y.subvector(options[:ymin], options[:ymax] - options[:ymin])
|
574
|
+
#else
|
575
|
+
#y = y[options[:ymax]].to_gslv
|
576
|
+
#end
|
577
|
+
#elsif options[:ymin]
|
578
|
+
#y = y[options[:ymin]].to_gslv
|
579
|
+
#end
|
580
|
+
|
581
|
+
|
582
|
+
|
583
|
+
#ep [options, options[:xmin]||0, (options[:xmax]||x.size-1) - (options[:xmin]||0) + 1]
|
584
|
+
x = x.subvector(options[:xmin]||0, (options[:xmax]||x.size-1) - (options[:xmin]||0) + 1).dup # if options[:xout] and options[:xin]
|
585
|
+
y = y.subvector(options[:ymin]||0, (options[:ymax]||y.size-1) - (options[:ymin]||0) + 1).dup # if options[:yout] and options[:yin]
|
586
|
+
###y = y.subvector(options[:ymin], options[:ymax] - options[:ymin] + 1)# if yi = options[:yout] and options[:yin]
|
587
|
+
#
|
588
|
+
###ep 'ncopy', options[:ncopy]
|
589
|
+
#y = y + options[:ncopy] * (y[-1]-y[0]) if options[:ncopy]
|
590
|
+
y = y + options[:ncopy] * ly if options[:ncopy]
|
591
|
+
#ep 'y', y
|
592
|
+
#ep y; gets
|
593
|
+
#ep options; gets
|
594
|
+
theta = gsl_vector('theta', options)
|
595
|
+
#ep theta; gets;
|
596
|
+
#ep 'thsize', @ntheta, theta.size
|
597
|
+
correct_3d_options(options)
|
598
|
+
rhoc = options[:rhoc_actual]
|
599
|
+
q_actual = options[:q_actual]
|
600
|
+
xfac = 1.0 / options[:rho_star_actual]
|
601
|
+
yfac = rhoc / q_actual / options[:rho_star_actual]
|
602
|
+
factors = geometric_factors_gsl_tensor(options)
|
603
|
+
|
604
|
+
|
605
|
+
|
606
|
+
|
607
|
+
coordinates = GSL::Tensor.alloc(3, y.size, x.size, theta.size)
|
608
|
+
for i in 0...y.size
|
609
|
+
for j in 0...x.size
|
610
|
+
for k in 0...theta.size
|
611
|
+
coordinates[0,i,j,k] = factors[0,k] + x[j]/xfac*factors[3,k] # R
|
612
|
+
coordinates[1,i,j,k] = factors[1,k] + x[j]/xfac*factors[4,k] # Z
|
613
|
+
coordinates[2,i,j,k] = y[i] / yfac - factors[2,k] - x[j]/xfac*factors[5,k] # phi
|
614
|
+
#ep [i,j,k], coordinates[0, false, j,k].to_a
|
615
|
+
if gs2f = options[:gs2_coordinate_factor]
|
616
|
+
rgs2 = (x[j]**2 + y[i]**2)**0.5
|
617
|
+
if rgs2 < 1.0e-8
|
618
|
+
phigs2 = 0
|
619
|
+
else
|
620
|
+
phigs2 = Math.acos(x[j]/rgs2)
|
621
|
+
end
|
622
|
+
coordinates[0,i,j,k] = rgs2 * gs2f + coordinates[0,i,j,k] * (1.0-gs2f)
|
623
|
+
coordinates[1,i,j,k] = theta[k] * gs2f + coordinates[1,i,j,k] * (1.0-gs2f)
|
624
|
+
coordinates[2,i,j,k] = phigs2 * gs2f + coordinates[2,i,j,k] * (1.0-gs2f)
|
625
|
+
end
|
626
|
+
|
627
|
+
|
628
|
+
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
#exit
|
633
|
+
case tp = options[:toroidal_projection]
|
634
|
+
when Numeric
|
635
|
+
coordinates[2, false] = tp
|
636
|
+
end
|
637
|
+
cache[[:cylindrical_coordinates_gsl_tensor, ops]] = coordinates
|
638
|
+
#save # save the run to save the hard_cache
|
639
|
+
return coordinates
|
640
|
+
end
|
641
|
+
|
642
|
+
# Return a rank 4 tensor which give
|
643
|
+
# cartesian coordinates X,Y,Z as a function
|
644
|
+
# of gs2 coordinates y, x, theta.
|
645
|
+
#
|
646
|
+
# a = cartesian_coordinates_gsl_tensor(options)
|
647
|
+
#
|
648
|
+
# # pseudocode
|
649
|
+
# X(y[i], x[j], theta[k]) = a[0,i,j,k]
|
650
|
+
# Y(y[i], x[j], theta[k]) = a[1,i,j,k]
|
651
|
+
# Z(y[i], x[j], theta[k]) = a[2,i,j,k]
|
652
|
+
|
653
|
+
|
654
|
+
def cartesian_coordinates_gsl_tensor(options)
|
655
|
+
cyl = cylindrical_coordinates_gsl_tensor(options)
|
656
|
+
shape = cyl.shape
|
657
|
+
cart = GSL::Tensor.alloc(*shape)
|
658
|
+
for i in 0...shape[1]
|
659
|
+
for j in 0...shape[2]
|
660
|
+
for k in 0...shape[3]
|
661
|
+
r = cyl[0,i,j,k]
|
662
|
+
z = cyl[1,i,j,k]
|
663
|
+
phi = cyl[2,i,j,k]
|
664
|
+
#cart[0,i,j,k] = r # Y
|
665
|
+
cart[0,i,j,k] = r*Math.cos(phi) # X
|
666
|
+
#cart[1,i,j,k] = phi # X
|
667
|
+
cart[1,i,j,k] = r*Math.sin(phi) # Y
|
668
|
+
cart[2,i,j,k] = z
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
cart
|
673
|
+
end
|
674
|
+
|
675
|
+
|
676
|
+
|
677
|
+
|
678
|
+
|
679
|
+
|
680
|
+
|
681
|
+
|
682
|
+
|
683
|
+
end #module
|
684
|
+
include GSLTensors
|
685
|
+
module GSLComplexTensors
|
686
|
+
def phi_gsl_tensor_complex(options)
|
687
|
+
return field_gsl_tensor_complex(options.absorb({field_name: :phi}))
|
688
|
+
end
|
689
|
+
def field_gsl_tensor_complex(options)
|
690
|
+
field = field_gsl_tensor(options)
|
691
|
+
fieldc = GSL::TensorComplex.alloc(*field.shape.slice(0..2))
|
692
|
+
nac = fieldc.narray
|
693
|
+
na = field.narray
|
694
|
+
for i in 0...field.shape[0]
|
695
|
+
for j in 0...field.shape[1]
|
696
|
+
for k in 0...field.shape[2]
|
697
|
+
nac[k,j,i] = Complex(na[0,k,j,i],na[1,k,j,i])
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|
701
|
+
return fieldc
|
702
|
+
end
|
703
|
+
end #module
|
704
|
+
include GSLComplexTensors
|
705
|
+
end #class
|