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
169
170 /* Make sure periodic coordinates are within [min, max] region. */
171 if(str->bc_x == PERIODICBC) {
172 x = fmod(x - str->x_min, str->x_max - str->x_min) + str->x_min;
173 x = x + (x < str->x_min) * (str->x_max - str->x_min);
174 }
175 if(str->bc_y == PERIODICBC) {
176 y = fmod(y - str->y_min, str->y_max - str->y_min) + str->y_min;
177 y = y + (y < str->y_min) * (str->y_max - str->y_min);
178 }
179
180 /* Index for x variable. The -1 needed at exactly grid end. */
181 int i_x = (x - str->x_min) / str->x_grid - 1*(x==str->x_max);
182 /* Normalized x coordinate in current cell */
183 real dx = ( x - (str->x_min + i_x*str->x_grid) ) / str->x_grid;
184 /* Helper variables */
185 real dx3 = dx * (dx*dx - 1.0);
186 real dxi = 1.0 - dx;
187 real dxi3 = dxi * (dxi*dxi - 1.0);
188 real xg2 = str->x_grid*str->x_grid;
189
190 /* Index for y variable. The -1 needed at exactly grid end. */
191 int i_y = (y - str->y_min) / str->y_grid - 1*(y==str->y_max);
192 /* Normalized y coordinate in current cell */
193 real dy = ( y - (str->y_min + i_y*str->y_grid) ) / str->y_grid;
194 /* Helper variables */
195 real dy3 = dy * (dy*dy - 1.0);
196 real dyi = 1.0 - dy;
197 real dyi3 = dyi * (dyi*dyi - 1.0);
198 real yg2 = str->y_grid*str->y_grid;
199
200 int n = i_y*str->n_x*4+i_x*4; /* Index jump to cell */
201 int x1 = 4; /* Index jump one x forward */
202 int y1 = str->n_x*4; /* Index jump one y forward */
203
204 int err = 0;
205
206 /* Enforce periodic BC or check that the coordinate is within the domain. */
207 if( str->bc_x == PERIODICBC && i_x == str->n_x-1 ) {
208 x1 = -(str->n_x-1)*x1;
209 }
210 else if( str->bc_x == NATURALBC && !(x >= str->x_min && x <= str->x_max) ) {
211 err = 1;
212 }
213 if( str->bc_y == PERIODICBC && i_y == str->n_y-1 ) {
214 y1 = -(str->n_y-1)*y1;
215 }
216 else if( str->bc_y == NATURALBC && !(y >= str->y_min && y <= str->y_max) ) {
217 err = 1;
218 }
219
220 if(!err) {
221 *f = (
222 dxi*(dyi*str->c[n]+dy*str->c[n+y1])
223 +dx*(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
224 +(xg2/6)*(
225 dxi3*(dyi*str->c[n+1] + dy*str->c[n+y1+1])
226 +dx3*(dyi*str->c[n+x1+1] + dy*str->c[n+y1+x1+1]))
227 +(yg2/6)*(
228 dxi*(dyi3*str->c[n+2]+dy3*str->c[n+y1+2])
229 +dx*(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
230 +(xg2*yg2/36)*(
231 dxi3*(dyi3*str->c[n+3]+dy3*str->c[n+y1+3])
232 +dx3*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
233 }
234
235 return err;
236}
237
261
262 /* Make sure periodic coordinates are within [min, max] region. */
263 if(str->bc_x == PERIODICBC) {
264 x = fmod(x - str->x_min, str->x_max - str->x_min) + str->x_min;
265 x = x + (x < str->x_min) * (str->x_max - str->x_min);
266 }
267 if(str->bc_y == PERIODICBC) {
268 y = fmod(y - str->y_min, str->y_max - str->y_min) + str->y_min;
269 y = y + (y < str->y_min) * (str->y_max - str->y_min);
270 }
271
272 /* Index for x variable. The -1 needed at exactly grid end. */
273 int i_x = (x - str->x_min) / str->x_grid - 1*(x==str->x_max);
274 /* Normalized x coordinate in current cell */
275 real dx = ( x - (str->x_min + i_x*str->x_grid) ) / str->x_grid;
276 /* Helper variables */
277 real dx3 = dx * (dx*dx - 1.0);
278 real dx3dx = 3*dx*dx - 1;
279 real dxi = 1.0 - dx;
280 real dxi3 = dxi * (dxi*dxi - 1.0);
281 real dxi3dx = -3*dxi*dxi + 1;
282 real xg = str->x_grid;
283 real xg2 = xg*xg;
284 real xgi = 1.0/xg;
285
286 /* Index for y variable. The -1 needed at exactly grid end. */
287 int i_y = (y - str->y_min) / str->y_grid - 1*(y==str->y_max);
288 /* Normalized y coordinate in current cell */
289 real dy = ( y - (str->y_min + i_y*str->y_grid) ) / str->y_grid;
290 /* Helper variables */
291 real dy3 = dy * (dy*dy - 1.0);
292 real dy3dy = 3*dy*dy - 1;
293 real dyi = 1.0 - dy;
294 real dyi3 = dyi * (dyi*dyi - 1.0);
295 real dyi3dy = -3*dyi*dyi + 1;
296 real yg = str->y_grid;
297 real yg2 = yg*yg;
298 real ygi = 1.0/yg;
299
300 int n = i_y*str->n_x*4+i_x*4;
301 int x1 = 4;
302 int y1 = str->n_x*4;
304 int err = 0;
305
306 /* Enforce periodic BC or check that the coordinate is within the domain. */
307 if( str->bc_x == PERIODICBC && i_x == str->n_x-1 ) {
308 x1 = -(str->n_x-1)*x1;
309 }
310 else if( str->bc_x == NATURALBC && !(x >= str->x_min && x <= str->x_max) ) {
311 err = 1;
312 }
313 if( str->bc_y == PERIODICBC && i_y == str->n_y-1 ) {
314 y1 = -(str->n_y-1)*y1;
315 }
316 else if( str->bc_y == NATURALBC && !(y >= str->y_min && y <= str->y_max) ) {
317 err = 1;
318 }
319
320 if(!err) {
321 /* f */
322 f_df[0] = (
323 dxi*(dyi*str->c[n]+dy*str->c[n+y1])
324 +dx*(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
325 +(xg2/6)*(
326 dxi3*(dyi*str->c[n+1] + dy*str->c[n+y1+1])
327 +dx3*(dyi*str->c[n+x1+1] + dy*str->c[n+y1+x1+1]))
328 +(yg2/6)*(
329 dxi*(dyi3*str->c[n+2]+dy3*str->c[n+y1+2])
330 +dx*(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
331 +(xg2*yg2/36)*(
332 dxi3*(dyi3*str->c[n+3]+dy3*str->c[n+y1+3])
333 +dx3*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
334
335 /* df/dx */
336 f_df[1] = xgi*(
337 -(dyi*str->c[n] +dy*str->c[n+y1])
338 +(dyi*str->c[n+x1]+dy*str->c[n+y1+x1]))
339 +(xg/6)*(
340 dxi3dx*(dyi*str->c[n+1] +dy*str->c[n+y1+1])
341 +dx3dx*(dyi*str->c[n+x1+1]+dy*str->c[n+y1+x1+1]))
342 +(xgi*yg2/6)*(
343 -(dyi3*str->c[n+2] +dy3*str->c[n+y1+2])
344 +(dyi3*str->c[n+x1+2]+dy3*str->c[n+y1+x1+2]))
345 +(xg*yg2/36)*(
346 dxi3dx*(dyi3*str->c[n+3] +dy3*str->c[n+y1+3])
347 +dx3dx*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
348
349 /* df/dy */
350 f_df[2] = ygi*(
351 dxi*(-str->c[n] +str->c[n+y1])
352 +dx*(-str->c[n+x1]+str->c[n+y1+x1]))
353 +(xg2*ygi/6)*(
354 dxi3*(-str->c[n+1] +str->c[n+y1+1])
355 +dx3*(-str->c[n+x1+1]+str->c[n+y1+x1+1]))
356 +(yg/6)*(
357 dxi*(dyi3dy*str->c[n+2] +dy3dy*str->c[n+y1+2])
358 +dx*(dyi3dy*str->c[n+x1+2]+dy3dy*str->c[n+y1+x1+2]))
359 +(xg2*yg/36)*(
360 dxi3*(dyi3dy*str->c[n+3] +dy3dy*str->c[n+y1+3])
361 +dx3*(dyi3dy*str->c[n+x1+3]+dy3dy*str->c[n+y1+x1+3]));
362
363 /* d2f/dx2 */
364 f_df[3] = (
365 dxi*(dyi*str->c[n+1] +dy*str->c[n+y1+1])
366 +dx*(dyi*str->c[n+x1+1]+dy*str->c[n+y1+x1+1]))
367 +(yg2/6)*(
368 dxi*(dyi3*str->c[n+3] +dy3*str->c[n+y1+3])
369 +dx*(dyi3*str->c[n+x1+3]+dy3*str->c[n+y1+x1+3]));
370
371 /* d2f/dy2 */
372 f_df[4] = (
373 dxi*(dyi*str->c[n+2] +dy*str->c[n+y1+2])
374 +dx*(dyi*str->c[n+x1+2]+dy*str->c[n+y1+x1+2]))
375 +xg2/6*(
376 dxi3*(dyi*str->c[n+3] +dy*str->c[n+y1+3])
377 +dx3*(dyi*str->c[n+x1+3]+dy*str->c[n+y1+x1+3]));
378
379 /* d2f/dydx */
380 f_df[5] = xgi*ygi*(
381 str->c[n] -str->c[n+y1]
382 -str->c[n+x1]+str->c[n+y1+x1])
383 +(xg/6*ygi)*(
384 dxi3dx*(-str->c[n+1] +str->c[n+y1+1])
385 +dx3dx*(-str->c[n+x1+1]+str->c[n+y1+x1+1]))
386 +(xgi/6*yg)*(
387 -(dyi3dy*str->c[n+2] +dy3dy*str->c[n+y1+2])
388 +(dyi3dy*str->c[n+x1+2]+dy3dy*str->c[n+y1+x1+2]))
389 +(xg*yg/36)*(
390 dxi3dx*(dyi3dy*str->c[n+3] +dy3dy*str->c[n+y1+3])
391 +dx3dx*(dyi3dy*str->c[n+x1+3]+dy3dy*str->c[n+y1+x1+3]));
392 }
393
394 return err;
395}
Main header file for ASCOT5.
double real
Definition ascot5.h:85
unsigned long int a5err
Simulation error flag.
Definition error.h:17
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