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 #pragma omp simd
99 for(int i=0; i < NSIMD; 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 for(int i=0; i < NSIMD; i++) {
109
110 /* Mask dummy markers and those which are running */
111 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
112 continue;
113 }
114
115 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
116 }
117}
118
130 #pragma omp simd
131 for(int i=0; i < NSIMD; i++) {
132 real pitchsign = 1 - 2*(p_f->pitch[i] < 0);
134 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
135 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
136 }
137
138
139 /* If marker simulation was ended, process and clean the data */
140 for(int i=0; i < NSIMD; i++) {
141 /* Mask dummy markers and those which are running */
142 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
143 continue;
144 }
145
146 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
147 }
148}
149
150
167 integer id, real rho, real r, real pitchsign,
168 real t_f, real t_i, real theta_f, real theta_i) {
169 /* Mask dummy markers */
170 if( id > 0 ) {
171
172 /* Check whether marker position should be recorded: *
173 * - Time step was accepted t_f > t_i
174 * - Enough time has passed since last record t_f - ti > interval OR
175 no data exists yet.
176 * - Marker has crossed OMP during the current time step.
177 */
178 real record = 0.0;
179 if( t_f > t_i ) {
180 if( data->datapoints[index] == NULL ) {
181 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
182 }
183 else if( t_f - data->datapoints[index]->time > data->interval ) {
184 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
185 }
186 }
187
188 /* Record */
189 if( record > 0) {
190 diag_transcoef_link* newlink =
191 malloc(sizeof(diag_transcoef_link));
192 newlink->time = t_f;
193 newlink->pitchsign = pitchsign;
194
195 if(data->recordrho) {
196 newlink->rho = rho;
197 }
198 else {
199 newlink->rho = r;
200 }
201
202 /* Store the link or make a new chain if the marker is new */
203 if( data->datapoints[index] == NULL ) {
204 newlink->prevlink = NULL;
205 data->datapoints[index] = newlink;
206 }
207 else {
208 newlink->prevlink = data->datapoints[index];
209 data->datapoints[index] = newlink;
210 }
211 }
212 }
213}
214
215
226 integer index, integer id) {
227
228 /* Count number of positive and negative crossings */
229 int positive = 0, negative = 0;
230 diag_transcoef_link* link = data->datapoints[index];
231 while(link != NULL) {
232 if(link->pitchsign < 0) {
233 negative++;
234 }
235 else {
236 positive++;
237 }
238 link = link->prevlink;
239 }
240
241 /* Which ever there are more are stored */
242 int datasize, sign;
243 if(positive >= negative) {
244 datasize = positive;
245 sign = 1;
246 }
247 else {
248 datasize = negative;
249 sign = -1;
250 }
251
252 /* If there are enough datapoints, process them to K and D */
253 if(datasize > data->Navg) {
254 /* How many points we have after averaging data */
255 int navgpnt = ceil(datasize/data->Navg);
256 real* rho = malloc(navgpnt*sizeof(real));
257 real* time = malloc(navgpnt*sizeof(real));
258
259 /* The datasize is not necessarily multiple of navg. We take the
260 "extra" points from last points and average them separately */
261 link = data->datapoints[index];
262 while(link->pitchsign * sign < 0) {
263 link = link->prevlink;
264 }
265 rho[navgpnt-1] = link->rho;
266 time[navgpnt-1] = link->time;
267
268 int nextrapnts = datasize - navgpnt*data->Navg;
269 if(nextrapnts == 0) {
270 nextrapnts = data->Navg;
271 }
272 for(int k = 1; k < nextrapnts; k++) {
273 link = link->prevlink;
274 while(link->pitchsign * sign < 0) {
275 link = link->prevlink;
276 }
277 rho[navgpnt-1] += link->rho;
278 time[navgpnt-1] += link->time;
279 }
280 rho[navgpnt-1] /= nextrapnts;
281 time[navgpnt-1] /= nextrapnts;
282
283 /* Take the full averages */
284 for(int j = navgpnt-2; j > -1; j--) {
285 rho[j] = 0;
286 time[j] = 0;
287 for(int k = 0; k < data->Navg; k++) {
288 link = link->prevlink;
289 while(link->pitchsign * sign < 0) {
290 link = link->prevlink;
291 }
292 rho[j] += link->rho;
293 time[j] += link->time;
294 }
295 rho[j] /= data->Navg;
296 time[j] /= data->Navg;
297 }
298
299 /* Evaluate coefficients */
300 real K = 0;
301 for(int j = 0; j < navgpnt-1; j++) {
302 K += ( rho[j+1] - rho[j] ) / ( time[j+1] - time[j] );
303 }
304 K = K / navgpnt;
305
306 real D = 0;
307 for(int j = 0; j < navgpnt-1; j++) {
308 real a = rho[j+1] - rho[j] - K * ( time[j+1] - time[j] );
309 D += 0.5*a*a / ( time[j+1] - time[j] );
310 }
311 D = D / navgpnt;
312
313 /* Store and free resources */
314 free(rho);
315 free(time);
316 data->id[index] = (real)id;
317 data->Kcoef[index] = K;
318 data->Dcoef[index] = D;
319 }
320
321 /* Clear temporary storage */
323 link = data->datapoints[index];
324 while(link != NULL) {
325 temp = link->prevlink;
326 free(link);
327 link = temp;
328 }
329 data->datapoints[index] = NULL;
330
331}
332
333
343
344 real k = 0.0;
345 if( floor( fang/CONST_2PI ) != floor( iang/CONST_2PI ) ) {
346
347 real a = fmod(iang, CONST_2PI);
348 if(a < 0){
349 a = CONST_2PI + a;
350 }
351
352 a = fabs(a);
353 if(a > CONST_PI) {
354 a = CONST_2PI - a;
355 }
356 k = fabs(a / (fang - iang));
357 }
358
359 return k;
360}
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:28
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
Struct representing NSIMD field line markers.
Definition particle.h:342