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.
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