gs2crmod 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|