ASCOT5
Loading...
Searching...
No Matches
ascot5_main.c
Go to the documentation of this file.
1
54#include <getopt.h>
55#include <math.h>
56#include <omp.h>
57#include <stdlib.h>
58#include <string.h>
59#include <time.h>
60#include "ascot5.h"
61#include "consts.h"
62#include "math.h"
63#include "wall.h"
64#include "diag.h"
65#include "B_field.h"
66#include "plasma.h"
67#include "print.h"
68#include "simulate.h"
69#include "particle.h"
70#include "endcond.h"
71#include "hdf5_interface.h"
72#include "gitver.h"
73#include "mpi_interface.h"
74
75#include "ascot5_main.h"
76
77#ifdef TRAP_FPE
78#include <fenv.h>
79#endif
80
81int read_arguments(int argc, char** argv, sim_data* sim);
82
99int main(int argc, char** argv) {
100
101#ifdef TRAP_FPE
102 /* This will raise floating point exceptions */
103 feenableexcept(FE_DIVBYZERO| FE_INVALID | FE_OVERFLOW);
104 /*
105 * If you are hunting a specific exception, you can disable the exceptions
106 * in other parts of the code by surrounding it with: */
107 /*
108 * fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
109 * --- your code here ---
110 * feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
111 *
112 * */
113#endif
114
115 /* Read and parse command line arguments */
116 sim_data sim;
117 if( read_arguments(argc, argv, &sim) ) {
118 abort();
119 return 1;
120 }
121
122 if(sim.mpi_size > 0) {
123 /* This is a pseudo-mpi run, where rank and size were set on the command
124 * line. Only set root equal to rank since there are no other processes
125 */
126 sim.mpi_root = sim.mpi_rank;
127 }
128 else {
129 /* Init MPI if used, or run serial */
130 int mpi_rank, mpi_size, mpi_root;
131 mpi_interface_init(argc, argv, &mpi_rank, &mpi_size, &mpi_root);
132 sim.mpi_rank = mpi_rank;
133 sim.mpi_size = mpi_size;
134 sim.mpi_root = mpi_root;
135 }
136
137 print_out0(VERBOSE_MINIMAL, sim.mpi_rank, sim.mpi_root, "ASCOT5_MAIN\n");
139 "Tag %s\nBranch %s\n\n", GIT_VERSION, GIT_BRANCH);
140 print_out(VERBOSE_NORMAL, "Initialized MPI, rank %d, size %d.\n",
141 sim.mpi_rank, sim.mpi_size);
142
143 /* Total number of markers to be simulated */
144 int n_tot;
145 /* Marker input struct */
147
148 /* Read input from the HDF5 file */
155 &p, &n_tot) ) {
157 "\nInput reading or initializing failed.\n"
158 "See stderr for details.\n");
160 abort();
161 return 1;
162 };
163
164 /* Initialize marker states array ps and free marker input p */
165 int n_proc; /* Number of markers allocated for this MPI process */
166 particle_state* ps;
167 if( prepare_markers(&sim, n_tot, p, &ps, &n_proc) ) {
168 goto CLEANUP_FAILURE;
169 }
170
171 /* Write run group and inistate */
172 char qid[11];
174 if( write_rungroup(&sim, ps, n_tot, qid) ) {
175 goto CLEANUP_FAILURE;
176 }
177
178 /* Actual simulation is done here; the results are stored in
179 * diag_offload_array and pout contains end states from all processes.
180 * n_gathered is the number of markers in the output array, which is n_tot
181 * for most cases except when the simulation is run in condor-like manner,
182 * in which case it is equal to n_proc. */
183 int n_gathered;
184 particle_state* pout;
186 &sim, n_tot, n_proc, ps, &n_gathered, &pout);
187
188 /* Free input data */
189 B_field_free(&sim.B_data);
190 E_field_free(&sim.E_data);
193 wall_free(&sim.wall_data);
195 mhd_free(&sim.mhd_data);
197
198 /* Write output and clean */
199 if( write_output(&sim, pout, n_gathered) ) {
200 goto CLEANUP_FAILURE;
201 }
202 diag_free(&sim.diag_data);
203
204 /* Display marker summary and free marker arrays */
205 if(sim.mpi_rank == sim.mpi_root) {
206 print_marker_summary(pout, n_tot);
207 }
208 free(pout);
209
210 print_out0(VERBOSE_MINIMAL, sim.mpi_rank, sim.mpi_root, "\nDone.\n");
212 return 0;
213
214/* GOTO this block to free resources in case simulation crashes */
215CLEANUP_FAILURE:
216 free(p);
217 free(ps);
218 free(pout);
220 abort();
221 return 1;
222}
223
244 sim_data* sim, int n_tot, input_particle* pin,
245 particle_state** pout, int* n_proc) {
246
247 /* Choose which markers are used in this MPI process. Simply put, markers
248 * are divided into mpi_size sequential blocks and the mpi_rank:th block
249 * is chosen for this simulation. */
250 int start_index;
251 mpi_my_particles(&start_index, n_proc, n_tot, sim->mpi_rank, sim->mpi_size);
252 pin += start_index;
253
254 /* Set up particlestates on host, needs magnetic field evaluation */
256 "\nInitializing marker states.\n");
257
258 *pout = (particle_state*) malloc(*n_proc * sizeof(particle_state));
259 for(int i = 0; i < *n_proc; i++) {
260 particle_input_to_state(&(pin[i]), &((*pout)[i]), &sim->B_data);
261 }
262
264 "Estimated memory usage %.1f MB.\n",
265 (sizeof(real) * (*n_proc)) / (1024.0*1024.0));
267 "Marker states initialized.\n");
268
269 /* We can now free the input markers */
270 free(pin-start_index);
271
272 return 0;
273}
274
275
286int write_rungroup(sim_data* sim, particle_state* ps, int n_tot, char* qid) {
287
288 if(sim->mpi_rank == sim->mpi_root) {
289 /* Initialize results group in the output file */
291 "\nPreparing output.\n");
292 if( hdf5_interface_init_results(sim, qid, "run") ) {
294 "\nInitializing output failed.\n"
295 "See stderr for details.\n");
296 /* Free offload data and terminate */
297 return 1;
298 }
299 strcpy(sim->qid, qid);
300 }
301
302 /* Gather particle states so that we can write inistate */
303 int n_gather;
304 particle_state* ps_gather;
305 mpi_gather_particlestate(ps, &ps_gather, &n_gather, n_tot,
306 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
307
308 if(sim->mpi_rank == sim->mpi_root) {
309 /* Write inistate */
311 sim->hdf5_out, "inistate", n_gather, ps_gather)) {
313 "\n"
314 "Writing inistate failed.\n"
315 "See stderr for details.\n"
316 "\n");
317 /* Free offload data and terminate */
318 return 1;
319 }
321 "\nInistate written.\n");
322 }
323 free(ps_gather);
324
325 return 0;
326}
327
328
347 sim_data* sim, int n_tot, int n_proc, particle_state* pin,
348 int* n_gather, particle_state** pout) {
349
350 /* Actual marker simulation happens here. */
351 real t_sim_start = omp_get_wtime();
352 simulate(n_proc, pin, sim);
353
355 real t_sim_end = omp_get_wtime();
357 "Simulation finished in %lf s\n", t_sim_end-t_sim_start);
358
359 /* Gather output data */
360 mpi_gather_particlestate(pin, pout, n_gather, n_tot, sim->mpi_rank,
361 sim->mpi_size, sim->mpi_root);
362 free(pin);
363
364 mpi_gather_diag(&sim->diag_data, n_tot,
365 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
366 return 0;
367}
368
369
380int write_output(sim_data* sim, particle_state* ps, int n_tot){
381
382 if(sim->mpi_rank == sim->mpi_root) {
383 /* Write endstate */
385 sim->hdf5_out, "endstate", n_tot, ps)) {
387 "\nWriting endstate failed.\n"
388 "See stderr for details.\n");
389 return 1;
390 }
392 "Endstate written.\n");
393 }
394
395 /* Combine diagnostic data and write it to HDF5 file */
397 "\nCombining and writing diagnostics.\n");
398 int err_writediag = 0;
399
400 if(sim->mpi_rank == sim->mpi_root) {
401 err_writediag = hdf5_interface_write_diagnostics(sim);
402 }
403 if(err_writediag) {
405 "\nWriting diagnostics failed.\n"
406 "See stderr for details.\n");
407 return 1;
408 }
409 else {
411 "Diagnostics written.\n");
412 }
413
414 return 0;
415}
416
417
442int read_arguments(int argc, char** argv, sim_data* sim) {
443 struct option longopts[] = {
444 {"in", required_argument, 0, 1},
445 {"out", required_argument, 0, 2},
446 {"mpi_size", required_argument, 0, 3},
447 {"mpi_rank", required_argument, 0, 4},
448 {"d", required_argument, 0, 5},
449 {"options", required_argument, 0, 6},
450 {"bfield", required_argument, 0, 7},
451 {"efield", required_argument, 0, 8},
452 {"marker", required_argument, 0, 9},
453 {"wall", required_argument, 0, 10},
454 {"plasma", required_argument, 0, 11},
455 {"neutral", required_argument, 0, 12},
456 {"boozer", required_argument, 0, 13},
457 {"mhd", required_argument, 0, 14},
458 {"asigma", required_argument, 0, 15},
459 {0, 0, 0, 0}
460 };
461
462 /* Initialize default values */
463 sim->hdf5_in[0] = '\0';
464 sim->hdf5_out[0] = '\0';
465 sim->mpi_rank = 0;
466 sim->mpi_size = 0;
467 strcpy(sim->description, "No description.");
468 sim->qid_options[0] = '\0';
469 sim->qid_bfield[0] = '\0';
470 sim->qid_efield[0] = '\0';
471 sim->qid_marker[0] = '\0';
472 sim->qid_wall[0] = '\0';
473 sim->qid_plasma[0] = '\0';
474 sim->qid_neutral[0] = '\0';
475 sim->qid_boozer[0] = '\0';
476 sim->qid_mhd[0] = '\0';
477 sim->qid_asigma[0] = '\0';
478 sim->qid_nbi[0] = '\0';
479
480 /* Read user input */
481 int c;
482 int slen; /* String length */
483 while((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
484 switch(c) {
485 case 1:
486 /* The .hdf5 filename can be specified with or without the
487 * trailing .h5 */
488 slen = strlen(optarg);
489 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
490 strcpy(sim->hdf5_in, optarg);
491 (sim->hdf5_in)[slen-3]='\0';
492 }
493 else {
494 strcpy(sim->hdf5_in, optarg);
495 }
496 break;
497 case 2:
498 /* The .hdf5 filename can be specified with or without the
499 * trailing .h5 */
500 slen = strlen(optarg);
501 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
502 strcpy(sim->hdf5_out, optarg);
503 (sim->hdf5_out)[slen-3]='\0';
504 }
505 else {
506 strcpy(sim->hdf5_out, optarg);
507 }
508 break;
509 case 3:
510 sim->mpi_size = atoi(optarg);
511 break;
512 case 4:
513 sim->mpi_rank = atoi(optarg);
514 break;
515 case 5:
516 strcpy(sim->description, optarg);
517 break;
518 case 6:
519 strcpy(sim->qid_options, optarg);
520 break;
521 case 7:
522 strcpy(sim->qid_bfield, optarg);
523 break;
524 case 8:
525 strcpy(sim->qid_efield, optarg);
526 break;
527 case 9:
528 strcpy(sim->qid_marker, optarg);
529 break;
530 case 10:
531 strcpy(sim->qid_wall, optarg);
532 break;
533 case 11:
534 strcpy(sim->qid_plasma, optarg);
535 break;
536 case 12:
537 strcpy(sim->qid_neutral, optarg);
538 break;
539 case 13:
540 strcpy(sim->qid_boozer, optarg);
541 break;
542 case 14:
543 strcpy(sim->qid_mhd, optarg);
544 break;
545 case 15:
546 strcpy(sim->qid_asigma, optarg);
547 break;
548 default:
549 // Unregonizable argument(s). Tell user how to run ascot5_main
551 "\nUnrecognized argument. The valid arguments are:\n");
553 "--in input file (default: ascot.h5)\n");
555 "--out output file (default: same as input)\n");
557 "--mpi_size number of independent processes\n");
559 "--mpi_rank rank of independent process\n");
561 "--d run description maximum of 250 characters\n");
562 return 1;
563 }
564 }
565
566 /* Default value for input file is ascot.h5, and for output same as input
567 * file. Adujust hdf5_in and hdf5_out accordingly. For output file, we don't
568 * add the .h5 extension here. */
569 if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] == '\0') {
570 /* No input, use default values for both */
571 strcpy(sim->hdf5_in, "ascot.h5");
572 strcpy(sim->hdf5_out, "ascot.h5");
573 }
574 else if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] != '\0') {
575 /* Output file is given but the input file is not */
576 strcpy(sim->hdf5_in, "ascot.h5");
577 strcat(sim->hdf5_out, ".h5");
578 }
579 else if(sim->hdf5_in[0] != '\0' && sim->hdf5_out[0] == '\0') {
580 /* Input file is given but the output is not */
581 strcat(sim->hdf5_in, ".h5");
582 strcpy(sim->hdf5_out, sim->hdf5_in);
583 }
584 else {
585 /* Both input and output files are given */
586 strcat(sim->hdf5_in, ".h5");
587 strcat(sim->hdf5_out, ".h5");
588 }
589 return 0;
590}
591
607
608 print_out(VERBOSE_MINIMAL, "\nSummary of results:\n");
609
610 /* Temporary arrays that are needed to store unique end conditions and
611 * errors. We can have at most n_tot different values. */
612 int* temp = (int*)malloc(n_tot*sizeof(int));
613 int* unique = (int*)malloc(n_tot*sizeof(int));
614 int* count = (int*)malloc((n_tot+1)*sizeof(int));
615
616 /* First we find out what the end conditions are */
617 for(int i=0; i<n_tot; i++) {
618 temp[i] = ps[i].endcond;
619 }
620 math_uniquecount(temp, unique, count, n_tot);
621 count[n_tot] = 0;/* This ensures the following while loops are terminated.*/
622
623 /* Print the end conditions, if marker has multiple end conditions, separate
624 * those with "and". */
625 int i = 0;
626 while(count[i] > 0) {
627 /* Initialize */
628 int endconds[32];
629 for(int j=0; j<32;j++) {
630 endconds[j] = 0;
631 }
632 char endcondstr[256];
633 endcondstr[0] = '\0';
634
635 /* Represent all end conditions with a single string and print it */
636 int j = 0;
637 endcond_parse(unique[i], endconds);
638 while(endconds[j]) {
639 if(j>0) {
640 strcat(endcondstr, " and ");
641 }
642 char temp[256];
643 endcond_parse2str(endconds[j], temp);
644 strcat(endcondstr, temp);
645 j++;
646 }
647 if(j == 0) {
648 sprintf(endcondstr, "Aborted");
649 }
650 print_out(VERBOSE_MINIMAL, "%9d markers had end condition %s\n",
651 count[i], endcondstr);
652 i++;
653 }
654
655 /* Empty line between end conditions and errors */
657
658 /* Find all errors */
659 for(int i=0; i<n_tot; i++) {
660 temp[i] = (int)(ps[i].err);
661 }
662 math_uniquecount(temp, unique, count, n_tot);
663
664 /* Go through each unique error and represent is a string */
665 i = 0;
666 while(count[i] > 0) {
667 if(unique[i] == 0) {
668 /* Value 0 indicates no error occurred so skip that */
669 i++;
670 continue;
671 }
672 char msg[256];
673 char line[256];
674 char file[256];
675 error_parse2str(unique[i], msg, line, file);
677 "%9d markers were aborted with an error message:\n"
678 " %s\n"
679 " at line %s in %s\n",
680 count[i], msg, line, file);
681 i++;
682 }
683
684 /* If count[0] equals to number of markers and their error field is zero,
685 * we have no markers that were aborted. */
686 if(count[0] == n_tot && unique[0] == 0) {
688 " No markers were aborted.\n");
689 }
690
691 /* Free temporary arrays */
692 free(temp);
693 free(unique);
694 free(count);
695}
void B_field_free(B_field_data *data)
Free allocated resources.
Definition B_field.c:32
Header file for B_field.c.
void E_field_free(E_field_data *data)
Free allocated resources.
Definition E_field.c:30
Main header file for ASCOT5.
double real
Definition ascot5.h:85
int main(int argc, char **argv)
Main function for ascot5_main.
Definition ascot5_main.c:99
int offload_and_simulate(sim_data *sim, int n_tot, int n_proc, particle_state *pin, int *n_gather, particle_state **pout)
Offload data to target, carry out the simulation, and return to host.
int prepare_markers(sim_data *sim, int n_tot, input_particle *pin, particle_state **pout, int *n_proc)
Prepare markers for offload.
void print_marker_summary(particle_state *ps, int n_tot)
Writes a summary of what happened to the markers during simulation.
int write_output(sim_data *sim, particle_state *ps, int n_tot)
Store simulation output data.
int write_rungroup(sim_data *sim, particle_state *ps, int n_tot, char *qid)
Create and store run group and marker inistate.
int read_arguments(int argc, char **argv, sim_data *sim)
Read command line arguments and modify sim struct accordingly.
Functions to execute main program externally.
void asigma_free(asigma_data *data)
Free allocated resources.
Definition asigma.c:54
void boozer_free(boozer_data *data)
Free allocated resources.
Definition boozer.c:79
Header file containing physical and mathematical constants.
void diag_free(diag_data *data)
Free allocated resources.
Definition diag.c:102
Header file for diag.c.
void endcond_parse(int endcond, int *endconds)
Split endcond to an array of end conditions.
Definition endcond.c:538
void endcond_parse2str(int endcond, char *str)
Represent end condition in human-readable format.
Definition endcond.c:564
Header file for endcond.c.
void error_parse2str(a5err err, char *msg, char *line, char *file)
Convert error flag in string format.
Definition error.c:62
int hdf5_interface_write_diagnostics(sim_data *sim)
Write diagnostics to HDF5 output.
int hdf5_interface_write_state(char *fn, char *state, integer n, particle_state *p)
Write marker state to HDF5 output.
int hdf5_interface_init_results(sim_data *sim, char *qid, char *run)
Initialize run group.
int hdf5_interface_read_input(sim_data *sim, int input_active, input_particle **p, int *n_markers)
Read and initialize input data.
void hdf5_generate_qid(char *qid)
Generate an identification number for a run.
Header file for hdf5_interface.c.
@ hdf5_input_marker
@ hdf5_input_plasma
@ hdf5_input_options
@ hdf5_input_wall
@ hdf5_input_neutral
@ hdf5_input_bfield
@ hdf5_input_efield
@ hdf5_input_boozer
@ hdf5_input_mhd
@ hdf5_input_asigma
void math_uniquecount(int *in, int *unique, int *count, int n)
Find unique numbers and their frequency in given array.
Definition math.c:276
Header file for math.c.
void mhd_free(mhd_data *data)
Free allocated resources.
Definition mhd.c:34
void mpi_gather_diag(diag_data *data, int ntotal, int mpi_rank, int mpi_size, int mpi_root)
Gather all diagnostics to the root process.
void mpi_my_particles(int *start_index, int *n, int n_tot, int mpi_rank, int mpi_size)
Divide markers to mpi processes.
void mpi_interface_init(int argc, char **argv, int *mpi_rank, int *mpi_size, int *mpi_root)
Initialize MPI.
void mpi_interface_finalize(int err)
Finalize MPI.
void mpi_interface_barrier()
Wait until all processes have reached this routine.
void mpi_gather_particlestate(particle_state *ps, particle_state **ps_gather, int *n_gather, int n_tot, int mpi_rank, int mpi_size, int mpi_root)
Gather all particle states to the root process.
Header file for mpi_interface.c.
void neutral_free(neutral_data *data)
Free allocated resources.
Definition neutral.c:29
void particle_input_to_state(input_particle *p, particle_state *ps, B_field_data *Bdata)
Converts input marker to a marker state.
Definition particle.c:550
Header file for particle.c.
void plasma_free(plasma_data *data)
Free allocated resources.
Definition plasma.c:38
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_IO
Definition print.h:20
@ VERBOSE_MINIMAL
Definition print.h:19
#define print_out0(v, rank, root,...)
Print to standard output only for root process.
Definition print.h:36
void simulate(int n_particles, particle_state *p, sim_data *sim)
Execute marker simulation.
Definition simulate.c:83
Header file for simulate.c.
Wrapper for marker structs.
Definition particle.h:186
General representation of a marker.
Definition particle.h:40
integer endcond
Definition particle.h:64
Simulation data struct.
Definition simulate.h:57
int mpi_size
Definition simulate.h:133
char qid[256]
Definition simulate.h:128
char qid_wall[256]
Definition simulate.h:140
char qid_asigma[256]
Definition simulate.h:145
plasma_data plasma_data
Definition simulate.h:61
mhd_data mhd_data
Definition simulate.h:65
char hdf5_in[256]
Definition simulate.h:126
char qid_plasma[256]
Definition simulate.h:141
char qid_marker[256]
Definition simulate.h:139
char qid_nbi[256]
Definition simulate.h:146
E_field_data E_data
Definition simulate.h:60
int mpi_rank
Definition simulate.h:132
char qid_bfield[256]
Definition simulate.h:137
char qid_options[256]
Definition simulate.h:136
char qid_boozer[256]
Definition simulate.h:143
neutral_data neutral_data
Definition simulate.h:62
boozer_data boozer_data
Definition simulate.h:64
char description[256]
Definition simulate.h:129
B_field_data B_data
Definition simulate.h:59
char qid_mhd[256]
Definition simulate.h:144
char hdf5_out[256]
Definition simulate.h:127
char qid_efield[256]
Definition simulate.h:138
wall_data wall_data
Definition simulate.h:63
int mpi_root
Definition simulate.h:131
asigma_data asigma_data
Definition simulate.h:66
char qid_neutral[256]
Definition simulate.h:142
diag_data diag_data
Definition simulate.h:68
void wall_free(wall_data *data)
Free allocated resources.
Definition wall.c:29
Header file for wall.c.