ASCOT5
Loading...
Searching...
No Matches
interp2Dcomp.c
Go to the documentation of this file.
1
5#include <stdlib.h>
6#include <math.h>
7#include "../ascot5.h"
8#include "../math.h"
9#include "interp.h"
10#include "spline.h"
11
34 int n_x, int n_y, int bc_x, int bc_y,
35 real x_min, real x_max,
36 real y_min, real y_max) {
37
38 /* Check boundary conditions and calculate grid intervals. Grid intervals
39 needed because we use normalized grid intervals. For periodic boundary
40 condition, grid maximum value and the last data point are not the same.
41 Take this into account in grid intervals. */
42 real x_grid, y_grid;
43 if(bc_x == PERIODICBC || bc_x == NATURALBC) {
44 x_grid = (x_max - x_min) / ( n_x - 1 * (bc_x == NATURALBC) );
45 }
46 else {
47 return 1;
48 }
49
50 if(bc_y == PERIODICBC || bc_y == NATURALBC) {
51 y_grid = (y_max - y_min) / ( n_y - 1 * (bc_y == NATURALBC) );
52 }
53 else {
54 return 1;
55 }
56
57 /* Allocate helper quantities */
58 real* f_x = malloc(n_x*sizeof(real));
59 real* f_y = malloc(n_y*sizeof(real));
60 real* c_x = malloc(n_x*NSIZE_COMP1D*sizeof(real));
61 real* c_y = malloc(n_y*NSIZE_COMP1D*sizeof(real));
62
63 if(f_x == NULL || f_y == NULL || c_x == NULL || c_y == NULL) {
64 return 1;
65 }
66
67 /* Calculate bicubic spline surface coefficients, i.e second derivatives.
68 For each grid cell (i_x, i_y), there are four coefficients:
69 [f, fxx, fyy, fxxyy]. Note how we account for normalized grid. */
70
71 /* Cubic spline along x for each y, using f values to get fxx */
72 for(int i_y=0; i_y<n_y; i_y++) {
73 /* fxx */
74 for(int i_x=0; i_x<n_x; i_x++) {
75 f_x[i_x] = f[i_y*n_x+i_x];
76 }
77 splinecomp(f_x, n_x, bc_x, c_x);
78 for(int i_x=0; i_x<n_x; i_x++) {
79 c[i_y*n_x*4 + i_x*4 ] = c_x[i_x*2];
80 c[i_y*n_x*4 + i_x*4 + 1] = c_x[i_x*2+1] / (x_grid*x_grid);
81 }
82 }
83
84 /* Two cubic splines along y for each x, using f and fxx to get fyy and
85 fxxyy */
86 for(int i_x=0; i_x<n_x; i_x++) {
87
88 /* fyy */
89 for(int i_y=0; i_y<n_y; i_y++) {
90 f_y[i_y] = f[i_y*n_x + i_x];
91 }
92 splinecomp(f_y, n_y, bc_y, c_y);
93 for(int i_y=0; i_y<n_y; i_y++) {
94 c[i_y*n_x*4+i_x*4+2] = c_y[i_y*2+1]/(y_grid*y_grid);
95 }
96
97 /* fxxyy */
98 for(int i_y=0; i_y<n_y; i_y++) {
99 f_y[i_y] = c[i_y*n_x*4 + i_x*4 + 1];
100 }
101 splinecomp(f_y, n_y, bc_y, c_y);
102 for(int i_y=0; i_y<n_y; i_y++) {
103 c[i_y*n_x*4 + i_x*4 + 3] = c_y[i_y*2 + 1] / (y_grid*y_grid);
104 }
105 }
106
107 /* Free allocated memory */
108 free(f_x);
109 free(f_y);
110 free(c_x);
111 free(c_y);
112
113 return 0;
114}
115
131 int n_x, int n_y, int bc_x, int bc_y,
132 real x_min, real x_max,
133 real y_min, real y_max) {
134
135 /* Calculate grid intervals. For periodic boundary condition, grid maximum
136 value and the last data point are not the same. Take this into account
137 in grid intervals. */
138 real x_grid = (x_max - x_min) / ( n_x - 1 * (bc_x == NATURALBC) );
139 real y_grid = (y_max - y_min) / ( n_y - 1 * (bc_y == NATURALBC) );
140
141 /* Initialize the interp2D_data struct */
142 str->n_x = n_x;
143 str->n_y = n_y;
144 str->bc_x = bc_x;
145 str->bc_y = bc_y;
146 str->x_min = x_min;
147 str->x_max = x_max;
148 str->x_grid = x_grid;
149 str->y_min = y_min;
150 str->y_max = y_max;
151 str->y_grid = y_grid;
152 str->c = c;
153}
154
175 int n_x, int n_y, int bc_x, int bc_y,
176 real x_min, real x_max, real y_min, real y_max) {
177 real* c = (real*) malloc(n_y*n_x*NSIZE_COMP2D*sizeof(real));
178 int err = interp2Dcomp_init_coeff(c, f, n_x, n_y, bc_x, bc_y, x_min, x_max,
179 y_min, y_max);
180 if(err) {
181 return err;
182 }
183 interp2Dcomp_init_spline(str, c, n_x, n_y, bc_x, bc_y, x_min, x_max,
184 y_min, y_max);
185 return 0;
186}
187
202
203 /* Make sure periodic coordinates are within [min, max] region. */
204 if(str->bc_x == PERIODICBC) {
205 x = fmod(x - str->x_min, str->x_max - str->x_min) + str->x_min;
206 x = x + (x < str->x_min) * (str->x_max - str->x_min);
207 }
208 if(str->bc_y == PERIODICBC) {
209 y = fmod(y - str->y_min, str->y_max - str->y_min) + str->y_min;
210 y = y + (y < str->y_min) * (str->y_max - str->y_min);
211 }
212
213 /* Index for x variable. The -1 needed at exactly grid end. */
214 int i_x = (x - str->x_min) / str->x_grid - 1*(x==str->x_max);
215 /* Normalized x coordinate in current cell */
216 real dx = ( x - (str->x_min + i_x*str->x_grid) ) / str->x_grid;
217 /* Helper variables */
218 real dx3 = dx * (dx*dx - 1.0);
219 real dxi = 1.0 - dx;
220 real dxi3 = dxi * (dxi*dxi - 1.0);
221 real xg2 = str->x_grid*str->x_grid;
222
223 /* Index for y variable. The -1 needed at exactly grid end. */
224 int i_y = (y - str->y_min) / str->y_grid - 1*(y==str->y_max);
225 /* Normalized y coordinate in current cell */
226 real dy = ( y - (str->y_min + i_y*str->y_grid) ) / str->y_grid;
227 /* Helper variables */
228 real dy3 = dy * (dy*dy - 1.0);
229 real dyi = 1.0 - dy;
230 real dyi3 = dyi * (dyi*dyi - 1.0);
231 real yg2 = str->y_grid*str->y_grid;
232
233 int n = i_y*str->n_x*4+i_x*4; /* Index jump to cell */
234 int x1 = 4; /* Index jump one x forward */
235 int y1 = str->n_x*4; /* Index jump one y forward */
236
237 int err = 0;
238
239 /* Enforce periodic BC or check that the coordinate is within the domain. */
240 if( str->bc_x == PERIODICBC && i_x == str->n_x-1 ) {
241 x1 = -(str->n_x-1)*x1;
242 }
243 else if( str->bc_x == NATURALBC && !(x >= str->x_min && x <= str->x_max) ) {
244 err = 1;
245 }
246 if( str->bc_y == PERIODICBC && i_y == str->n_y-1 ) {
247 y1 = -(str->n_y-1)*y1;
248 }
249 else if( str->bc_y == NATURALBC && !(y >= str->y_min && y <= str->y_max) ) {
250 err = 1;
251 }
252
253 if(!err) {
254 *f = (
255 dxi*(dyi*str->c[n]+dy*str->c[n+y1])
256 +dx*(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
257 +(xg2/6)*(
258 dxi3*(dyi*str->c[n+1] + dy*str->c[n+y1+1])
259 +dx3*(dyi*str->c[n+x1+1] + dy*str->c[n+y1+x1+1]))
260 +(yg2/6)*(
261 dxi*(dyi3*str->c[n+2]+dy3*str->c[n+y1+2])
262 +dx*(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
263 +(xg2*yg2/36)*(
264 dxi3*(dyi3*str->c[n+3]+dy3*str->c[n+y1+3])
265 +dx3*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
266 }
267
268 return err;
269}
270
294
295 /* Make sure periodic coordinates are within [min, max] region. */
296 if(str->bc_x == PERIODICBC) {
297 x = fmod(x - str->x_min, str->x_max - str->x_min) + str->x_min;
298 x = x + (x < str->x_min) * (str->x_max - str->x_min);
299 }
300 if(str->bc_y == PERIODICBC) {
301 y = fmod(y - str->y_min, str->y_max - str->y_min) + str->y_min;
302 y = y + (y < str->y_min) * (str->y_max - str->y_min);
303 }
304
305 /* Index for x variable. The -1 needed at exactly grid end. */
306 int i_x = (x - str->x_min) / str->x_grid - 1*(x==str->x_max);
307 /* Normalized x coordinate in current cell */
308 real dx = ( x - (str->x_min + i_x*str->x_grid) ) / str->x_grid;
309 /* Helper variables */
310 real dx3 = dx * (dx*dx - 1.0);
311 real dx3dx = 3*dx*dx - 1;
312 real dxi = 1.0 - dx;
313 real dxi3 = dxi * (dxi*dxi - 1.0);
314 real dxi3dx = -3*dxi*dxi + 1;
315 real xg = str->x_grid;
316 real xg2 = xg*xg;
317 real xgi = 1.0/xg;
318
319 /* Index for y variable. The -1 needed at exactly grid end. */
320 int i_y = (y - str->y_min) / str->y_grid - 1*(y==str->y_max);
321 /* Normalized y coordinate in current cell */
322 real dy = ( y - (str->y_min + i_y*str->y_grid) ) / str->y_grid;
323 /* Helper variables */
324 real dy3 = dy * (dy*dy - 1.0);
325 real dy3dy = 3*dy*dy - 1;
326 real dyi = 1.0 - dy;
327 real dyi3 = dyi * (dyi*dyi - 1.0);
328 real dyi3dy = -3*dyi*dyi + 1;
329 real yg = str->y_grid;
330 real yg2 = yg*yg;
331 real ygi = 1.0/yg;
332
333 int n = i_y*str->n_x*4+i_x*4;
334 int x1 = 4;
335 int y1 = str->n_x*4;
337 int err = 0;
338
339 /* Enforce periodic BC or check that the coordinate is within the domain. */
340 if( str->bc_x == PERIODICBC && i_x == str->n_x-1 ) {
341 x1 = -(str->n_x-1)*x1;
342 }
343 else if( str->bc_x == NATURALBC && !(x >= str->x_min && x <= str->x_max) ) {
344 err = 1;
345 }
346 if( str->bc_y == PERIODICBC && i_y == str->n_y-1 ) {
347 y1 = -(str->n_y-1)*y1;
348 }
349 else if( str->bc_y == NATURALBC && !(y >= str->y_min && y <= str->y_max) ) {
350 err = 1;
351 }
352
353 if(!err) {
354 /* f */
355 f_df[0] = (
356 dxi*(dyi*str->c[n]+dy*str->c[n+y1])
357 +dx*(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
358 +(xg2/6)*(
359 dxi3*(dyi*str->c[n+1] + dy*str->c[n+y1+1])
360 +dx3*(dyi*str->c[n+x1+1] + dy*str->c[n+y1+x1+1]))
361 +(yg2/6)*(
362 dxi*(dyi3*str->c[n+2]+dy3*str->c[n+y1+2])
363 +dx*(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
364 +(xg2*yg2/36)*(
365 dxi3*(dyi3*str->c[n+3]+dy3*str->c[n+y1+3])
366 +dx3*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
367
368 /* df/dx */
369 f_df[1] = xgi*(
370 -(dyi*str->c[n] +dy*str->c[n+y1])
371 +(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
372 +(xg/6)*(
373 dxi3dx*(dyi*str->c[n+1] +dy*str->c[n+y1+1])
374 +dx3dx*(dyi*str->c[n+x1+1]+dy*str->c[n+y1+x1+1]))
375 +(xgi*yg2/6)*(
376 -(dyi3*str->c[n+2] +dy3*str->c[n+y1+2])
377 +(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
378 +(xg*yg2/36)*(
379 dxi3dx*(dyi3*str->c[n+3] +dy3*str->c[n+y1+3])
380 +dx3dx*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
381
382 /* df/dy */
383 f_df[2] = ygi*(
384 dxi*(-str->c[n] +str->c[n+y1])
385 +dx*(-str->c[n+x1]+str->c[n+y1+x1]))
386 +(xg2*ygi/6)*(
387 dxi3*(-str->c[n+1] +str->c[n+y1+1])
388 +dx3*(-str->c[n+x1+1]+str->c[n+y1+x1+1]))
389 +(yg/6)*(
390 dxi*(dyi3dy*str->c[n+2] +dy3dy*str->c[n+y1+2])
391 +dx*(dyi3dy*str->c[n+x1+2]+dy3dy*str->c[n+y1+x1+2]))
392 +(xg2*yg/36)*(
393 dxi3*(dyi3dy*str->c[n+3] +dy3dy*str->c[n+y1+3])
394 +dx3*(dyi3dy*str->c[n+x1+3]+dy3dy*str->c[n+y1+x1+3]));
395
396 /* d2f/dx2 */
397 f_df[3] = (
398 dxi*(dyi*str->c[n+1] +dy*str->c[n+y1+1])
399 +dx*(dyi*str->c[n+x1+1]+dy*str->c[n+y1+x1+1]))
400 +(yg2/6)*(
401 dxi*(dyi3*str->c[n+3] +dy3*str->c[n+y1+3])
402 +dx*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
403
404 /* d2f/dy2 */
405 f_df[4] = (
406 dxi*(dyi*str->c[n+2] +dy*str->c[n+y1+2])
407 +dx*(dyi*str->c[n+x1+2]+dy*str->c[n+y1+x1+2]))
408 +xg2/6*(
409 dxi3*(dyi*str->c[n+3] +dy*str->c[n+y1+3])
410 +dx3*(dyi*str->c[n+x1+3]+dy*str->c[n+y1+x1+3]));
411
412 /* d2f/dydx */
413 f_df[5] = xgi*ygi*(
414 str->c[n] -str->c[n+y1]
415 -str->c[n+x1]+str->c[n+y1+x1])
416 +(xg/6*ygi)*(
417 dxi3dx*(-str->c[n+1] +str->c[n+y1+1])
418 +dx3dx*(-str->c[n+x1+1]+str->c[n+y1+x1+1]))
419 +(xgi/6*yg)*(
420 -(dyi3dy*str->c[n+2] +dy3dy*str->c[n+y1+2])
421 +(dyi3dy*str->c[n+x1+2]+dy3dy*str->c[n+y1+x1+2]))
422 +(xg*yg/36)*(
423 dxi3dx*(dyi3dy*str->c[n+3] +dy3dy*str->c[n+y1+3])
424 +dx3dx*(dyi3dy*str->c[n+x1+3]+dy3dy*str->c[n+y1+x1+3]));
425 }
426
427 return err;
428}
Main header file for ASCOT5.
double real
Definition ascot5.h:85
unsigned long int a5err
Simulation error flag.
Definition error.h:17
int interp2Dcomp_setup(interp2D_data *str, real *f, int n_x, int n_y, int bc_x, int bc_y, real x_min, real x_max, real y_min, real y_max)
Set up splines to interpolate 2D scalar data.
int interp2Dcomp_init_coeff(real *c, real *f, int n_x, int n_y, int bc_x, int bc_y, real x_min, real x_max, real y_min, real y_max)
Calculate bicubic spline interpolation coefficients for scalar 2D data.
void interp2Dcomp_init_spline(interp2D_data *str, real *c, int n_x, int n_y, int bc_x, int bc_y, real x_min, real x_max, real y_min, real y_max)
Initialize a bicubic spline.
a5err interp2Dcomp_eval_f(real *f, interp2D_data *str, real x, real y)
Evaluate interpolated value of a 2D field.
a5err interp2Dcomp_eval_df(real *f_df, interp2D_data *str, real x, real y)
Evaluate interpolated value and 1st and 2nd derivatives of 2D field.
Spline interpolation library.
@ NATURALBC
Definition interp.h:37
@ PERIODICBC
Definition interp.h:38
real fmod(real x, real y)
Compute the modulus of two real numbers.
Definition math.c:22
Header file for math.c.
Header file for splineexpl.c and splinecomp.c.
void splinecomp(real *f, int n, int bc, real *c)
Calculate compact cubic spline interpolation coefficients in 1D.
Definition splinecomp.c:22
Bicubic interpolation struct.
Definition interp.h:68
real y_min
Definition interp.h:76
real y_grid
Definition interp.h:78
real x_grid
Definition interp.h:75
real x_min
Definition interp.h:73
real y_max
Definition interp.h:77
real x_max
Definition interp.h:74
real * c
Definition interp.h:79