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
33 diag_transcoef_offload_data* offload_data,
34 real* offload_array) {
35 data->id = &(offload_array[0*offload_data->Nmrk]);
36 data->Kcoef = &(offload_array[1*offload_data->Nmrk]);
37 data->Dcoef = &(offload_array[2*offload_data->Nmrk]);
38
39 data->interval = offload_data->interval;
40 data->recordrho = offload_data->recordrho;
41 data->Navg = offload_data->Navg;
42
43 data->datapoints = malloc(
44 offload_data->Nmrk*sizeof(diag_transcoef_link*) );
45 for(int i = 0; i < offload_data->Nmrk; i++) {
46 data->id[i] = -1;
47 data->datapoints[i] = NULL;
48 }
49}
50
57 free(data->datapoints);
58}
59
71
72 GPU_PARALLEL_LOOP_ALL_LEVELS
73 for(int i=0; i < p_f->n_mrk; i++) {
74 real p[3] = {p_f->p_r[i], p_f->p_phi[i], p_f->p_z[i]};
75 real B[3] = {p_f->B_r[i], p_f->B_phi[i], p_f->B_z[i]};
76 real pitchsign = 1 - 2*(math_dot(p, B) < 0);
78 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
79 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
80 }
81
82 /* If marker simulation was ended, process and clean the data */
83 GPU_PARALLEL_LOOP_ALL_LEVELS
84 for(int i=0; i < p_f->n_mrk; i++) {
85 /* Mask dummy markers and those which are running */
86 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
87 continue;
88 }
89 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
90 }
91}
92
104 #pragma omp simd
105 for(int i=0; i < NSIMD; i++) {
106 real pitchsign = 1 - 2*(p_f->ppar[i] < 0);
108 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
109 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
110 }
111
112
113 /* If marker simulation was ended, process and clean the data */
114 for(int i=0; i < NSIMD; i++) {
115
116 /* Mask dummy markers and those which are running */
117 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
118 continue;
119 }
120
121 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
122 }
123}
124
136 #pragma omp simd
137 for(int i=0; i < NSIMD; i++) {
138 real pitchsign = 1 - 2*(p_f->pitch[i] < 0);
140 data, p_f->index[i], p_f->id[i], p_f->rho[i], p_f->r[i], pitchsign,
141 p_f->mileage[i], p_i->mileage[i], p_f->theta[i], p_i->theta[i]);
142 }
143
144
145 /* If marker simulation was ended, process and clean the data */
146 for(int i=0; i < NSIMD; i++) {
147 /* Mask dummy markers and those which are running */
148 if( p_f->id[i] < 1 || p_f->running[i] > 0 ) {
149 continue;
150 }
151
152 diag_transcoef_process_and_clean(data, p_f->index[i], p_f->id[i]);
153 }
154}
155
156
173 integer id, real rho, real r, real pitchsign,
174 real t_f, real t_i, real theta_f, real theta_i) {
175 /* Mask dummy markers */
176 if( id > 0 ) {
177
178 /* Check whether marker position should be recorded: *
179 * - Time step was accepted t_f > t_i
180 * - Enough time has passed since last record t_f - ti > interval OR
181 no data exists yet.
182 * - Marker has crossed OMP during the current time step.
183 */
184 real record = 0.0;
185 if( t_f > t_i ) {
186 if( data->datapoints[index] == NULL ) {
187 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
188 }
189 else if( t_f - data->datapoints[index]->time > data->interval ) {
190 record = diag_transcoef_check_omp_crossing(theta_f, theta_i);
191 }
192 }
193
194 /* Record */
195 if( record > 0) {
196 diag_transcoef_link* newlink =
197 malloc(sizeof(diag_transcoef_link));
198 newlink->time = t_f;
199 newlink->pitchsign = pitchsign;
200
201 if(data->recordrho) {
202 newlink->rho = rho;
203 }
204 else {
205 newlink->rho = r;
206 }
207
208 /* Store the link or make a new chain if the marker is new */
209 if( data->datapoints[index] == NULL ) {
210 newlink->prevlink = NULL;
211 data->datapoints[index] = newlink;
212 }
213 else {
214 newlink->prevlink = data->datapoints[index];
215 data->datapoints[index] = newlink;
216 }
217 }
218 }
219}
220
221
232 integer index, integer id) {
233
234 /* Count number of positive and negative crossings */
235 int positive = 0, negative = 0;
236 diag_transcoef_link* link = data->datapoints[index];
237 while(link != NULL) {
238 if(link->pitchsign < 0) {
239 negative++;
240 }
241 else {
242 positive++;
243 }
244 link = link->prevlink;
245 }
246
247 /* Which ever there are more are stored */
248 int datasize, sign;
249 if(positive >= negative) {
250 datasize = positive;
251 sign = 1;
252 }
253 else {
254 datasize = negative;
255 sign = -1;
256 }
257
258 /* If there are enough datapoints, process them to K and D */
259 if(datasize > data->Navg) {
260 /* How many points we have after averaging data */
261 int navgpnt = ceil(datasize/data->Navg);
262 real* rho = malloc(navgpnt*sizeof(real));
263 real* time = malloc(navgpnt*sizeof(real));
264
265 /* The datasize is not necessarily multiple of navg. We take the
266 "extra" points from last points and average them separately */
267 link = data->datapoints[index];
268 while(link->pitchsign * sign < 0) {
269 link = link->prevlink;
270 }
271 rho[navgpnt-1] = link->rho;
272 time[navgpnt-1] = link->time;
273
274 int nextrapnts = datasize - navgpnt*data->Navg;
275 if(nextrapnts == 0) {
276 nextrapnts = data->Navg;
277 }
278 for(int k = 1; k < nextrapnts; k++) {
279 link = link->prevlink;
280 while(link->pitchsign * sign < 0) {
281 link = link->prevlink;
282 }
283 rho[navgpnt-1] += link->rho;
284 time[navgpnt-1] += link->time;
285 }
286 rho[navgpnt-1] /= nextrapnts;
287 time[navgpnt-1] /= nextrapnts;
288
289 /* Take the full averages */
290 for(int j = navgpnt-2; j > -1; j--) {
291 rho[j] = 0;
292 time[j] = 0;
293 for(int k = 0; k < data->Navg; k++) {
294 link = link->prevlink;
295 while(link->pitchsign * sign < 0) {
296 link = link->prevlink;
297 }
298 rho[j] += link->rho;
299 time[j] += link->time;
300 }
301 rho[j] /= data->Navg;
302 time[j] /= data->Navg;
303 }
304
305 /* Evaluate coefficients */
306 real K = 0;
307 for(int j = 0; j < navgpnt-1; j++) {
308 K += ( rho[j+1] - rho[j] ) / ( time[j+1] - time[j] );
309 }
310 K = K / navgpnt;
311
312 real D = 0;
313 for(int j = 0; j < navgpnt-1; j++) {
314 real a = rho[j+1] - rho[j] - K * ( time[j+1] - time[j] );
315 D += 0.5*a*a / ( time[j+1] - time[j] );
316 }
317 D = D / navgpnt;
318
319 /* Store and free resources */
320 free(rho);
321 free(time);
322 data->id[index] = (real)id;
323 data->Kcoef[index] = K;
324 data->Dcoef[index] = D;
325 }
326
327 /* Clear temporary storage */
329 link = data->datapoints[index];
330 while(link != NULL) {
331 temp = link->prevlink;
332 free(link);
333 link = temp;
334 }
335 data->datapoints[index] = NULL;
336
337}
338
339
349
350 real k = 0.0;
351 if( floor( fang/CONST_2PI ) != floor( iang/CONST_2PI ) ) {
352
353 real a = fmod(iang, CONST_2PI);
354 if(a < 0){
355 a = CONST_2PI + a;
356 }
357
358 a = fabs(a);
359 if(a > CONST_PI) {
360 a = CONST_2PI - a;
361 }
362 k = fabs(a / (fang - iang));
363 }
364
365 return k;
366}
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.
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 transport coefficient data on target.
void diag_transcoef_init(diag_transcoef_data *data, diag_transcoef_offload_data *offload_data, real *offload_array)
Initializes orbit diagnostics offload data.
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
Transport coefficient diagnostics offload data struct.
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