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 /* Initialize diagnostics offload data */
172 diag_init(&sim.diag_data, n_tot);
173
174 /* Write run group and inistate */
175 char qid[11];
177 if( write_rungroup(&sim, ps, n_tot, qid) ) {
178 goto CLEANUP_FAILURE;
179 }
180
181 /* Actual simulation is done here; the results are stored in
182 * diag_offload_array and pout contains end states from all processes.
183 * n_gathered is the number of markers in the output array, which is n_tot
184 * for most cases except when the simulation is run in condor-like manner,
185 * in which case it is equal to n_proc. */
186 int n_gathered;
187 particle_state* pout;
189 &sim, n_tot, n_proc, ps, &n_gathered, &pout);
190
191 /* Free input data */
192 B_field_free(&sim.B_data);
193 E_field_free(&sim.E_data);
196 wall_free(&sim.wall_data);
198 mhd_free(&sim.mhd_data);
200
201 /* Write output and clean */
202 if( write_output(&sim, pout, n_gathered) ) {
203 goto CLEANUP_FAILURE;
204 }
205 diag_free(&sim.diag_data);
206
207 /* Display marker summary and free marker arrays */
208 if(sim.mpi_rank == sim.mpi_root) {
209 print_marker_summary(pout, n_tot);
210 }
211 free(pout);
212
213 print_out0(VERBOSE_MINIMAL, sim.mpi_rank, sim.mpi_root, "\nDone.\n");
215 return 0;
216
217/* GOTO this block to free resources in case simulation crashes */
218CLEANUP_FAILURE:
220 free(p);
221 free(ps);
222 free(pout);
223 abort();
224 return 1;
225}
226
247 sim_data* sim, int n_tot, input_particle* pin,
248 particle_state** pout, int* n_proc) {
249
250 /* Choose which markers are used in this MPI process. Simply put, markers
251 * are divided into mpi_size sequential blocks and the mpi_rank:th block
252 * is chosen for this simulation. */
253 int start_index;
254 mpi_my_particles(&start_index, n_proc, n_tot, sim->mpi_rank, sim->mpi_size);
255 pin += start_index;
256
257 /* Set up particlestates on host, needs magnetic field evaluation */
259 "\nInitializing marker states.\n");
260
261 *pout = (particle_state*) malloc(*n_proc * sizeof(particle_state));
262 for(int i = 0; i < *n_proc; i++) {
263 particle_input_to_state(&(pin[i]), &((*pout)[i]), &sim->B_data);
264 }
265
267 "Estimated memory usage %.1f MB.\n",
268 (sizeof(real) * (*n_proc)) / (1024.0*1024.0));
270 "Marker states initialized.\n");
271
272 /* We can now free the input markers */
273 free(pin-start_index);
274
275 return 0;
276}
277
278
289int write_rungroup(sim_data* sim, particle_state* ps, int n_tot, char* qid) {
290
291 if(sim->mpi_rank == sim->mpi_root) {
292 /* Initialize results group in the output file */
294 "\nPreparing output.\n");
295 if( hdf5_interface_init_results(sim, qid, "run") ) {
297 "\nInitializing output failed.\n"
298 "See stderr for details.\n");
299 /* Free offload data and terminate */
300 return 1;
301 }
302 strcpy(sim->qid, qid);
303 }
304
305 /* Gather particle states so that we can write inistate */
306 int n_gather;
307 particle_state* ps_gather;
308 mpi_gather_particlestate(ps, &ps_gather, &n_gather, n_tot,
309 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
310
311 if(sim->mpi_rank == sim->mpi_root) {
312 /* Write inistate */
314 sim->hdf5_out, "inistate", n_gather, ps_gather)) {
316 "\n"
317 "Writing inistate failed.\n"
318 "See stderr for details.\n"
319 "\n");
320 /* Free offload data and terminate */
321 return 1;
322 }
324 "\nInistate written.\n");
325 }
326 free(ps_gather);
327
328 return 0;
329}
330
331
350 sim_data* sim, int n_tot, int n_proc, particle_state* pin,
351 int* n_gather, particle_state** pout) {
352
353 /* Actual marker simulation happens here. */
354 real t_sim_start = omp_get_wtime();
355 simulate(n_proc, pin, sim);
356
358 real t_sim_end = omp_get_wtime();
360 "Simulation finished in %lf s\n", t_sim_end-t_sim_start);
361
362 /* Gather output data */
363 mpi_gather_particlestate(pin, pout, n_gather, n_tot, sim->mpi_rank,
364 sim->mpi_size, sim->mpi_root);
365 free(pin);
366
367 mpi_gather_diag(&sim->diag_data, n_tot,
368 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
369 return 0;
370}
371
372
383int write_output(sim_data* sim, particle_state* ps, int n_tot){
384
385 if(sim->mpi_rank == sim->mpi_root) {
386 /* Write endstate */
388 sim->hdf5_out, "endstate", n_tot, ps)) {
390 "\nWriting endstate failed.\n"
391 "See stderr for details.\n");
392 return 1;
393 }
395 "Endstate written.\n");
396 }
397
398 /* Combine diagnostic data and write it to HDF5 file */
400 "\nCombining and writing diagnostics.\n");
401 int err_writediag = 0;
402
403 if(sim->mpi_rank == sim->mpi_root) {
404 err_writediag = hdf5_interface_write_diagnostics(sim);
405 }
406 if(err_writediag) {
408 "\nWriting diagnostics failed.\n"
409 "See stderr for details.\n");
410 return 1;
411 }
412 else {
414 "Diagnostics written.\n");
415 }
416
417 return 0;
418}
419
420
445int read_arguments(int argc, char** argv, sim_data* sim) {
446 struct option longopts[] = {
447 {"in", required_argument, 0, 1},
448 {"out", required_argument, 0, 2},
449 {"mpi_size", required_argument, 0, 3},
450 {"mpi_rank", required_argument, 0, 4},
451 {"d", required_argument, 0, 5},
452 {"options", required_argument, 0, 6},
453 {"bfield", required_argument, 0, 7},
454 {"efield", required_argument, 0, 8},
455 {"marker", required_argument, 0, 9},
456 {"wall", required_argument, 0, 10},
457 {"plasma", required_argument, 0, 11},
458 {"neutral", required_argument, 0, 12},
459 {"boozer", required_argument, 0, 13},
460 {"mhd", required_argument, 0, 14},
461 {"asigma", required_argument, 0, 15},
462 {0, 0, 0, 0}
463 };
464
465 /* Initialize default values */
466 sim->hdf5_in[0] = '\0';
467 sim->hdf5_out[0] = '\0';
468 sim->mpi_rank = 0;
469 sim->mpi_size = 0;
470 strcpy(sim->description, "No description.");
471 sim->qid_options[0] = '\0';
472 sim->qid_bfield[0] = '\0';
473 sim->qid_efield[0] = '\0';
474 sim->qid_marker[0] = '\0';
475 sim->qid_wall[0] = '\0';
476 sim->qid_plasma[0] = '\0';
477 sim->qid_neutral[0] = '\0';
478 sim->qid_boozer[0] = '\0';
479 sim->qid_mhd[0] = '\0';
480 sim->qid_asigma[0] = '\0';
481 sim->qid_nbi[0] = '\0';
482
483 /* Read user input */
484 int c;
485 int slen; /* String length */
486 while((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
487 switch(c) {
488 case 1:
489 /* The .hdf5 filename can be specified with or without the
490 * trailing .h5 */
491 slen = strlen(optarg);
492 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
493 strcpy(sim->hdf5_in, optarg);
494 (sim->hdf5_in)[slen-3]='\0';
495 }
496 else {
497 strcpy(sim->hdf5_in, optarg);
498 }
499 break;
500 case 2:
501 /* The .hdf5 filename can be specified with or without the
502 * trailing .h5 */
503 slen = strlen(optarg);
504 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
505 strcpy(sim->hdf5_out, optarg);
506 (sim->hdf5_out)[slen-3]='\0';
507 }
508 else {
509 strcpy(sim->hdf5_out, optarg);
510 }
511 break;
512 case 3:
513 sim->mpi_size = atoi(optarg);
514 break;
515 case 4:
516 sim->mpi_rank = atoi(optarg);
517 break;
518 case 5:
519 strcpy(sim->description, optarg);
520 break;
521 case 6:
522 strcpy(sim->qid_options, optarg);
523 break;
524 case 7:
525 strcpy(sim->qid_bfield, optarg);
526 break;
527 case 8:
528 strcpy(sim->qid_efield, optarg);
529 break;
530 case 9:
531 strcpy(sim->qid_marker, optarg);
532 break;
533 case 10:
534 strcpy(sim->qid_wall, optarg);
535 break;
536 case 11:
537 strcpy(sim->qid_plasma, optarg);
538 break;
539 case 12:
540 strcpy(sim->qid_neutral, optarg);
541 break;
542 case 13:
543 strcpy(sim->qid_boozer, optarg);
544 break;
545 case 14:
546 strcpy(sim->qid_mhd, optarg);
547 break;
548 case 15:
549 strcpy(sim->qid_asigma, optarg);
550 break;
551 default:
552 // Unregonizable argument(s). Tell user how to run ascot5_main
554 "\nUnrecognized argument. The valid arguments are:\n");
556 "--in input file (default: ascot.h5)\n");
558 "--out output file (default: same as input)\n");
560 "--mpi_size number of independent processes\n");
562 "--mpi_rank rank of independent process\n");
564 "--d run description maximum of 250 characters\n");
565 return 1;
566 }
567 }
568
569 /* Default value for input file is ascot.h5, and for output same as input
570 * file. Adujust hdf5_in and hdf5_out accordingly. For output file, we don't
571 * add the .h5 extension here. */
572 if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] == '\0') {
573 /* No input, use default values for both */
574 strcpy(sim->hdf5_in, "ascot.h5");
575 strcpy(sim->hdf5_out, "ascot.h5");
576 }
577 else if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] != '\0') {
578 /* Output file is given but the input file is not */
579 strcpy(sim->hdf5_in, "ascot.h5");
580 strcat(sim->hdf5_out, ".h5");
581 }
582 else if(sim->hdf5_in[0] != '\0' && sim->hdf5_out[0] == '\0') {
583 /* Input file is given but the output is not */
584 strcat(sim->hdf5_in, ".h5");
585 strcpy(sim->hdf5_out, sim->hdf5_in);
586 }
587 else {
588 /* Both input and output files are given */
589 strcat(sim->hdf5_in, ".h5");
590 strcat(sim->hdf5_out, ".h5");
591 }
592 return 0;
593}
594
610
611 print_out(VERBOSE_MINIMAL, "\nSummary of results:\n");
612
613 /* Temporary arrays that are needed to store unique end conditions and
614 * errors. We can have at most n_tot different values. */
615 int* temp = (int*)malloc(n_tot*sizeof(int));
616 int* unique = (int*)malloc(n_tot*sizeof(int));
617 int* count = (int*)malloc((n_tot+1)*sizeof(int));
618
619 /* First we find out what the end conditions are */
620 for(int i=0; i<n_tot; i++) {
621 temp[i] = ps[i].endcond;
622 }
623 math_uniquecount(temp, unique, count, n_tot);
624 count[n_tot] = 0;/* This ensures the following while loops are terminated.*/
625
626 /* Print the end conditions, if marker has multiple end conditions, separate
627 * those with "and". */
628 int i = 0;
629 while(count[i] > 0) {
630 /* Initialize */
631 int endconds[32];
632 for(int j=0; j<32;j++) {
633 endconds[j] = 0;
634 }
635 char endcondstr[256];
636 endcondstr[0] = '\0';
637
638 /* Represent all end conditions with a single string and print it */
639 int j = 0;
640 endcond_parse(unique[i], endconds);
641 while(endconds[j]) {
642 if(j>0) {
643 strcat(endcondstr, " and ");
644 }
645 char temp[256];
646 endcond_parse2str(endconds[j], temp);
647 strcat(endcondstr, temp);
648 j++;
649 }
650 if(j == 0) {
651 sprintf(endcondstr, "Aborted");
652 }
653 print_out(VERBOSE_MINIMAL, "%9d markers had end condition %s\n",
654 count[i], endcondstr);
655 i++;
656 }
657
658 /* Empty line between end conditions and errors */
660
661 /* Find all errors */
662 for(int i=0; i<n_tot; i++) {
663 temp[i] = (int)(ps[i].err);
664 }
665 math_uniquecount(temp, unique, count, n_tot);
666
667 /* Go through each unique error and represent is a string */
668 i = 0;
669 while(count[i] > 0) {
670 if(unique[i] == 0) {
671 /* Value 0 indicates no error occurred so skip that */
672 i++;
673 continue;
674 }
675 char msg[256];
676 char line[256];
677 char file[256];
678 error_parse2str(unique[i], msg, line, file);
680 "%9d markers were aborted with an error message:\n"
681 " %s\n"
682 " at line %s in %s\n",
683 count[i], msg, line, file);
684 i++;
685 }
686
687 /* If count[0] equals to number of markers and their error field is zero,
688 * we have no markers that were aborted. */
689 if(count[0] == n_tot && unique[0] == 0) {
691 " No markers were aborted.\n");
692 }
693
694 /* Free temporary arrays */
695 free(temp);
696 free(unique);
697 free(count);
698}
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.
int diag_init(diag_data *data, int Nmrk)
Initializes diagnostics data.
Definition diag.c:37
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_finalize()
Finalize MPI.
void mpi_interface_init(int argc, char **argv, int *mpi_rank, int *mpi_size, int *mpi_root)
Initialize 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.