ASCOT5
Loading...
Searching...
No Matches
B_STS.c
Go to the documentation of this file.
1
28#include <stdlib.h>
29#include <stdio.h>
30#include <math.h>
31#include <string.h>
32#include "../math.h"
33#include "../ascot5.h"
34#include "../error.h"
35#include "../print.h"
36#include "../consts.h"
37#include "B_STS.h"
38#include "../linint/linint.h"
39#include "../spline/interp.h"
40
98int B_STS_init_offload(B_STS_offload_data* offload_data, real** offload_array) {
99
100 /* Spline initialization. */
101 int err = 0;
102 int psi_size = offload_data->psigrid_n_r * offload_data->psigrid_n_z
103 * offload_data->psigrid_n_phi;
104 int B_size = offload_data->Bgrid_n_r * offload_data->Bgrid_n_z
105 * offload_data->Bgrid_n_phi;
106 int axis_size = offload_data->n_axis;
107
108 /* Allocate enough space to store four 3D arrays and axis data */
109 real* coeff_array = (real*) malloc( (3*NSIZE_COMP3D*B_size
110 + NSIZE_COMP3D*psi_size
111 + 2*axis_size)*sizeof(real));
112 real* B_r = &(coeff_array[0*B_size*NSIZE_COMP3D]);
113 real* B_phi = &(coeff_array[1*B_size*NSIZE_COMP3D]);
114 real* B_z = &(coeff_array[2*B_size*NSIZE_COMP3D]);
115 real* psi = &(coeff_array[3*B_size*NSIZE_COMP3D]);
116 real* axis_r = &(coeff_array[(3*B_size + psi_size)*NSIZE_COMP3D]);
117 real* axis_z = &(coeff_array[(3*B_size + psi_size)*NSIZE_COMP3D
118 + axis_size]);
119
121 psi, *offload_array + 3*B_size,
122 offload_data->psigrid_n_r, offload_data->psigrid_n_phi,
123 offload_data->psigrid_n_z,
125 offload_data->psigrid_r_min, offload_data->psigrid_r_max,
126 offload_data->psigrid_phi_min, offload_data->psigrid_phi_max,
127 offload_data->psigrid_z_min, offload_data->psigrid_z_max);
128
130 B_r, *offload_array + 0*B_size,
131 offload_data->Bgrid_n_r, offload_data->Bgrid_n_phi,
132 offload_data->Bgrid_n_z,
134 offload_data->Bgrid_r_min, offload_data->Bgrid_r_max,
135 offload_data->Bgrid_phi_min, offload_data->Bgrid_phi_max,
136 offload_data->Bgrid_z_min, offload_data->Bgrid_z_max);
137
139 B_phi, *offload_array + 1*B_size,
140 offload_data->Bgrid_n_r, offload_data->Bgrid_n_phi,
141 offload_data->Bgrid_n_z,
143 offload_data->Bgrid_r_min, offload_data->Bgrid_r_max,
144 offload_data->Bgrid_phi_min, offload_data->Bgrid_phi_max,
145 offload_data->Bgrid_z_min, offload_data->Bgrid_z_max);
146
148 B_z, *offload_array + 2*B_size,
149 offload_data->Bgrid_n_r, offload_data->Bgrid_n_phi,
150 offload_data->Bgrid_n_z,
152 offload_data->Bgrid_r_min, offload_data->Bgrid_r_max,
153 offload_data->Bgrid_phi_min, offload_data->Bgrid_phi_max,
154 offload_data->Bgrid_z_min, offload_data->Bgrid_z_max);
155
156 if(err) {
157 print_err("Error: Failed to initialize splines.\n");
158 return err;
159 }
160
161 for(int i = 0; i < axis_size; i++) {
162 axis_r[i] = (*offload_array)[3*B_size + psi_size + i];
163 axis_z[i] = (*offload_array)[3*B_size + psi_size + axis_size + i];
164 }
165
166 /* Re-allocate the offload array and store spline coefficients there */
167 free(*offload_array);
168 *offload_array = coeff_array;
169 offload_data->offload_array_length = 3*NSIZE_COMP3D*B_size
170 + NSIZE_COMP3D*psi_size
171 + 2*axis_size;
172
173 /* Evaluate psi and magnetic field on axis for checks */
174 B_STS_data Bdata;
175 B_STS_init(&Bdata, offload_data, *offload_array);
176 real psival[1], Bval[3], axis[2];
177 err += B_STS_get_axis_rz(axis, &Bdata, 0);
178 err += B_STS_eval_psi(psival, axis[0], 0, axis[1],
179 &Bdata);
180 err += B_STS_eval_B(Bval, axis[0], 0, axis[1],
181 &Bdata);
182 if(err) {
183 print_err("Error: Initialization failed.\n");
184 return err;
185 }
186
187 printf("\nStellarator magnetic field (B_STS)\n");
188 print_out(VERBOSE_IO, "Psi-grid: nR = %4.d Rmin = %3.3f m Rmax = %3.3f m\n",
189 offload_data->psigrid_n_r,
190 offload_data->psigrid_r_min, offload_data->psigrid_r_max);
191 print_out(VERBOSE_IO, " nz = %4.d zmin = %3.3f m zmax = %3.3f m\n",
192 offload_data->psigrid_n_z,
193 offload_data->psigrid_z_min, offload_data->psigrid_z_max);
194 print_out(VERBOSE_IO, "nphi = %4.d phimin = %3.3f deg phimax = %3.3f deg\n",
195 offload_data->psigrid_n_phi,
196 math_rad2deg(offload_data->psigrid_phi_min),
197 math_rad2deg(offload_data->psigrid_phi_max));
198 print_out(VERBOSE_IO, "B-grid: nR = %4.d Rmin = %3.3f m Rmax = %3.3f m\n",
199 offload_data->Bgrid_n_r,
200 offload_data->Bgrid_r_min, offload_data->Bgrid_r_max);
201 print_out(VERBOSE_IO, " nz = %4.d zmin = %3.3f m zmax = %3.3f m\n",
202 offload_data->Bgrid_n_z,
203 offload_data->Bgrid_z_min, offload_data->Bgrid_z_max);
204 print_out(VERBOSE_IO, "nphi = %4.d phimin = %3.3f deg phimax = %3.3f deg\n",
205 offload_data->Bgrid_n_phi,
206 math_rad2deg(offload_data->Bgrid_phi_min),
207 math_rad2deg(offload_data->Bgrid_phi_max));
208 print_out(VERBOSE_IO, "Psi at magnetic axis (phi=0) (%1.3f m, %1.3f m)\n",
209 axis[0], axis[1]);
210 print_out(VERBOSE_IO, "%3.3f (evaluated)\n%3.3f (given)\n",
211 psival[0], offload_data->psi0);
212 print_out(VERBOSE_IO, "Magnetic field on axis:\n"
213 "B_R = %3.3f B_phi = %3.3f B_z = %3.3f\n",
214 Bval[0], Bval[1], Bval[2]);
215
216 return 0;
217}
218
225void B_STS_free_offload(B_STS_offload_data* offload_data, real** offload_array) {
226 free(*offload_array);
227 *offload_array = NULL;
228}
229
237void B_STS_init(B_STS_data* Bdata, B_STS_offload_data* offload_data,
238 real* offload_array) {
239
240 int B_size = offload_data->Bgrid_n_r * offload_data->Bgrid_n_z
241 * offload_data->Bgrid_n_phi*NSIZE_COMP3D;
242 int psi_size = offload_data->psigrid_n_r * offload_data->psigrid_n_z
243 * offload_data->psigrid_n_phi*NSIZE_COMP3D;
244 int axis_size = offload_data->n_axis;
245
246 /* Initialize target data struct */
247 Bdata->psi0 = offload_data->psi0;
248 Bdata->psi1 = offload_data->psi1;
249
250
251 /* Initialize spline structs from the coefficients */
252 interp3Dcomp_init_spline(&Bdata->B_r, &(offload_array[0*B_size]),
253 offload_data->Bgrid_n_r,
254 offload_data->Bgrid_n_phi,
255 offload_data->Bgrid_n_z,
257 offload_data->Bgrid_r_min,
258 offload_data->Bgrid_r_max,
259 offload_data->Bgrid_phi_min,
260 offload_data->Bgrid_phi_max,
261 offload_data->Bgrid_z_min,
262 offload_data->Bgrid_z_max);
263
264 interp3Dcomp_init_spline(&Bdata->B_phi, &(offload_array[1*B_size]),
265 offload_data->Bgrid_n_r,
266 offload_data->Bgrid_n_phi,
267 offload_data->Bgrid_n_z,
269 offload_data->Bgrid_r_min,
270 offload_data->Bgrid_r_max,
271 offload_data->Bgrid_phi_min,
272 offload_data->Bgrid_phi_max,
273 offload_data->Bgrid_z_min,
274 offload_data->Bgrid_z_max);
275
276 interp3Dcomp_init_spline(&Bdata->B_z, &(offload_array[2*B_size]),
277 offload_data->Bgrid_n_r,
278 offload_data->Bgrid_n_phi,
279 offload_data->Bgrid_n_z,
281 offload_data->Bgrid_r_min,
282 offload_data->Bgrid_r_max,
283 offload_data->Bgrid_phi_min,
284 offload_data->Bgrid_phi_max,
285 offload_data->Bgrid_z_min,
286 offload_data->Bgrid_z_max);
287
288 interp3Dcomp_init_spline(&Bdata->psi, &(offload_array[3*B_size]),
289 offload_data->psigrid_n_r,
290 offload_data->psigrid_n_phi,
291 offload_data->psigrid_n_z,
293 offload_data->psigrid_r_min,
294 offload_data->psigrid_r_max,
295 offload_data->psigrid_phi_min,
296 offload_data->psigrid_phi_max,
297 offload_data->psigrid_z_min,
298 offload_data->psigrid_z_max);
299
300 linint1D_init(&Bdata->axis_r,
301 &(offload_array[3*B_size + psi_size]),
302 offload_data->n_axis, PERIODICBC,
303 offload_data->axis_min, offload_data->axis_max);
304
305 linint1D_init(&Bdata->axis_z,
306 &(offload_array[3*B_size + psi_size + axis_size]),
307 offload_data->n_axis, PERIODICBC,
308 offload_data->axis_min, offload_data->axis_max);
309}
310
323 B_STS_data* Bdata) {
324 a5err err = 0;
325 int interperr = 0; /* If error happened during interpolation */
326
327 interperr += interp3Dcomp_eval_f(&psi[0], &Bdata->psi, r, phi, z);
328
329#ifdef B_STS_CLAMP_RHO_NONNEGATIVE
330 if ( psi[0] < Bdata->psi0 ){
331 psi[0] = Bdata->psi0;
332 }
333#endif
334
335 /* Test for psi interpolation error */
336 if(interperr) {
337 return error_raise( ERR_INPUT_EVALUATION, __LINE__, EF_B_STS );
338 }
339
340 return err;
341}
342
355 B_STS_data* Bdata) {
356 a5err err = 0;
357 int interperr = 0; /* If error happened during interpolation */
358 real psi_dpsi_temp[10];
359
360 interperr += interp3Dcomp_eval_df(psi_dpsi_temp, &Bdata->psi, r, phi, z);
361
362
363 psi_dpsi[0] = psi_dpsi_temp[0];
364 psi_dpsi[1] = psi_dpsi_temp[1];
365 psi_dpsi[2] = psi_dpsi_temp[2];
366 psi_dpsi[3] = psi_dpsi_temp[3];
367
368#ifdef B_STS_CLAMP_RHO_NONNEGATIVE
369 if ( psi_dpsi_temp[0] < Bdata->psi0 ){
370 psi_dpsi[0] = Bdata->psi0;
371 psi_dpsi[1] = 0.0;
372 psi_dpsi[2] = 0.0;
373 psi_dpsi[3] = 0.0;
374 }
375#endif
376
377
378 if(interperr) {
379 return error_raise( ERR_INPUT_EVALUATION, __LINE__, EF_B_STS );
380 }
381
382 return err;
383}
384
397 B_STS_data* Bdata) {
398 a5err err = 0;
399 real psi_dpsi[4];
400
401 err = B_STS_eval_psi_dpsi(psi_dpsi, r, phi, z, Bdata);
402 if(err){
403 return error_raise( ERR_INPUT_UNPHYSICAL, __LINE__, EF_B_STS );
404 }
405
406 /* Check that the values seem valid */
407 real delta = Bdata->psi1 - Bdata->psi0;
408 if( (psi_dpsi[0] - Bdata->psi0) / delta <= 0 ) {
409#ifdef B_STS_CLAMP_RHO_NONNEGATIVE
410 /* Set rho and the partial derivatives to zero, because otherwise one
411 would need to divide by rho, which is zero. Of course, this problem
412 persists when B_STS_CLAMP_RHO_NONNEGATIVE is not defined and
413 the evaluation happens exactly at rho=0.0 */
414 rho_drho[0] = 0.0;
415 rho_drho[1] = 0.0;
416 rho_drho[2] = 0.0;
417 rho_drho[3] = 0.0;
418 return err;
419#else
420 return error_raise( ERR_INPUT_UNPHYSICAL, __LINE__, EF_B_STS );
421#endif
422 }
423
424 /* Normalize psi to get rho */
425 rho_drho[0] = sqrt( (psi_dpsi[0] - Bdata->psi0) / delta );
426
427 rho_drho[1] = psi_dpsi[1] / (2*delta*rho_drho[0]);
428 rho_drho[2] = psi_dpsi[2] / (2*delta*rho_drho[0]);
429 rho_drho[3] = psi_dpsi[3] / (2*delta*rho_drho[0]);
430
431 return err;
432}
433
445a5err B_STS_eval_B(real B[3], real r, real phi, real z, B_STS_data* Bdata) {
446 a5err err = 0;
447 int interperr = 0; /* If error happened during interpolation */
448
449 interperr += interp3Dcomp_eval_f(&B[0], &Bdata->B_r, r, phi, z);
450 interperr += interp3Dcomp_eval_f(&B[1], &Bdata->B_phi, r, phi, z);
451 interperr += interp3Dcomp_eval_f(&B[2], &Bdata->B_z, r, phi, z);
452
453 /* Test for B field interpolation error */
454 if(interperr) {
455 return error_raise( ERR_INPUT_EVALUATION, __LINE__, EF_B_STS );
456 }
457
458 /* Check that magnetic field seems valid */
459 int check = 0;
460 check += ((B[0]*B[0] + B[1]*B[1] + B[2]*B[2]) == 0);
461 if(!err && check) {
462 return error_raise( ERR_INPUT_UNPHYSICAL, __LINE__, EF_B_STS );
463 }
464
465 return err;
466
467}
468
481 B_STS_data* Bdata) {
482 a5err err = 0;
483 int interperr = 0; /* If error happened during interpolation */
484 real B_dB_temp[10];
485
486 interperr += interp3Dcomp_eval_df(B_dB_temp, &Bdata->B_r, r, phi, z);
487
488 B_dB[0] = B_dB_temp[0];
489 B_dB[1] = B_dB_temp[1];
490 B_dB[2] = B_dB_temp[2];
491 B_dB[3] = B_dB_temp[3];
492
493 interperr += interp3Dcomp_eval_df(B_dB_temp, &Bdata->B_phi, r, phi, z);
494
495 B_dB[4] = B_dB_temp[0];
496 B_dB[5] = B_dB_temp[1];
497 B_dB[6] = B_dB_temp[2];
498 B_dB[7] = B_dB_temp[3];
499
500 interperr += interp3Dcomp_eval_df(B_dB_temp, &Bdata->B_z, r, phi, z);
501
502 B_dB[8] = B_dB_temp[0];
503 B_dB[9] = B_dB_temp[1];
504 B_dB[10] = B_dB_temp[2];
505 B_dB[11] = B_dB_temp[3];
506
507 /* Test for B field interpolation error */
508 if(interperr) {
509 return error_raise( ERR_INPUT_EVALUATION, __LINE__, EF_B_STS );
510 }
511
512 /* Check that magnetic field seems valid */
513 int check = 0;
514 check += ((B_dB[0]*B_dB[0] + B_dB[4]*B_dB[4] + B_dB[8]*B_dB[8]) == 0);
515 if(!err && check) {
516 return error_raise( ERR_INPUT_UNPHYSICAL, __LINE__, EF_B_STS );
517 }
518
519 return 0;
520}
521
532 a5err err = 0;
533
534 int interperr = 0; /* If error happened during interpolation */
535 interperr += linint1D_eval_f(&rz[0], &Bdata->axis_r, phi);
536 interperr += linint1D_eval_f(&rz[1], &Bdata->axis_z, phi);
537 if(interperr) {
538 err = error_raise( ERR_INPUT_EVALUATION, __LINE__, EF_B_STS );
539 }
540 return err;
541}
a5err B_STS_eval_rho_drho(real rho_drho[4], real r, real phi, real z, B_STS_data *Bdata)
Evaluate normalized poloidal flux rho and its derivatives.
Definition B_STS.c:396
void B_STS_free_offload(B_STS_offload_data *offload_data, real **offload_array)
Free offload array.
Definition B_STS.c:225
void B_STS_init(B_STS_data *Bdata, B_STS_offload_data *offload_data, real *offload_array)
Initialize magnetic field data struct on target.
Definition B_STS.c:237
a5err B_STS_eval_B_dB(real B_dB[12], real r, real phi, real z, B_STS_data *Bdata)
Evaluate magnetic field and its derivatives.
Definition B_STS.c:480
int B_STS_init_offload(B_STS_offload_data *offload_data, real **offload_array)
Initialize magnetic field offload data.
Definition B_STS.c:98
a5err B_STS_eval_psi(real *psi, real r, real phi, real z, B_STS_data *Bdata)
Evaluate poloidal flux psi.
Definition B_STS.c:322
a5err B_STS_eval_psi_dpsi(real psi_dpsi[4], real r, real phi, real z, B_STS_data *Bdata)
Evaluate poloidal flux psi and its derivatives.
Definition B_STS.c:354
a5err B_STS_get_axis_rz(real rz[2], B_STS_data *Bdata, real phi)
Return magnetic axis Rz-coordinates.
Definition B_STS.c:531
a5err B_STS_eval_B(real B[3], real r, real phi, real z, B_STS_data *Bdata)
Evaluate magnetic field.
Definition B_STS.c:445
Header file for B_STS.c.
Main header file for ASCOT5.
double real
Definition ascot5.h:85
Header file containing physical and mathematical constants.
Error module for ASCOT5.
unsigned long int a5err
Simulation error flag.
Definition error.h:17
@ EF_B_STS
Definition error.h:38
@ ERR_INPUT_EVALUATION
Definition error.h:63
@ ERR_INPUT_UNPHYSICAL
Definition error.h:65
static DECLARE_TARGET_SIMD a5err error_raise(error_type type, int line, error_file file)
Raise a new error.
Definition error.h:86
Spline interpolation library.
DECLARE_TARGET_END a5err interp3Dcomp_eval_f(real *f, interp3D_data *str, real x, real y, real z)
Evaluate interpolated value of 3D scalar field.
int interp3Dcomp_init_coeff(real *c, real *f, int n_x, int n_y, int n_z, int bc_x, int bc_y, int bc_z, real x_min, real x_max, real y_min, real y_max, real z_min, real z_max)
Calculate tricubic spline interpolation coefficients for 3D data.
@ NATURALBC
Definition interp.h:37
@ PERIODICBC
Definition interp.h:38
void interp3Dcomp_init_spline(interp3D_data *str, real *c, int n_x, int n_y, int n_z, int bc_x, int bc_y, int bc_z, real x_min, real x_max, real y_min, real y_max, real z_min, real z_max)
Initialize a tricubic spline.
DECLARE_TARGET_END a5err interp3Dcomp_eval_df(real *f_df, interp3D_data *str, real x, real y, real z)
Evaluate interpolated value of 3D field and 1st and 2nd derivatives.
Linear interpolation library.
int linint1D_eval_f(real *f, linint1D_data *str, real x)
Evaluate interpolated value of 1D scalar field.
Definition linint1D.c:47
void linint1D_init(linint1D_data *str, real *c, int n_x, int bc_x, real x_min, real x_max)
Initialize linear interpolation struct for scalar 1D data.
Definition linint1D.c:22
Header file for math.c.
#define math_rad2deg(a)
Convert radians to degrees.
Definition math.h:110
Macros for printing console output.
#define print_out(v,...)
Print to standard output.
Definition print.h:31
@ VERBOSE_IO
Definition print.h:20
#define print_err(...)
Print to standard error.
Definition print.h:42
stellarator magnetic field parameters on the target
Definition B_STS.h:49
stellarator magnetic field parameters on the host
Definition B_STS.h:15
real psigrid_r_max
Definition B_STS.h:20
int offload_array_length
Definition B_STS.h:38
real Bgrid_phi_max
Definition B_STS.h:34
real Bgrid_phi_min
Definition B_STS.h:33
real psigrid_phi_min
Definition B_STS.h:23
real psigrid_z_min
Definition B_STS.h:21
real psigrid_r_min
Definition B_STS.h:19
real psigrid_phi_max
Definition B_STS.h:24
real psigrid_z_max
Definition B_STS.h:22