gs2crmod 0.11.78 → 0.11.79

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gs2crmod/gs2.rb CHANGED
@@ -1181,246 +1181,10 @@ end
1181
1181
  end
1182
1182
  end
1183
1183
 
1184
- #This function will handle running the correlation analysis and writing the results to a NetCDF file.
1185
- #Cases need to be handled differently since perp, par and full are just subsets of the full correlation function
1186
- #but the time correlation calculation needs to deal with each radial location separately. Time correlation
1187
- #uses the zonal flows in the toroidal direction to calculate the correlation time.
1188
- #
1189
- #This function takes in the same options as field_real_space_standard_representation, along with the following
1190
- #new options dealing with interpolation and binning:
1191
- #
1192
- # correlation_type: determines which subset of correlation function should be calculated (perp/par/full/time)
1193
- # nbins_array: array giving number of bins to use in the binning procedure. Index order (x, y, z ,t)
1194
- # nt_reg: Most of the time you have many more time points than you need for spatial correlations. This sets
1195
- # number of new interpolation points in time.
1196
- #
1197
- # Using this function: Since this can only be single threaded, this can be a very expensive calculation when
1198
- # trying to do the full correlation function, so this is not recommended for highly resolved nonlinear runs. This is
1199
- # why the perp/par/full splitting is implemented, allowing one dimension to be taken out essentially.
1200
- def correlation_analysis(options={})
1201
-
1202
- #Sanity checks:
1203
- #Cannot only have one bin since require difference between bins for index calculation
1204
- if options[:nbins_array].include?1
1205
- raise('Cannot have only one bin in nbins_array. Minuimum is two.')
1206
- end
1207
- #Thetamin shouldn't be equal to thetamax to avoid possibili
1208
- #
1209
-
1210
- case options[:correlation_type]
1211
- when 'perp', 'par', 'full'
1212
- gsl_tensor = field_correlation_gsl_tensor(options)
1213
- shape = gsl_tensor.shape
1214
-
1215
- #Set up dimensions
1216
- file = NumRu::NetCDF.create(@run_name + "_correlation_analysis_#{options[:correlation_type]}.nc")
1217
- ydim = file.def_dim('x',shape[0])
1218
- xdim = file.def_dim('y',shape[1])
1219
- zdim = file.def_dim('z',shape[2])
1220
- tdim = file.def_dim('t',shape[3])
1221
- correlation_var = file.def_var("correlation", 'sfloat', [xdim, ydim, zdim, tdim])
1222
- file.enddef
1223
- #Write out array
1224
- correlation_var.put(NArray.to_na(gsl_tensor.to_a))
1225
- file.close
1226
- when 'time'
1227
- nakx_actual = NumRu::NetCDF.open(@run_name + ".out.nc").var('kx').get
1228
- kx_len = nakx_actual.length
1229
- if options[:nakx] == nil
1230
- radial_pts = kx_len
1231
- elsif options[:nakx] <= kx_len
1232
- radial_pts = options[:nakx]
1233
- else
1234
- raise('nakx exceeds the total number of kx\'s in simulation')
1235
- end
1236
-
1237
- #Check whether t_index_window is specified, if not, set to entire t range
1238
- if options[:t_index_window] == nil
1239
- options[:t_index_window] = [1, -1]
1240
- end
1241
-
1242
-
1243
- #Now loop through the radial locations and calculate the correlation function in y and t.
1244
- for x in 0...radial_pts
1245
- options[:xmin] = x
1246
- options[:xmax] = x
1247
- gsl_tensor = field_correlation_gsl_tensor(options)
1248
- shape = gsl_tensor.shape
1249
-
1250
- if x == 0 #Write dimensions to NetCDF file
1251
- file = NumRu::NetCDF.create(@run_name + "_correlation_analysis_#{options[:correlation_type]}.nc")
1252
- ydim = file.def_dim('x',shape[0])
1253
- xdim = file.def_dim('y',shape[1])
1254
- zdim = file.def_dim('z',shape[2])
1255
- tdim = file.def_dim('t',shape[3])
1256
- end
1257
- file.redef
1258
- correlation_var = file.def_var("correlation_x_#{x}", 'sfloat', [xdim, ydim, zdim, tdim])
1259
- file.enddef
1260
- #Write out array
1261
- correlation_var.put(NArray.to_na(gsl_tensor.to_a))
1262
- end
1263
- file.close #only close after loop over radial points
1264
- else
1265
- raise 'Please specify correlation_type as perp/par/time/full'
1266
- end
1267
- end
1268
-
1269
1184
  def input_file_extension
1270
1185
  '.in'
1271
1186
  end
1272
1187
 
1273
- #This function will interpolate and output either phi or density at the outboard midplane
1274
- #on a 40x40 grid appropriate to analyse as experimental data. It called as a run_command
1275
- #e.g. rc 'bes_output(options)', j:<run number>. It will call field_real_space_poloidal_plane_graphkit
1276
- #for every time step, interpolate at outboard midplane, and write fields and grids out to NetCDF file.
1277
- #
1278
- #Options: Same as field_real_space_poloidal_plane, field name must also be specified for generality. New options:
1279
- #
1280
- # no_flux_tube_copies: ensures only one flux tube is printed out with zeroes everywhere else.
1281
- # amin: Minor radius (to which R,Z are normalized) so that grid is in right units
1282
- # output_box_size: Array of sizes of output box (in units of amin) either side of middle of fluxtube at outboard midplane
1283
- # in R direction and either side of outboard midplane in Z direction.
1284
- # output_box_points: Array of number of points in output box (R,Z). Default will be 50x50.
1285
- #
1286
- #The interpolation routine used will only interpolate correctly inside the fluxtube and produce garbage outside. Regular points are checked
1287
- #for being inside or outside the fluxtube and values of the field outside the fluxtube are set to zero.
1288
- def bes_output(options={})
1289
- #******************
1290
- # Read in options *
1291
- #******************
1292
- #In order to interpolate on constant grids, ensure constant_torphi is set to some value (default 0.0)
1293
- if options[:constant_torphi] == nil
1294
- p 'constant_torphi not set! Setting it to 0.0.'
1295
- options[:constant_torphi] = 0.0
1296
- end
1297
- #Check whether t_index_window is specified, if not, set to entire t range
1298
- if options[:t_index_window] == nil
1299
- t_index_beg = 1
1300
- t_index_end = gsl_vector(:t).length
1301
- else
1302
- t_index_beg = options[:t_index_window][0]
1303
- t_index_end = options[:t_index_window][1]
1304
- end
1305
- if options[:amin]
1306
- amin = options[:amin]
1307
- end
1308
- if options[:v_ref] # velocity of reference species
1309
- v_ref = options[:v_ref]
1310
- end
1311
- if options[:omega] # angular velocity of plasma
1312
- omega = options[:omega]
1313
- end
1314
- if options[:omega] and (options[:v_ref] == nil or options[:amin] == nil)
1315
- raise 'Need to specify amin AND v_ref options when specifying omega to move to LAB frame!'
1316
- end
1317
- if options[:output_box_size] and options[:output_box_size].kind_of?Array
1318
- _r_box_size = options[:output_box_size][0] # EGH These variables are marked as unused... are they used anywhere?
1319
- _z_box_size = options[:output_box_size][1]
1320
- #else
1321
- # raise 'Option output_box_size must be specified (in units of amin) and must be an Array.'
1322
- end
1323
- if options[:output_box_points] and options[:output_box_points].kind_of?Array
1324
- r_box_pts = options[:output_box_points][0]
1325
- z_box_pts = options[:output_box_points][1]
1326
- else
1327
- r_box_pts = 50
1328
- z_box_pts = 50
1329
- end
1330
-
1331
- #Call at first time step to set up arrays and grids
1332
- options[:t_index] = t_index_beg
1333
- kit = field_real_space_poloidal_plane_graphkit(options)
1334
- x = kit.data[0].x.data
1335
- _y = kit.data[0].y.data
1336
- z = kit.data[0].z.data
1337
-
1338
- #Set up NetCDf file
1339
- file = NumRu::NetCDF.create(@run_name + "_bes_output.nc")
1340
- xdim = file.def_dim('y', x.shape[0])
1341
- zdim = file.def_dim('z', z.shape[1])
1342
- tdim = file.def_dim('t', 0) #zero means unlimited
1343
- x_var = file.def_var("x", 'sfloat', [xdim, zdim])
1344
- z_var = file.def_var("z", 'sfloat', [xdim, zdim])
1345
- t_var = file.def_var("t", 'sfloat', [tdim])
1346
- field_var = file.def_var("field", 'sfloat', [xdim, zdim, tdim])
1347
- file.enddef
1348
- #Write dimensions to file
1349
- x_var.put(NArray.to_na(x.to_a))
1350
- z_var.put(NArray.to_na(z.to_a))
1351
-
1352
- #Loop over time, load field as function of space at each time index, write to file
1353
- for i in t_index_beg...t_index_end #inclusive of end
1354
- Terminal.erewind(1) #go back one line in terminal
1355
- eputs sprintf("Writing time index = %d of %d#{Terminal::CLEAR_LINE}", i, t_index_end-t_index_beg+1) #clear line and print time index
1356
- options[:t_index] = i
1357
- #Need to test whether omega is specified to change torphi at each time step. If not, do nothing since torphi must be
1358
- #set to a value to call the graphkit below
1359
- if options[:omega]
1360
- options[:torphi] = omega * (gsl_vector(:t)[i] - gsl_vector(:t)[0]) * (amin/v_ref)
1361
- end
1362
- kit = field_real_space_poloidal_plane_graphkit(options)
1363
- t_var.put(gsl_vector(:t)[i], 'index'=>[i-t_index_beg]) #Write time to unlimited time NetCDF variable
1364
- field_var.put(NArray.to_na((kit.data[0].f.data).to_a), 'start'=>[0,0,i-t_index_beg], 'end'=>[-1,-1,i-t_index_beg])
1365
- end
1366
- file.close
1367
-
1368
- #Ignore this until interpolation issue is sorted
1369
- =begin
1370
- #**************************
1371
- # Set up new regular grid *
1372
- #**************************
1373
- th_grid_size = x.shape[1]
1374
- flux_tube_midpt = x[0, (th_grid_size-1)/2] + (x[-1, (th_grid_size-1)/2] - x[1, (th_grid_size-1)/2])/2
1375
- x_vec_reg = GSL::Vector.linspace(flux_tube_midpt - r_box_size, flux_tube_midpt + r_box_size, r_box_pts)
1376
- z_vec_reg = GSL::Vector.linspace(-z_box_size, z_box_size, z_box_pts)
1377
- x_reg = GSL::Matrix.alloc(r_box_pts, z_box_pts)
1378
- z_reg = GSL::Matrix.alloc(r_box_pts, z_box_pts)
1379
- field_reg = GSL::Matrix.alloc(r_box_pts, z_box_pts)
1380
- for i in 0...r_box_pts
1381
- for j in 0...z_box_pts
1382
- x_reg[i,j] = x_vec_reg[i]
1383
- z_reg[i,j] = z_vec_reg[j]
1384
- end
1385
- end
1386
-
1387
- #************************************************
1388
- # Find the field at every point on regular grid *
1389
- #************************************************
1390
- #To evaluate field on a regular grid given the field on an irregular grid, need to interpolate. The rubygem
1391
- #gsl_extras contains an interpolation routine called ScatterInterp which does exactly this based on a
1392
- #'Radial Basis Function' method.
1393
-
1394
- #Have R, Z, and field on an irregular grid in the form of matrices. ScatterInterp only takes in GSL vectors
1395
- #so simply convert these matrices to vectors (of size row*col) since the order of the pts don't matter.
1396
- x_vec = GSL::Vector.alloc(x.shape[0]*x.shape[1])
1397
- z_vec = GSL::Vector.alloc(x.shape[0]*x.shape[1])
1398
- field_vec = GSL::Vector.alloc(x.shape[0]*x.shape[1])
1399
- for i in 0...x.shape[0]
1400
- for j in 0...x.shape[1]
1401
- x_vec[x.shape[1]*i + j] = x[i,j]
1402
- z_vec[x.shape[1]*i + j] = z[i,j]
1403
- field_vec[x.shape[1]*i + j] = field[i,j]
1404
- end
1405
- end
1406
-
1407
- #Now pass these vectors to ScatterInterp. This creates an object with instance method 'eval' which can be given an x,z coord
1408
- #at which to evaluate the interpolated function.
1409
- p 'Interpolating'
1410
- interp = GSL::ScatterInterp.alloc(:linear, [x_vec, z_vec, field_vec], false, r0=0.1)
1411
- p 'Finished interpolating'
1412
- for i in 0...x_vec_reg.size
1413
- for j in 0...z_vec_reg.size
1414
- field_reg[i,j] = interp.eval(x_vec_reg[i], z_vec_reg[j])
1415
- end
1416
- end
1417
-
1418
- kit = GraphKit.quick_create([x_vec_reg, z_vec_reg, field_reg])
1419
- #kit2 = GraphKit.quick_create([x_vec, z_vec, field_vec])
1420
- =end
1421
-
1422
- end
1423
-
1424
1188
  #This section defines a selection of graphs which are written to a latex file when the CR function write_report is called. To add your own, simply copy one a similar looking graph and modify it to your needs.
1425
1189
  # The requirements to use the latex report writing is further specified in CodeRunner.
1426
1190
  def latex_graphs