ASCOT5
Loading...
Searching...
No Matches
simulate_gc_adaptive.c
Go to the documentation of this file.
1
5#include <stdio.h>
6#include <stdlib.h>
7#include <time.h>
8#include <omp.h>
9#include <math.h>
10#include "../ascot5.h"
11#include "../endcond.h"
12#include "../math.h"
13#include "../consts.h"
14#include "../physlib.h"
15#include "../simulate.h"
16#include "../particle.h"
17#include "../wall.h"
18#include "../diag.h"
19#include "../B_field.h"
20#include "../E_field.h"
21#include "../boozer.h"
22#include "../mhd.h"
23#include "../rfof.h"
24#include "../plasma.h"
26#include "step/step_gc_cashkarp.h"
27#include "mccc/mccc.h"
28#include "mccc/mccc_wiener.h"
29
30DECLARE_TARGET_SIMD_UNIFORM(sim)
32
33#define DUMMY_TIMESTEP_VAL 1.0
34
56
57 /* Wiener arrays needed for the adaptive time step */
58 mccc_wienarr wienarr[NSIMD];
59
60 /* Current time step, suggestions for the next time step and next time
61 * step */
63 real hout_orb[NSIMD] __memalign__;
64 real hout_col[NSIMD] __memalign__;
65 real hout_rfof[NSIMD] __memalign__;
66 real hnext[NSIMD] __memalign__;
67
68 Acceleration acceleration;
69
70 /* Flag indicateing whether a new marker was initialized */
71 int cycle[NSIMD] __memalign__;
72
73 real tol_col = sim->ada_tol_clmbcol;
74 real tol_orb = sim->ada_tol_orbfol;
75
76 real cputime, cputime_last; // Global cpu time: recent and previous record
77
78 particle_simd_gc p; // This array holds current states
79 particle_simd_gc p0; // This array stores previous states
80
81 rfof_marker rfof_mrk; // RFOF specific data
82
83 for(int i=0; i< NSIMD; i++) {
84 p.id[i] = -1;
85 p.running[i] = 0;
86 acceleration.acc[i] = 1.0;
87 acceleration.orbittime[i] = -1;
88 acceleration.cross[i].crossed_once = 0;
89 }
90
91 /* Initialize running particles */
92 int n_running = particle_cycle_gc(pq, &p, &sim->B_data, cycle);
93
94 if(sim->enable_icrh) {
95 rfof_set_up(&rfof_mrk, &sim->rfof_data);
96 }
97
98 #pragma omp simd
99 for(int i = 0; i < NSIMD; i++) {
100 if(cycle[i] > 0) {
101 /* Determine initial time-step */
102 hin[i] = simulate_gc_adaptive_inidt(sim, &p, i);
103 if(sim->enable_clmbcol) {
104 /* Allocate array storing the Wiener processes */
105 mccc_wiener_initialize(&(wienarr[i]), p.time[i]);
106 }
107 }
108 }
109
110 cputime_last = A5_WTIME;
111
112 /* MAIN SIMULATION LOOP
113 * - Store current state
114 * - Integrate motion due to bacgkround EM-field (orbit-following)
115 * - Integrate scattering due to Coulomb collisions
116 * - Check whether time step was accepted
117 * - NO: revert to initial state and ignore the end of the loop
118 * (except CPU_TIME_MAX end condition if this is implemented)
119 * - YES: update particle time, clean redundant Wiener processes, and
120 * proceed
121 * - Check for end condition(s)
122 * - Update diagnostics
123 */
124 while(n_running > 0) {
125
126 /* Store marker states in case time step will be rejected */
127 #pragma omp simd
128 for(int i = 0; i < NSIMD; i++) {
129 particle_copy_gc(&p, i, &p0, i);
130 hout_orb[i] = DUMMY_TIMESTEP_VAL;
131 hout_col[i] = DUMMY_TIMESTEP_VAL;
132 hout_rfof[i] = DUMMY_TIMESTEP_VAL;
133 hnext[i] = DUMMY_TIMESTEP_VAL;
134 }
135
136 /*************************** Physics **********************************/
137
138 /* Set time-step negative if tracing backwards in time */
139 #pragma omp simd
140 for(int i = 0; i < NSIMD; i++) {
141 if(sim->reverse_time) {
142 hin[i] = -hin[i];
143 }
144 }
145
146 /* Cash-Karp method for orbit-following */
147 if(sim->enable_orbfol) {
148 if(sim->enable_mhd) {
150 &p, hin, hout_orb, tol_orb, &sim->B_data, &sim->E_data,
151 &sim->boozer_data, &sim->mhd_data, sim->enable_aldforce);
152 }
153 else {
155 &p, hin, hout_orb, tol_orb, &sim->B_data, &sim->E_data,
156 sim->enable_aldforce);
157 }
158 /* Check whether time step was rejected */
159 #pragma omp simd
160 for(int i = 0; i < NSIMD; i++) {
161 /* Switch sign of the time-step again if it was reverted earlier
162 */
163 if(sim->reverse_time) {
164 hout_orb[i] = -hout_orb[i];
165 hin[i] = -hin[i];
166 }
167 if(p.running[i] && hout_orb[i] < 0){
168 p.running[i] = 0;
169 hnext[i] = hout_orb[i];
170 }
171 }
172 }
173
174 /* Milstein method for collisions */
175 if(sim->enable_clmbcol) {
176 real rnd[5*NSIMD];
177 random_normal_simd(&sim->random_data, 5*NSIMD, rnd);
179 &p, hin, acceleration.acc, acceleration.collfreq,
180 hout_col, tol_col, wienarr, &sim->B_data,
181 &sim->plasma_data, &sim->mccc_data, rnd);
182
183 /* Check whether time step was rejected */
184 #pragma omp simd
185 for(int i = 0; i < NSIMD; i++) {
186 if(p.running[i] && hout_col[i] < 0){
187 p.running[i] = 0;
188 hnext[i] = hout_col[i];
189 }
190 }
191 }
192
193 /* Performs the ICRH kick if in resonance. */
194 if(sim->enable_icrh) {
195 rfof_resonance_check_and_kick_gc(
196 &p, hin, hout_rfof, &rfof_mrk, &sim->rfof_data, &sim->B_data);
197
198 /* Check whether time step was rejected */
199 #pragma omp simd
200 for(int i = 0; i < NSIMD; i++) {
201 if(p.running[i] && hout_rfof[i] < 0){
202 p.running[i] = 0;
203 hnext[i] = hout_rfof[i];
204 }
205 }
206 }
207
208 /**********************************************************************/
209
210 cputime = A5_WTIME;
211 #pragma omp simd
212 for(int i = 0; i < NSIMD; i++) {
213 if(p.id[i] > 0 && !p.err[i]) {
214 /* Check other time step limitations */
215 if(hnext[i] > 0) {
216 real dphi = fabs(p0.phi[i]-p.phi[i]) / sim->ada_max_dphi;
217 real drho = fabs(p0.rho[i]-p.rho[i]) / sim->ada_max_drho;
218
219 if(dphi > 1 && dphi > drho) {
220 hnext[i] = -hin[i]/dphi;
221 }
222 else if(drho > 1 && drho > dphi) {
223 hnext[i] = -hin[i]/drho;
224 }
225 }
226
227 /* Retrieve marker states in case time step was rejected */
228 if(hnext[i] < 0) {
229 particle_copy_gc(&p0, i, &p, i);
230 }
231 if(p.running[i]){
232
233 /* Advance time (if time step was accepted) and determine
234 next time step */
235 if(hnext[i] < 0){
236 /* if hnext < 0, you screwed up and had to copy the
237 previous state. Therefore, let us use the suggestion
238 given by the integrator when retaking the failed step.*/
239 hin[i] = -hnext[i];
240 }
241 else {
242 p.time[i] += ( 1.0 - 2.0 * ( sim->reverse_time > 0 ) )
243 * hin[i] * acceleration.acc[i];
244 p.mileage[i] += hin[i] * acceleration.acc[i];
245 if(acceleration.orbittime[i] >= 0)
246 acceleration.orbittime[i] += hin[i] * acceleration.acc[i];
247 /* In case the time step was succesful, pick the
248 smallest recommended value for the next step */
249 if(hnext[i] > hout_orb[i]) {
250 /* Use time step suggested by the orbit-following
251 integrator */
252 hnext[i] = hout_orb[i];
253 }
254 if(hnext[i] > hout_col[i]) {
255 /* Use time step suggested by the collision
256 integrator */
257 hnext[i] = hout_col[i];
258 }
259 if(hnext[i] > hout_rfof[i]) {
260 /* Use time step suggested by RFOF */
261 hnext[i] = hout_rfof[i];
262 }
263 if(hnext[i] == 1.0) {
264 /* Time step is unchanged (happens when no physics
265 are enabled) */
266 hnext[i] = hin[i];
267 }
268 hin[i] = hnext[i];
269 if(sim->enable_clmbcol) {
270 /* Clear wiener processes */
271 mccc_wiener_clean(&(wienarr[i]), p.time[i]);
272 }
273 }
274
275 p.cputime[i] += cputime - cputime_last;
276 }
277 }
278 }
279 cputime_last = cputime;
280
281 /* If OMP is crossed, adjust acceleration */
282 if(sim->enable_ada > 1) {
283 recalculate_acceleration(&acceleration, sim, &p, &p0);
284 }
285
286 /* Check possible end conditions */
287 endcond_check_gc(&p, &p0, sim);
288
289 /* Update diagnostics */
290 diag_update_gc(&sim->diag_data, &sim->B_data, &p, &p0);
291
292 /* Update number of running particles */
293 n_running = particle_cycle_gc(pq, &p, &sim->B_data, cycle);
294
295 /* Determine simulation time-step for new particles */
296 #pragma omp simd
297 for(int i = 0; i < NSIMD; i++) {
298 if(cycle[i] > 0) {
299 hin[i] = simulate_gc_adaptive_inidt(sim, &p, i);
300 acceleration.acc[i] = 1.0;
301 acceleration.orbittime[i] = -1;
302 acceleration.cross[i].crossed_once = 0;
303 if(sim->enable_clmbcol) {
304 /* Re-allocate array storing the Wiener processes */
305 mccc_wiener_initialize(&(wienarr[i]), p.time[i]);
306 }
307 if(sim->enable_icrh) {
308 /* Reset icrh (rfof) resonance memory matrix. */
309 rfof_clear_history(&rfof_mrk, i);
310 }
311 }
312 }
313 }
314
315 /* All markers simulated! */
316
317 /* Deallocate rfof structs */
318 if(sim->enable_icrh) {
319 rfof_tear_down(&rfof_mrk);
320 }
321}
322
336 /* Just use some large value if no physics are defined */
338
339 /* Value defined directly by user */
340 if(sim->fix_usrdef_use) {
341 h = sim->fix_usrdef_val;
342 }
343 else {
344 /* Value calculated from gyrotime */
345 if(sim->enable_orbfol) {
346 real Bnorm = math_normc(p->B_r[i], p->B_phi[i], p->B_z[i]);
347 real gyrotime = CONST_2PI /
348 phys_gyrofreq_ppar(p->mass[i], p->charge[i], p->mu[i],
349 p->ppar[i], Bnorm);
350 if(h > gyrotime) {
351 h = gyrotime;
352 }
353 }
354
355 /* Value calculated from collision frequency */
356 if(sim->enable_clmbcol) {
357 real nu = 1;
358 /*mccc_collfreq_gc(p, &sim->B_data, &sim->plasma_data,
359 sim->coldata, &nu, i); */
360
361 /* Only small angle collisions so divide this by 100 */
362 real colltime = 1/(100*nu);
363 if(h > colltime) {h=colltime;}
364 }
365 }
366 return h;
367}
368
369
387{
388 real rz[2];
389 real SAFETY_FACTOR = (float)sim->enable_ada / 1000.0;
390 for(int i = 0; i < NSIMD; i++) {
391 B_field_get_axis_rz(rz, &sim->B_data, p->phi[i]);
392 int omp_crossed = ((p->z[i] - rz[1]) * (p0->z[i] - rz[1]) < 0) &&
393 p->r[i] > rz[0];
394 if(omp_crossed && acc->cross[i].crossed_twice) {
395 if( ((float)acc->cross[i].first_ppar - 0.5) * p->ppar[i] > 0 ) {
396 acc->acc[i] = fmax(1.0, SAFETY_FACTOR / (acc->orbittime[i] * acc->collfreq[i]));
397 }
398 else {
399 acc->acc[i] = 1;
400 }
401 acc->cross[i].crossed_once = 1;
402 acc->cross[i].crossed_twice = 0;
403 acc->cross[i].first_ppar = p->ppar[i] > 0;
404 acc->orbittime[i] = 0;
405 }
406 else if(omp_crossed && acc->cross[i].crossed_once) {
407 acc->cross[i].crossed_twice = 1;
408 if( ((float)acc->cross[i].first_ppar - 0.5) * p->ppar[i] > 0 ) {
409 acc->acc[i] = fmax(1.0, SAFETY_FACTOR / (acc->orbittime[i] * acc->collfreq[i]));
410 acc->cross[i].crossed_once = 1;
411 acc->cross[i].crossed_twice = 0;
412 acc->cross[i].first_ppar = p->ppar[i] > 0;
413 acc->orbittime[i] = 0;
414 }
415 }
416 else if(omp_crossed) {
417 acc->cross[i].crossed_once = 1;
418 acc->cross[i].first_ppar = p->ppar[i] > 0;
419 acc->orbittime[i] = 0;
420 }
421 }
422}
a5err B_field_get_axis_rz(real rz[2], B_field_data *Bdata, real phi)
Return magnetic axis Rz-coordinates.
Definition B_field.c:501
Header file for B_field.c.
Header file for E_field.c.
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
#define A5_WTIME
Wall time.
Definition ascot5.h:124
#define __memalign__
Definition ascot5.h:76
Header file for boozer.c.
Header file containing physical and mathematical constants.
#define CONST_2PI
2*pi
Definition consts.h:14
void diag_update_gc(diag_data *data, B_field_data *Bdata, particle_simd_gc *p_f, particle_simd_gc *p_i)
Collects diagnostics when marker represents a guiding center.
Definition diag.c:217
Header file for diag.c.
void endcond_check_gc(particle_simd_gc *p_f, particle_simd_gc *p_i, sim_data *sim)
Check end conditions for GC markers.
Definition endcond.c:262
Header file for endcond.c.
Header file for math.c.
#define math_normc(a1, a2, a3)
Calculate norm of 3D vector from its components a1, a2, a3.
Definition math.h:71
Header file for mccc package.
void mccc_gc_milstein(particle_simd_gc *p, real *hin, real *acc, real *collfreq, real *hout, real tol, mccc_wienarr *w, B_field_data *Bdata, plasma_data *pdata, mccc_data *mdata, real *rnd)
Integrate collisions for one time-step.
a5err mccc_wiener_clean(mccc_wienarr *w, real t)
Removes Wiener processes from the array that are no longer required.
void mccc_wiener_initialize(mccc_wienarr *w, real initime)
Initializes a struct that stores generated Wiener processes.
Definition mccc_wiener.c:36
header file for mccc_wiener.c
Header file for mhd.c.
void particle_copy_gc(particle_simd_gc *p1, int i, particle_simd_gc *p2, int j)
Copy GC struct.
Definition particle.c:1355
int particle_cycle_gc(particle_queue *q, particle_simd_gc *p, B_field_data *Bdata, int *cycle)
Replace finished GC markers with new ones or dummies.
Definition particle.c:367
Header file for particle.c.
Methods to evaluate elementary physical quantities.
#define phys_gyrofreq_ppar(m, q, mu, ppar, B)
Evaluate gyrofrequency [rad/s] from parallel momentum and magnetic moment.
Definition physlib.h:278
Header file for plasma.c.
#define random_normal_simd(data, n, r)
Definition random.h:102
Contains the functions to be called from the simulation loop when using ICRH.
Header file for simulate.c.
void recalculate_acceleration(Acceleration *acc, sim_data *sim, particle_simd_gc *p, particle_simd_gc *p0)
real simulate_gc_adaptive_inidt(sim_data *sim, particle_simd_gc *p, int i)
Calculates time step value.
void simulate_gc_adaptive(particle_queue *pq, sim_data *sim)
Simulates guiding centers using adaptive time-step.
#define DUMMY_TIMESTEP_VAL
Header file for simulate_gc_adaptive.c.
void step_gc_cashkarp_mhd(particle_simd_gc *p, real *h, real *hnext, real tol, B_field_data *Bdata, E_field_data *Edata, boozer_data *boozer, mhd_data *mhd, int aldforce)
Integrate a guiding center step for a struct of markers with MHD.
void step_gc_cashkarp(particle_simd_gc *p, real *h, real *hnext, real tol, B_field_data *Bdata, E_field_data *Edata, int aldforce)
Integrate a guiding center step for a struct of markers.
Crossing cross[NSIMD]
real orbittime[NSIMD]
Struct for storing Wiener processes.
Definition mccc_wiener.h:28
Marker queue.
Definition particle.h:154
Struct representing NSIMD guiding center markers.
Definition particle.h:275
Reusable struct for storing marker specific data during the simulation loop.
Definition rfof.h:19
Simulation data struct.
Definition simulate.h:58
int enable_orbfol
Definition simulate.h:99
real ada_max_drho
Definition simulate.h:93
real ada_tol_clmbcol
Definition simulate.h:91
plasma_data plasma_data
Definition simulate.h:62
mhd_data mhd_data
Definition simulate.h:66
rfof_data rfof_data
Definition simulate.h:70
real fix_usrdef_val
Definition simulate.h:84
E_field_data E_data
Definition simulate.h:61
int enable_aldforce
Definition simulate.h:104
int enable_mhd
Definition simulate.h:101
int fix_usrdef_use
Definition simulate.h:83
mccc_data mccc_data
Definition simulate.h:75
random_data random_data
Definition simulate.h:74
boozer_data boozer_data
Definition simulate.h:65
int enable_ada
Definition simulate.h:79
B_field_data B_data
Definition simulate.h:60
int reverse_time
Definition simulate.h:113
real ada_max_dphi
Definition simulate.h:95
int enable_icrh
Definition simulate.h:103
int enable_clmbcol
Definition simulate.h:100
real ada_tol_orbfol
Definition simulate.h:89
diag_data diag_data
Definition simulate.h:69
Header file for wall.c.