ASCOT5
Loading...
Searching...
No Matches
simulate.c
Go to the documentation of this file.
1
14#include <string.h>
15#include <unistd.h>
16#include "endcond.h"
17#include "particle.h"
18#include "plasma.h"
19#include "wall.h"
20#include "boozer.h"
21#include "mhd.h"
22#include "neutral.h"
23#include "B_field.h"
24#include "E_field.h"
25#include "random.h"
26#include "simulate.h"
27#include "print.h"
32#include "simulate/mccc/mccc.h"
33#include "gctransform.h"
34#include "asigma.h"
35#include "rfof.h"
36
37void sim_monitor(char* filename, volatile int* n, volatile int* finished);
38
84void simulate(int n_particles, particle_state* p, sim_data* sim) {
85
86 // Size = NSIMD on CPU and Size = Total number of particles on GPU
87 int n_queue_size;
88#ifdef GPU
89 n_queue_size = n_particles;
90#else
91 n_queue_size = NSIMD;
92#endif
93 /**************************************************************************/
94 /* 1. Input offload data is unpacked and initialized by calling */
95 /* respective init functions. */
96 /* */
97 /**************************************************************************/
98
99 simulate_init(sim);
100
101#ifdef GPU
102 if((sim->sim_mode != 1) && (sim->sim_mode != 2)) {
103 print_err("Only GO and GC mode ported to GPU. Please set SIM_MODE=1 or 2.");
104 exit(1);
105 }
106 if(sim->enable_icrh) {
107 print_err("ENABLE_ICRH=1 not ported to GPU. Please disable it.");
108 exit(1);
109 }
110 if(sim->record_mode) {
111 print_err("RECORD_MODE=1 not ported to GPU. Please disable it.");
112 exit(1);
113 }
114 if(sim->enable_atomic) {
115 print_err("Atomic not yet ported to GPU. Please set ENABLE_ATOMIC=0.");
116 exit(1);
117 }
118 if(sim->enable_mhd) {
119 print_err("MHD not yet ported to GPU. Please set ENABLE_MHD=0.");
120 exit(1);
121 }
122 if(sim->diag_data.diagorb_collect) {
123 print_err(
124 "ENABLE_ORBITWRITE=1 not ported to GPU. Please disable it.");
125 exit(1);
126 }
128 print_err(
129 "ENABLE_TRANSCOEF=1 not ported to GPU. Please disable it.");
130 exit(1);
131 }
132
133#endif
134
135 diag_init(&sim->diag_data, n_particles);
136 GPU_MAP_TO_DEVICE(sim[0:1])
137 B_field_offload(&sim->B_data);
138 E_field_offload(&sim->E_data);
141 wall_offload(&sim->wall_data);
143 mhd_offload(&sim->mhd_data);
145 diag_offload(&sim->diag_data);
146
147 /**************************************************************************/
148 /* 2. Meta data (e.g. random number generator) is initialized. */
149 /* */
150 /**************************************************************************/
151#ifdef GPU
152 /* On GPU we need one RNG state per parallel slot (thread/lane).
153 * data_size is a safety factor (number of RNGs used per particle/loop).
154 * Total number of RNG states = data_size * n_queue_size.
155 */
156 int data_size = 5;
157 /* Allocate an array of RNG states (one per parallel element) */
158 sim->random_data = malloc(data_size * n_queue_size * sizeof(random_data));
159 /* Initialize each RNG state with a different seed.
160 * Using i ensures independent sequences across threads.
161 */
162 for(int i = 0; i < data_size * n_queue_size; ++i) {
163 random_init(&sim->random_data[i], i);
164 }
165 /* Transfer RNG states to the GPU device memory */
166 GPU_MAP_TO_DEVICE(sim->random_data[0:data_size * n_queue_size])
167#else
168 sim->random_data = malloc(sizeof(random_data));
169 random_init(sim->random_data, 0);
170#endif
171 /**************************************************************************/
172 /* 3. Markers are put into simulation queue. */
173 /* */
174 /**************************************************************************/
176
177 pq.n = 0;
178 for(int i = 0; i < n_particles; i++) {
179 pq.n++;
180 }
181
182 pq.p = (particle_state**) malloc(pq.n * sizeof(particle_state*));
183 pq.finished = 0;
184
185 pq.next = 0;
186 for(int i = 0; i < n_particles; i++) {
187 pq.p[pq.next++] = &p[i];
188
189 }
190 pq.next = 0;
191
192 print_out(VERBOSE_NORMAL, "Simulation begins; %d threads.\n",
193 omp_get_max_threads());
194 fflush(stdout);
195
196 /**************************************************************************/
197 /* 4. Threads are spawned. One thread is dedicated for monitoring */
198 /* progress, if monitoring is active. */
199 /* */
200 /**************************************************************************/
201#ifndef GPU
202 omp_set_max_active_levels(2);
203#endif
204#if !defined(GPU) && VERBOSE > 1
205 #pragma omp parallel sections num_threads(2)
206 {
207 #pragma omp section
208#endif
209 {
210 /******************************************************************/
211 /* 5. Other threads execute marker simulation using the mode the */
212 /* user has chosen. */
213 /* */
214 /******************************************************************/
215 if(pq.n > 0 && (sim->sim_mode == simulate_mode_gc
216 || sim->sim_mode == simulate_mode_hybrid)) {
217 if(sim->enable_ada) {
218 OMP_PARALLEL_CPU_ONLY
219 simulate_gc_adaptive(&pq, sim, n_queue_size);
220 }
221 else {
222 OMP_PARALLEL_CPU_ONLY
223 simulate_gc_fixed(&pq, sim, n_queue_size);
224 }
225 }
226 else if(pq.n > 0 && sim->sim_mode == simulate_mode_fo) {
227 OMP_PARALLEL_CPU_ONLY
228 simulate_fo_fixed(&pq, sim, n_queue_size);
229 }
230 else if(pq.n > 0 && sim->sim_mode == simulate_mode_ml) {
231 OMP_PARALLEL_CPU_ONLY
232 simulate_ml_adaptive(&pq, sim);
233 }
234 }
235#if !defined(GPU) && VERBOSE > 1
236 #pragma omp section
237 {
238 /* Update progress until simulation is complete. */
239 /* Trim .h5 from filename and replace it with _<QID>.stdout */
240 if(sim->mpi_rank == sim->mpi_root) {
241 char filename[519], outfn[256];
242 strcpy(outfn, sim->hdf5_out);
243 outfn[strlen(outfn)-3] = '\0';
244 sprintf(filename, "%s_%s.stdout", outfn, sim->qid);
245 sim_monitor(filename, &pq.n, &pq.finished);
246 }
247 }
248 }
249#endif
250
251 /**************************************************************************/
252 /* 6. (If hybrid mode is active) Markers with hybrid end condition active */
253 /* are placed on a new queue, and they have their end condition */
254 /* deactivated and they are simulated with simulate_fo_fixed.c until */
255 /* they have met some other end condition. Threads are spawned and */
256 /* progress is monitored as previously. */
257 /* */
258 /**************************************************************************/
259 int n_new = 0;
260 if(sim->sim_mode == simulate_mode_hybrid) {
261
262 /* Determine the number markers that should be run
263 * in fo after previous gc simulation */
264 for(int i = 0; i < pq.n; i++) {
265 if(pq.p[i]->endcond == endcond_hybrid) {
266 /* Check that there was no wall between when moving from
267 gc to fo */
268 real w_coll;
269 int tile = wall_hit_wall(pq.p[i]->r, pq.p[i]->phi, pq.p[i]->z,
270 pq.p[i]->rprt, pq.p[i]->phiprt, pq.p[i]->zprt,
271 &sim->wall_data, &w_coll);
272 if(tile > 0) {
273 pq.p[i]->walltile = tile;
274 pq.p[i]->endcond |= endcond_wall;
275 }
276 else {
277 n_new++;
278 }
279 }
280 }
281 }
282 if(n_new > 0) {
283
284 /* Reset hybrid marker end condition */
285 for(int i = 0; i < pq.n; i++) {
286 if(pq.p[i]->endcond & endcond_hybrid) {
287 pq.p[i]->endcond ^= endcond_hybrid;
288 }
289 }
290 pq.next = 0;
291 pq.finished = 0;
292
293#if !defined(GPU) && VERBOSE > 1
294 #pragma omp parallel sections num_threads(2)
295 {
296 #pragma omp section
297#endif
298 {
299 OMP_PARALLEL_CPU_ONLY
300 simulate_fo_fixed(&pq, sim, n_queue_size);
301 }
302#if !defined(GPU) && VERBOSE > 1
303 #pragma omp section
304 {
305 /* Trim .h5 from filename and replace it with _<qid>.stdout */
306 if(sim->mpi_rank == sim->mpi_root) {
307 char filename[519], outfn[256];
308 strcpy(outfn, sim->hdf5_out);
309 outfn[strlen(outfn)-3] = '\0';
310 sprintf(filename, "%s_%s.stdout", outfn, sim->qid);
311 sim_monitor(filename, &pq.n, &pq.finished);
312 }
313 }
314 }
315#endif
316 }
317
318 /**************************************************************************/
319 /* 7. Simulation data is deallocated. */
320 /**************************************************************************/
321 free(pq.p);
322
323
324 /**************************************************************************/
325 /* 8. Execution returns to host where this function was called. */
326 /* */
327 /**************************************************************************/
328
329 diag_onload(&sim->diag_data);
330 print_out(VERBOSE_NORMAL, "Simulation complete.\n");
331}
332
339
342
343 if(sim->disable_gctransform) {
345 }
347}
348
365void sim_monitor(char* filename, volatile int* n, volatile int* finished) {
366 /* Open a file for writing simulation progress */
367 FILE *f = fopen(filename, "w");
368 if (f == NULL) {
370 "Warning. %s could not be opened for progress updates.\n",
371 filename);
372 return;
373 }
374
375 real time_sim_started = A5_WTIME;
376 int stopflag = 1; /* Ensures progress is written one last time at 100% */
377 int n_temp, finished_temp; /* Use these to store volatile variables so that
378 their value does not change during one loop */
379 while(stopflag) {
380 n_temp = *n;
381 finished_temp = *finished;
382 real fracprog = ((real) finished_temp)/n_temp;
383 real timespent = (A5_WTIME)-time_sim_started;
384
385 if(n_temp == finished_temp) {
386 stopflag = 0;
387 }
388
389 if(fracprog == 0) {
390 fprintf(f, "No marker has finished simulation yet. "
391 "Time spent: %.2f h\n", timespent/3600);
392 }
393 else {
394 fprintf(f, "Progress: %d/%d, %.2f %%. Time spent: %.2f h, "
395 "estimated time to finish: %.2f h\n", finished_temp, n_temp,
396 100*fracprog, timespent/3600,
397 (1/fracprog-1)*timespent/3600);
398 }
399 fflush(f);
401 }
402
403 fprintf(f, "Simulation finished.\n");
404 fclose(f);
405}
void B_field_offload(B_field_data *data)
Offload data to the accelerator.
Definition B_field.c:61
Header file for B_field.c.
void E_field_offload(E_field_data *data)
Offload data to the accelerator.
Definition E_field.c:50
Header file for E_field.c.
double real
Definition ascot5.h:85
#define NSIMD
Number of particles simulated simultaneously in a particle group operations.
Definition ascot5.h:91
#define A5_PRINTPROGRESSINTERVAL
How often progress is being written (s) in the stdout file.
Definition ascot5.h:121
#define A5_WTIME
Wall time.
Definition ascot5.h:124
void asigma_extrapolate(int extrapolate)
Toggle extrapolation when evaluating cross sections.
Definition asigma.c:45
void asigma_offload(asigma_data *data)
Offload data to the accelerator.
Definition asigma.c:67
Header file for asigma.c.
void boozer_offload(boozer_data *data)
Offload data to the accelerator.
Definition boozer.c:91
Header file for boozer.c.
void diag_offload(diag_data *data)
Offload data to the accelerator.
Definition diag.c:131
void diag_onload(diag_data *data)
Onload data back to the host.
Definition diag.c:154
int diag_init(diag_data *data, int Nmrk)
Initializes diagnostics data.
Definition diag.c:37
Header file for endcond.c.
@ endcond_wall
Definition endcond.h:22
@ endcond_hybrid
Definition endcond.h:28
void gctransform_setorder(int order)
Set the order of the transformation.
Definition gctransform.c:62
Header file for gctransform.c.
void mccc_init(mccc_data *mdata, int include_energy, int include_pitch, int include_gcdiff)
Set collision operator data.
Definition mccc.c:17
Header file for mccc package.
void mhd_offload(mhd_data *data)
Offload data to the accelerator.
Definition mhd.c:50
Header file for mhd.c.
void neutral_offload(neutral_data *data)
Offload data to the accelerator.
Definition neutral.c:45
Header file for neutral.c.
Header file for particle.c.
void plasma_offload(plasma_data *data)
Offload data to the accelerator.
Definition plasma.c:62
Header file for plasma.c.
Macros for printing console output.
#define print_out(v,...)
Print to standard output.
Definition print.h:31
@ VERBOSE_NORMAL
Definition print.h:18
@ VERBOSE_DEBUG
Definition print.h:17
#define print_err(...)
Print to standard error.
Definition print.h:42
Header file for random.c.
void * random_data
Definition random.h:100
#define random_init(data, seed)
Definition random.h:107
Contains the functions to be called from the simulation loop when using ICRH.
void simulate(int n_particles, particle_state *p, sim_data *sim)
Execute marker simulation.
Definition simulate.c:84
void simulate_init(sim_data *sim)
Initialize simulation data struct.
Definition simulate.c:338
void sim_monitor(char *filename, volatile int *n, volatile int *finished)
Monitor simulation progress.
Definition simulate.c:365
Header file for simulate.c.
@ simulate_mode_fo
Definition simulate.h:34
@ simulate_mode_ml
Definition simulate.h:45
@ simulate_mode_gc
Definition simulate.h:37
@ simulate_mode_hybrid
Definition simulate.h:42
void simulate_fo_fixed(particle_queue *pq, sim_data *sim, int mrk_array_size)
Simulates particles using fixed time-step.
Header file for simulate_fo_fixed.c.
void simulate_gc_adaptive(particle_queue *pq, sim_data *sim, int mrk_array_size)
Simulates guiding centers using adaptive time-step.
Header file for simulate_gc_adaptive.c.
void simulate_gc_fixed(particle_queue *pq, sim_data *sim, int mrk_array_size)
Simulates guiding centers using fixed time-step.
Header file for simulate_gc_fixed.c.
void simulate_ml_adaptive(particle_queue *pq, sim_data *sim)
Simulates magnetic field-lines using adaptive time-step.
Header file for simulate_ml_adaptive.c.
int diagtrcof_collect
Definition diag.h:28
int diagorb_collect
Definition diag.h:22
Marker queue.
Definition particle.h:154
particle_state ** p
Definition particle.h:156
volatile int next
Definition particle.h:158
volatile int finished
Definition particle.h:159
General representation of a marker.
Definition particle.h:40
integer walltile
Definition particle.h:65
integer endcond
Definition particle.h:64
Simulation data struct.
Definition simulate.h:58
char qid[256]
Definition simulate.h:132
int record_mode
Definition simulate.h:80
int sim_mode
Definition simulate.h:78
int disable_energyccoll
Definition simulate.h:107
plasma_data plasma_data
Definition simulate.h:62
mhd_data mhd_data
Definition simulate.h:66
int enable_atomic
Definition simulate.h:102
int disable_gcdiffccoll
Definition simulate.h:111
E_field_data E_data
Definition simulate.h:61
int mpi_rank
Definition simulate.h:136
int disable_pitchccoll
Definition simulate.h:109
int enable_mhd
Definition simulate.h:101
random_data * random_data
Definition simulate.h:74
mccc_data mccc_data
Definition simulate.h:75
neutral_data neutral_data
Definition simulate.h:63
boozer_data boozer_data
Definition simulate.h:65
int enable_ada
Definition simulate.h:79
B_field_data B_data
Definition simulate.h:60
char hdf5_out[256]
Definition simulate.h:131
wall_data wall_data
Definition simulate.h:64
int mpi_root
Definition simulate.h:135
int enable_icrh
Definition simulate.h:103
asigma_data asigma_data
Definition simulate.h:67
int disable_gctransform
Definition simulate.h:105
diag_data diag_data
Definition simulate.h:69
void wall_offload(wall_data *data)
Offload data to the accelerator.
Definition wall.c:46
int wall_hit_wall(real r1, real phi1, real z1, real r2, real phi2, real z2, wall_data *w, real *w_coll)
Check if a given directed line segment intersects the wall.
Definition wall.c:80
Header file for wall.c.