ASCOT5
Loading...
Searching...
No Matches
diag_transcoef.c
Go to the documentation of this file.
1
5#include <math.h>
6#include <stdlib.h>
7#include <stdio.h>
8#include <string.h>
9#include "../ascot5.h"
10#include "../math.h"
11#include "../consts.h"
12#include "../simulate.h"
13#include "../particle.h"
14#include "diag_transcoef.h"
15
16DECLARE_TARGET_SIMD
18DECLARE_TARGET_SIMD_UNIFORM(data)
20 integer id, real rho, real r, real pitchsign,
21 real t_f, real t_i, real theta_f, real theta_i);
23 integer index, integer id);
24
31 data->id = (int*) malloc( data->Nmrk * sizeof(int) );
32 data->Kcoef = (real*) malloc( data->Nmrk * sizeof(real) );
33 data->Dcoef = (real*) malloc( data->Nmrk * sizeof(real) );
34
35 data->datapoints = malloc( data->Nmrk*sizeof(diag_transcoef_link*) );
36 for(int i = 0; i < data->Nmrk; i++) {
37 data->id[i] = -1;
38 data->datapoints[i] = NULL;
39 }
40}
41
48 free(data->datapoints);
49 free(data->id);
50 free(data->Kcoef);
51 free(data->Dcoef);
52}
53
65
66 GPU_PARALLEL_LOOP_ALL_LEVELS
67 for(int i=0; i < p_f->n_mrk; i++) {
68 real p[3] = {p_f->p_r[i], p_f->p_phi[i], p_f->p_z[i]};
69 real B[3] = {p_f->B_r[i], p_f->B_phi[i], p_f->B_z[i]};
70 real pitchsign = 1 - 2*(math_dot(p, B) < 0);
72 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
73 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
74 }
75
76 /* If marker simulation was ended, process and clean the data */
77 GPU_PARALLEL_LOOP_ALL_LEVELS
78 for(int i=0; i < p_f->n_mrk; i++) {
79 /* Mask dummy markers and those which are running */
80 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
81 continue;
82 }
83 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
84 }
85}
86
98 GPU_PARALLEL_LOOP_ALL_LEVELS
99 for(int i=0; i < p_f->n_mrk; i++) {
100 real pitchsign = 1 - 2*(p_f->ppar[i] < 0);
102 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
103 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
104 }
105
106
107 /* If marker simulation was ended, process and clean the data */
108 GPU_PARALLEL_LOOP_ALL_LEVELS
109 for(int i=0; i < p_f->n_mrk; i++) {
110
111 /* Mask dummy markers and those which are running */
112 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
113 continue;
114 }
115
116 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
117 }
118}
119
131 #pragma omp simd
132 for(int i=0; i < NSIMD; i++) {
133 real pitchsign = 1 - 2*(p_f->pitch[i] < 0);
135 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
136 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
137 }
138
139
140 /* If marker simulation was ended, process and clean the data */
141 for(int i=0; i < NSIMD; i++) {
142 /* Mask dummy markers and those which are running */
143 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
144 continue;
145 }
146
147 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
148 }
149}
150
151
168 integer id, real rho, real r, real pitchsign,
169 real t_f, real t_i, real theta_f, real theta_i) {
170 /* Mask dummy markers */
171 if( id > 0 ) {
172
173 /* Check whether marker position should be recorded: *
174 * - Time step was accepted t_f > t_i
175 * - Enough time has passed since last record t_f - ti > interval OR
176 no data exists yet.
177 * - Marker has crossed OMP during the current time step.
178 */
179 real record = 0.0;
180 if( t_f > t_i ) {
181 if( data->datapoints[index] == NULL ) {
182 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
183 }
184 else if( t_f - data->datapoints[index]->time > data->interval ) {
185 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
186 }
187 }
188
189 /* Record */
190 if( record > 0) {
191 diag_transcoef_link* newlink =
192 malloc(sizeof(diag_transcoef_link));
193 newlink->time = t_f;
194 newlink->pitchsign = pitchsign;
195
196 if(data->recordrho) {
197 newlink->rho = rho;
198 }
199 else {
200 newlink->rho = r;
201 }
202
203 /* Store the link or make a new chain if the marker is new */
204 if( data->datapoints[index] == NULL ) {
205 newlink->prevlink = NULL;
206 data->datapoints[index] = newlink;
207 }
208 else {
209 newlink->prevlink = data->datapoints[index];
210 data->datapoints[index] = newlink;
211 }
212 }
213 }
214}
215
216
227 integer index, integer id) {
228
229 /* Count number of positive and negative crossings */
230 int positive = 0, negative = 0;
231 diag_transcoef_link* link = data->datapoints[index];
232 while(link != NULL) {
233 if(link->pitchsign < 0) {
234 negative++;
235 }
236 else {
237 positive++;
238 }
239 link = link->prevlink;
240 }
241
242 /* Which ever there are more are stored */
243 int datasize, sign;
244 if(positive >= negative) {
245 datasize = positive;
246 sign = 1;
247 }
248 else {
249 datasize = negative;
250 sign = -1;
251 }
252
253 /* If there are enough datapoints, process them to K and D */
254 if(datasize > data->Navg) {
255 /* How many points we have after averaging data */
256 int navgpnt = ceil(datasize/data->Navg);
257 real* rho = malloc(navgpnt*sizeof(real));
258 real* time = malloc(navgpnt*sizeof(real));
259
260 /* The datasize is not necessarily multiple of navg. We take the
261 "extra" points from last points and average them separately */
262 link = data->datapoints[index];
263 while(link->pitchsign * sign < 0) {
264 link = link->prevlink;
265 }
266 rho[navgpnt-1] = link->rho;
267 time[navgpnt-1] = link->time;
268
269 int nextrapnts = datasize - navgpnt*data->Navg;
270 if(nextrapnts == 0) {
271 nextrapnts = data->Navg;
272 }
273 for(int k = 1; k < nextrapnts; k++) {
274 link = link->prevlink;
275 while(link->pitchsign * sign < 0) {
276 link = link->prevlink;
277 }
278 rho[navgpnt-1] += link->rho;
279 time[navgpnt-1] += link->time;
280 }
281 rho[navgpnt-1] /= nextrapnts;
282 time[navgpnt-1] /= nextrapnts;
283
284 /* Take the full averages */
285 for(int j = navgpnt-2; j > -1; j--) {
286 rho[j] = 0;
287 time[j] = 0;
288 for(int k = 0; k < data->Navg; k++) {
289 link = link->prevlink;
290 while(link->pitchsign * sign < 0) {
291 link = link->prevlink;
292 }
293 rho[j] += link->rho;
294 time[j] += link->time;
295 }
296 rho[j] /= data->Navg;
297 time[j] /= data->Navg;
298 }
299
300 /* Evaluate coefficients */
301 real K = 0;
302 for(int j = 0; j < navgpnt-1; j++) {
303 K += ( rho[j+1] - rho[j] ) / ( time[j+1] - time[j] );
304 }
305 K = K / navgpnt;
306
307 real D = 0;
308 for(int j = 0; j < navgpnt-1; j++) {
309 real a = rho[j+1] - rho[j] - K * ( time[j+1] - time[j] );
310 D += 0.5*a*a / ( time[j+1] - time[j] );
311 }
312 D = D / navgpnt;
313
314 /* Store and free resources */
315 free(rho);
316 free(time);
317 data->id[index] = (real)id;
318 data->Kcoef[index] = K;
319 data->Dcoef[index] = D;
320 }
321
322 /* Clear temporary storage */
324 link = data->datapoints[index];
325 while(link != NULL) {
326 temp = link->prevlink;
327 free(link);
328 link = temp;
329 }
330 data->datapoints[index] = NULL;
331
332}
333
334
344
345 real k = 0.0;
346 if( floor( fang/CONST_2PI ) != floor( iang/CONST_2PI ) ) {
347
348 real a = fmod(iang, CONST_2PI);
349 if(a < 0){
350 a = CONST_2PI + a;
351 }
352
353 a = fabs(a);
354 if(a > CONST_PI) {
355 a = CONST_2PI - a;
356 }
357 k = fabs(a / (fang - iang));
358 }
359
360 return k;
361}
Main header file for ASCOT5.
double real
Definition ascot5.h:85
#define NSIMD
Number of particles simulated simultaneously in a particle group operations.
Definition ascot5.h:91
long integer
Definition ascot5.h:84
Header file containing physical and mathematical constants.
#define CONST_PI
pi
Definition consts.h:11
#define CONST_2PI
2*pi
Definition consts.h:14
void diag_transcoef_update_ml(diag_transcoef_data *data, particle_simd_ml *p_f, particle_simd_ml *p_i)
Collect transport diagnostics for ml simulation.
void diag_transcoef_init(diag_transcoef_data *data)
Initializes transport coefficient diagnostics data.
DECLARE_TARGET_SIMD real diag_transcoef_check_omp_crossing(real fang, real iang)
Check if marker has crossed omp.
void diag_transcoef_process_and_clean(diag_transcoef_data *data, integer index, integer id)
Process recorded data to transport coefficients and clean.
void diag_transcoef_update_gc(diag_transcoef_data *data, particle_simd_gc *p_f, particle_simd_gc *p_i)
Collect transport diagnostics for gc simulation.
void diag_transcoef_update_fo(diag_transcoef_data *data, particle_simd_fo *p_f, particle_simd_fo *p_i)
Collect transport diagnostics for fo simulation.
void diag_transcoef_free(diag_transcoef_data *data)
Free allocated resources.
void diag_transcoef_record(diag_transcoef_data *data, integer index, integer id, real rho, real r, real pitchsign, real t_f, real t_i, real theta_f, real theta_i)
Check if criteria for recording is met for a single marker and make the record.
Header file for diag_transcoef.c.
real fmod(real x, real y)
Compute the modulus of two real numbers.
Definition math.c:22
Header file for math.c.
#define math_dot(a, b)
Calculate dot product a[3] dot b[3].
Definition math.h:32
Header file for particle.c.
Header file for simulate.c.
Transport coefficient diagnostics offload data struct.
diag_transcoef_link ** datapoints
Struct representing NSIMD particle markers.
Definition particle.h:210
integer * id
Definition particle.h:246
integer * index
Definition particle.h:255
integer * running
Definition particle.h:252
Struct representing NSIMD guiding center markers.
Definition particle.h:275
integer * running
Definition particle.h:320
integer * id
Definition particle.h:312
integer * index
Definition particle.h:323
Struct representing NSIMD field line markers.
Definition particle.h:343