gs2crmod 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.document +5 -0
  2. data/Gemfile +13 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.md +4 -0
  5. data/README.rdoc +19 -0
  6. data/Rakefile +56 -0
  7. data/VERSION +1 -0
  8. data/ext/extconf.rb +9 -0
  9. data/ext/gs2crmod_ext.c +366 -0
  10. data/gs2crmod.gemspec +98 -0
  11. data/include/gs2crmod_ext.h +58 -0
  12. data/lib/gs2crmod/astrogk/astrogk.rb +201 -0
  13. data/lib/gs2crmod/astrogk/calculations.rb +57 -0
  14. data/lib/gs2crmod/astrogk/check_convergence.rb +7 -0
  15. data/lib/gs2crmod/astrogk/deleted_variables.rb +76 -0
  16. data/lib/gs2crmod/astrogk/graphs.rb +13 -0
  17. data/lib/gs2crmod/astrogk/gsl_data.rb +13 -0
  18. data/lib/gs2crmod/astrogk/gsl_tools.rb +182 -0
  19. data/lib/gs2crmod/astrogk/ingen.rb +18 -0
  20. data/lib/gs2crmod/astrogk/input_file_tools.rb +7 -0
  21. data/lib/gs2crmod/astrogk/namelist_tools.rb +14 -0
  22. data/lib/gs2crmod/astrogk/namelists.rb +2800 -0
  23. data/lib/gs2crmod/astrogk/properties.rb +17 -0
  24. data/lib/gs2crmod/astrogk/species_dependent_namelists.rb +228 -0
  25. data/lib/gs2crmod/astrogk/test_gs2.rb +231 -0
  26. data/lib/gs2crmod/astrogk.rb +200 -0
  27. data/lib/gs2crmod/calculations.rb +780 -0
  28. data/lib/gs2crmod/check_convergence.rb +179 -0
  29. data/lib/gs2crmod/deleted_variables.rb +916 -0
  30. data/lib/gs2crmod/graphs.rb +1899 -0
  31. data/lib/gs2crmod/graphs_rdoc.rb +556 -0
  32. data/lib/gs2crmod/gs2.rb +1143 -0
  33. data/lib/gs2crmod/gsl_data.rb +1181 -0
  34. data/lib/gs2crmod/gsl_data_3d.rb +705 -0
  35. data/lib/gs2crmod/gsl_tools.rb +187 -0
  36. data/lib/gs2crmod/ingen.rb +218 -0
  37. data/lib/gs2crmod/namelists.rb +5142 -0
  38. data/lib/gs2crmod/properties.rb +22 -0
  39. data/lib/gs2crmod/species_dependent_namelists.rb +228 -0
  40. data/lib/gs2crmod/test_gs2.rb +231 -0
  41. data/lib/gs2crmod.rb +2 -0
  42. data/lib/gs2crmod_extension.rb +1 -0
  43. data/test/helper.rb +18 -0
  44. data/test/test_gs2crmod.rb +7 -0
  45. metadata +176 -0
@@ -0,0 +1,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