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
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
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 hnext[NSIMD] __memalign__;
66
67 /* Flag indicateing whether a new marker was initialized */
68 int cycle[NSIMD] __memalign__;
69
70 real tol_col = sim->ada_tol_clmbcol;
71 real tol_orb = sim->ada_tol_orbfol;
72
73 real cputime, cputime_last; // Global cpu time: recent and previous record
74
75 particle_simd_gc p; // This array holds current states
76 particle_simd_gc p0; // This array stores previous states
77
78 for(int i=0; i< NSIMD; i++) {
79 p.id[i] = -1;
80 p.running[i] = 0;
81 }
82
83 /* Initialize running particles */
84 int n_running = particle_cycle_gc(pq, &p, &sim->B_data, cycle);
85
86 #pragma omp simd
87 for(int i = 0; i < NSIMD; i++) {
88 if(cycle[i] > 0) {
89 /* Determine initial time-step */
90 hin[i] = simulate_gc_adaptive_inidt(sim, &p, i);
91 if(sim->enable_clmbcol) {
92 /* Allocate array storing the Wiener processes */
93 mccc_wiener_initialize(&(wienarr[i]), p.time[i]);
94 }
95 }
96 }
97
98 cputime_last = A5_WTIME;
99
100 /* MAIN SIMULATION LOOP
101 * - Store current state
102 * - Integrate motion due to bacgkround EM-field (orbit-following)
103 * - Integrate scattering due to Coulomb collisions
104 * - Check whether time step was accepted
105 * - NO: revert to initial state and ignore the end of the loop
106 * (except CPU_TIME_MAX end condition if this is implemented)
107 * - YES: update particle time, clean redundant Wiener processes, and proceed
108 * - Check for end condition(s)
109 * - Update diagnostics
110 */
111 while(n_running > 0) {
112
113 /* Store marker states in case time step will be rejected */
114 #pragma omp simd
115 for(int i = 0; i < NSIMD; i++) {
116 particle_copy_gc(&p, i, &p0, i);
117 hout_orb[i] = DUMMY_TIMESTEP_VAL;
118 hout_col[i] = DUMMY_TIMESTEP_VAL;
119 hnext[i] = DUMMY_TIMESTEP_VAL;
120 }
121
122 /*************************** Physics **********************************/
123
124 /* Set time-step negative if tracing backwards in time */
125 #pragma omp simd
126 for(int i = 0; i < NSIMD; i++) {
127 if(sim->reverse_time) {
128 hin[i] = -hin[i];
129 }
130 }
131
132 /* Cash-Karp method for orbit-following */
133 if(sim->enable_orbfol) {
134 if(sim->enable_mhd) {
135 step_gc_cashkarp_mhd(&p, hin, hout_orb, tol_orb,
136 &sim->B_data, &sim->E_data,
137 &sim->boozer_data, &sim->mhd_data);
138 }
139 else {
140 step_gc_cashkarp(&p, hin, hout_orb, tol_orb,
141 &sim->B_data, &sim->E_data);
142 }
143 /* Check whether time step was rejected */
144 #pragma omp simd
145 for(int i = 0; i < NSIMD; i++) {
146 /* Switch sign of the time-step again if it was reverted earlier */
147 if(sim->reverse_time) {
148 hout_orb[i] = -hout_orb[i];
149 hin[i] = -hin[i];
150 }
151 if(p.running[i] && hout_orb[i] < 0){
152 p.running[i] = 0;
153 hnext[i] = hout_orb[i];
154 }
155 }
156 }
157
158 /* Milstein method for collisions */
159 if(sim->enable_clmbcol) {
160 real rnd[5*NSIMD];
161 random_normal_simd(&sim->random_data, 5*NSIMD, rnd);
162 mccc_gc_milstein(&p, hin, hout_col, tol_col, wienarr, &sim->B_data,
163 &sim->plasma_data, &sim->mccc_data, rnd);
164
165 /* Check whether time step was rejected */
166 #pragma omp simd
167 for(int i = 0; i < NSIMD; i++) {
168 if(p.running[i] && hout_col[i] < 0){
169 p.running[i] = 0;
170 hnext[i] = hout_col[i];
171 }
172 }
173 }
174
175 /**********************************************************************/
176
177 cputime = A5_WTIME;
178 #pragma omp simd
179 for(int i = 0; i < NSIMD; i++) {
180 if(p.id[i] > 0 && !p.err[i]) {
181 /* Check other time step limitations */
182 if(hnext[i] > 0) {
183 real dphi = fabs(p0.phi[i]-p.phi[i]) / sim->ada_max_dphi;
184 real drho = fabs(p0.rho[i]-p.rho[i]) / sim->ada_max_drho;
185
186 if(dphi > 1 && dphi > drho) {
187 hnext[i] = -hin[i]/dphi;
188 }
189 else if(drho > 1 && drho > dphi) {
190 hnext[i] = -hin[i]/drho;
191 }
192 }
193
194 /* Retrieve marker states in case time step was rejected */
195 if(hnext[i] < 0) {
196 particle_copy_gc(&p0, i, &p, i);
197
198 hin[i] = -hnext[i];
199 }
200 if(p.running[i]){
201
202 /* Advance time (if time step was accepted) and determine
203 next time step */
204 if(hnext[i] < 0){
205 /* Time step was rejected, use the suggestion given by
206 integrator */
207 hin[i] = -hnext[i];
208 }
209 else {
210 p.time[i] += ( 1.0 - 2.0 * ( sim->reverse_time > 0 ) )
211 * hin[i];
212 p.mileage[i] += hin[i];
213
214 if(hnext[i] > hout_orb[i]) {
215 /* Use time step suggested by the orbit-following
216 integrator */
217 hnext[i] = hout_orb[i];
218 }
219 if(hnext[i] > hout_col[i]) {
220 /* Use time step suggested by the collision
221 integrator */
222 hnext[i] = hout_col[i];
223 }
224 if(hnext[i] == 1.0) {
225 /* Time step is unchanged (happens when no physics
226 are enabled) */
227 hnext[i] = hin[i];
228 }
229 hin[i] = hnext[i];
230 if(sim->enable_clmbcol) {
231 /* Clear wiener processes */
232 mccc_wiener_clean(&(wienarr[i]), p.time[i]);
233 }
234 }
235
236 p.cputime[i] += cputime - cputime_last;
237 }
238 }
239 }
240 cputime_last = cputime;
241
242 /* Check possible end conditions */
243 endcond_check_gc(&p, &p0, sim);
244
245 /* Update diagnostics */
246 diag_update_gc(&sim->diag_data, &sim->B_data, &p, &p0);
247
248 /* Update number of running particles */
249 n_running = particle_cycle_gc(pq, &p, &sim->B_data, cycle);
250
251 /* Determine simulation time-step for new particles */
252 #pragma omp simd
253 for(int i = 0; i < NSIMD; i++) {
254 if(cycle[i] > 0) {
255 hin[i] = simulate_gc_adaptive_inidt(sim, &p, i);
256 if(sim->enable_clmbcol) {
257 /* Re-allocate array storing the Wiener processes */
258 mccc_wiener_initialize(&(wienarr[i]), p.time[i]);
259 }
260 }
261 }
262 }
263
264 /* All markers simulated! */
265
266}
267
281 /* Just use some large value if no physics are defined */
283
284 /* Value defined directly by user */
285 if(sim->fix_usrdef_use) {
286 h = sim->fix_usrdef_val;
287 }
288 else {
289 /* Value calculated from gyrotime */
290 if(sim->enable_orbfol) {
291 real Bnorm = math_normc(p->B_r[i], p->B_phi[i], p->B_z[i]);
292 real gyrotime = CONST_2PI /
293 phys_gyrofreq_ppar(p->mass[i], p->charge[i], p->mu[i],
294 p->ppar[i], Bnorm);
295 if(h > gyrotime) {
296 h = gyrotime;
297 }
298 }
299
300 /* Value calculated from collision frequency */
301 if(sim->enable_clmbcol) {
302 real nu = 1;
303 //mccc_collfreq_gc(p, &sim->B_data, &sim->plasma_data, sim->coldata, &nu, i);
304
305 /* Only small angle collisions so divide this by 100 */
306 real colltime = 1/(100*nu);
307 if(h > colltime) {h=colltime;}
308 }
309 }
310 return h;
311}
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:258
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:67
Header file for mccc package.
void mccc_gc_milstein(particle_simd_gc *p, real *hin, 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:273
Header file for plasma.c.
#define random_normal_simd(data, n, r)
Definition random.h:102
Header file for simulate.c.
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)
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)
Integrate a guiding center step for a struct of markers.
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
Simulation data struct.
Definition simulate.h:154
int enable_orbfol
Definition simulate.h:194
real ada_max_drho
Definition simulate.h:188
real ada_tol_clmbcol
Definition simulate.h:186
plasma_data plasma_data
Definition simulate.h:158
mhd_data mhd_data
Definition simulate.h:162
real fix_usrdef_val
Definition simulate.h:179
E_field_data E_data
Definition simulate.h:157
int enable_mhd
Definition simulate.h:196
int fix_usrdef_use
Definition simulate.h:178
mccc_data mccc_data
Definition simulate.h:169
random_data random_data
Definition simulate.h:168
boozer_data boozer_data
Definition simulate.h:161
B_field_data B_data
Definition simulate.h:156
int reverse_time
Definition simulate.h:206
real ada_max_dphi
Definition simulate.h:190
int enable_clmbcol
Definition simulate.h:195
real ada_tol_orbfol
Definition simulate.h:184
diag_data diag_data
Definition simulate.h:165
Header file for wall.c.