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 "rfof.h"
68#include "print.h"
69#include "simulate.h"
70#include "particle.h"
71#include "endcond.h"
72#include "hdf5_interface.h"
73#include "gitver.h"
74#include "mpi_interface.h"
75
76#include "ascot5_main.h"
77
78#ifdef TRAP_FPE
79#include <fenv.h>
80#endif
81
82int read_arguments(int argc, char** argv, sim_data* sim);
83
100int main(int argc, char** argv) {
101
102#ifdef TRAP_FPE
103 /* This will raise floating point exceptions */
104 feenableexcept(FE_DIVBYZERO| FE_INVALID | FE_OVERFLOW);
105 /*
106 * If you are hunting a specific exception, you can disable the exceptions
107 * in other parts of the code by surrounding it with: */
108 /*
109 * fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
110 * --- your code here ---
111 * feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
112 *
113 * */
114#endif
115
116 /* Read and parse command line arguments */
117 sim_data sim;
118 if( read_arguments(argc, argv, &sim) ) {
119 abort();
120 return 1;
121 }
122
123 if(sim.mpi_size > 0) {
124 /* This is a pseudo-mpi run, where rank and size were set on the command
125 * line. Only set root equal to rank since there are no other processes
126 */
127 sim.mpi_root = sim.mpi_rank;
128 }
129 else {
130 /* Init MPI if used, or run serial */
131 int mpi_rank, mpi_size, mpi_root;
132 mpi_interface_init(argc, argv, &mpi_rank, &mpi_size, &mpi_root);
133 sim.mpi_rank = mpi_rank;
134 sim.mpi_size = mpi_size;
135 sim.mpi_root = mpi_root;
136 }
137
138 print_out0(VERBOSE_MINIMAL, sim.mpi_rank, sim.mpi_root, "ASCOT5_MAIN\n");
140 "Tag %s\nBranch %s\n\n", GIT_VERSION, GIT_BRANCH);
141 print_out(VERBOSE_NORMAL, "Initialized MPI, rank %d, size %d.\n",
142 sim.mpi_rank, sim.mpi_size);
143
144 /* Total number of markers to be simulated */
145 int n_tot;
146 /* Marker input struct */
148
149 /* Read input from the HDF5 file */
156 &p, &n_tot) ) {
158 "\nInput reading or initializing failed.\n"
159 "See stderr for details.\n");
161 abort();
162 return 1;
163 };
164
165 if(sim.enable_icrh) {
166 rfof_init(&(sim.rfof_data));
167 }
168
169 /* Initialize marker states array ps and free marker input p */
170 int n_proc; /* Number of markers allocated for this MPI process */
171 particle_state* ps;
172 if( prepare_markers(&sim, n_tot, p, &ps, &n_proc) ) {
173 goto CLEANUP_FAILURE;
174 }
175
176 /* Write run group and inistate */
177 char qid[11];
179 if( write_rungroup(&sim, ps, n_tot, qid) ) {
180 goto CLEANUP_FAILURE;
181 }
182
183 /* Actual simulation is done here; the results are stored in
184 * diag_offload_array and pout contains end states from all processes.
185 * n_gathered is the number of markers in the output array, which is n_tot
186 * for most cases except when the simulation is run in condor-like manner,
187 * in which case it is equal to n_proc. */
188 int n_gathered;
189 particle_state* pout;
191 &sim, n_tot, n_proc, ps, &n_gathered, &pout);
192
193 /* Free input data */
194 B_field_free(&sim.B_data);
195 E_field_free(&sim.E_data);
198 wall_free(&sim.wall_data);
200 mhd_free(&sim.mhd_data);
202
203 if(sim.enable_icrh) {
204 rfof_free(&sim.rfof_data);
205 }
206
207 /* Write output and clean */
208 if( write_output(&sim, pout, n_gathered) ) {
209 goto CLEANUP_FAILURE;
210 }
211 diag_free(&sim.diag_data);
212
213 /* Display marker summary and free marker arrays */
214 if(sim.mpi_rank == sim.mpi_root) {
215 print_marker_summary(pout, n_tot);
216 }
217 free(pout);
218
219 print_out0(VERBOSE_MINIMAL, sim.mpi_rank, sim.mpi_root, "\nDone.\n");
221 return 0;
222
223/* GOTO this block to free resources in case simulation crashes */
224CLEANUP_FAILURE:
225 free(p);
226 free(ps);
227 free(pout);
229 abort();
230 return 1;
231}
232
253 sim_data* sim, int n_tot, input_particle* pin,
254 particle_state** pout, int* n_proc) {
255
256 /* Choose which markers are used in this MPI process. Simply put, markers
257 * are divided into mpi_size sequential blocks and the mpi_rank:th block
258 * is chosen for this simulation. */
259 int start_index;
260 mpi_my_particles(&start_index, n_proc, n_tot, sim->mpi_rank, sim->mpi_size);
261 pin += start_index;
262
263 /* Set up particlestates on host, needs magnetic field evaluation */
265 "\nInitializing marker states.\n");
266
267 *pout = (particle_state*) malloc(*n_proc * sizeof(particle_state));
268 for(int i = 0; i < *n_proc; i++) {
269 particle_input_to_state(&(pin[i]), &((*pout)[i]), &sim->B_data);
270 }
271
273 "Estimated memory usage %.1f MB.\n",
274 (sizeof(real) * (*n_proc)) / (1024.0*1024.0));
276 "Marker states initialized.\n");
277
278 /* We can now free the input markers */
279 free(pin-start_index);
280
281 return 0;
282}
283
284
295int write_rungroup(sim_data* sim, particle_state* ps, int n_tot, char* qid) {
296
297 if(sim->mpi_rank == sim->mpi_root) {
298 /* Initialize results group in the output file */
300 "\nPreparing output.\n");
301 if( hdf5_interface_init_results(sim, qid, "run") ) {
303 "\nInitializing output failed.\n"
304 "See stderr for details.\n");
305 /* Free offload data and terminate */
306 return 1;
307 }
308 strcpy(sim->qid, qid);
309 }
310
311 /* Gather particle states so that we can write inistate */
312 int n_gather;
313 particle_state* ps_gather;
314 mpi_gather_particlestate(ps, &ps_gather, &n_gather, n_tot,
315 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
316
317 if(sim->mpi_rank == sim->mpi_root) {
318 /* Write inistate */
320 sim->hdf5_out, "inistate", n_gather, ps_gather)) {
322 "\n"
323 "Writing inistate failed.\n"
324 "See stderr for details.\n"
325 "\n");
326 /* Free offload data and terminate */
327 return 1;
328 }
330 "\nInistate written.\n");
331 }
332 free(ps_gather);
333
334 return 0;
335}
336
337
356 sim_data* sim, int n_tot, int n_proc, particle_state* pin,
357 int* n_gather, particle_state** pout) {
358
359 /* Actual marker simulation happens here. */
360 real t_sim_start = omp_get_wtime();
361 simulate(n_proc, pin, sim);
362
364 real t_sim_end = omp_get_wtime();
366 "Simulation finished in %lf s\n", t_sim_end-t_sim_start);
367
368 /* Gather output data */
369 mpi_gather_particlestate(pin, pout, n_gather, n_tot, sim->mpi_rank,
370 sim->mpi_size, sim->mpi_root);
371 free(pin);
372
373 mpi_gather_diag(&sim->diag_data, n_tot,
374 sim->mpi_rank, sim->mpi_size, sim->mpi_root);
375 return 0;
376}
377
378
389int write_output(sim_data* sim, particle_state* ps, int n_tot){
390
391 if(sim->mpi_rank == sim->mpi_root) {
392 /* Write endstate */
394 sim->hdf5_out, "endstate", n_tot, ps)) {
396 "\nWriting endstate failed.\n"
397 "See stderr for details.\n");
398 return 1;
399 }
401 "Endstate written.\n");
402 }
403
404 /* Combine diagnostic data and write it to HDF5 file */
406 "\nCombining and writing diagnostics.\n");
407 int err_writediag = 0;
408
409 if(sim->mpi_rank == sim->mpi_root) {
410 err_writediag = hdf5_interface_write_diagnostics(sim);
411 }
412 if(err_writediag) {
414 "\nWriting diagnostics failed.\n"
415 "See stderr for details.\n");
416 return 1;
417 }
418 else {
420 "Diagnostics written.\n");
421 }
422
423 return 0;
424}
425
426
451int read_arguments(int argc, char** argv, sim_data* sim) {
452 struct option longopts[] = {
453 {"in", required_argument, 0, 1},
454 {"out", required_argument, 0, 2},
455 {"mpi_size", required_argument, 0, 3},
456 {"mpi_rank", required_argument, 0, 4},
457 {"d", required_argument, 0, 5},
458 {"options", required_argument, 0, 6},
459 {"bfield", required_argument, 0, 7},
460 {"efield", required_argument, 0, 8},
461 {"marker", required_argument, 0, 9},
462 {"wall", required_argument, 0, 10},
463 {"plasma", required_argument, 0, 11},
464 {"neutral", required_argument, 0, 12},
465 {"boozer", required_argument, 0, 13},
466 {"mhd", required_argument, 0, 14},
467 {"asigma", required_argument, 0, 15},
468 {0, 0, 0, 0}
469 };
470
471 /* Initialize default values */
472 sim->hdf5_in[0] = '\0';
473 sim->hdf5_out[0] = '\0';
474 sim->mpi_rank = 0;
475 sim->mpi_size = 0;
476 strcpy(sim->description, "No description.");
477 sim->qid_options[0] = '\0';
478 sim->qid_bfield[0] = '\0';
479 sim->qid_efield[0] = '\0';
480 sim->qid_marker[0] = '\0';
481 sim->qid_wall[0] = '\0';
482 sim->qid_plasma[0] = '\0';
483 sim->qid_neutral[0] = '\0';
484 sim->qid_boozer[0] = '\0';
485 sim->qid_mhd[0] = '\0';
486 sim->qid_asigma[0] = '\0';
487 sim->qid_nbi[0] = '\0';
488
489 /* Read user input */
490 int c;
491 int slen; /* String length */
492 while((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
493 switch(c) {
494 case 1:
495 /* The .hdf5 filename can be specified with or without the
496 * trailing .h5 */
497 slen = strlen(optarg);
498 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
499 strcpy(sim->hdf5_in, optarg);
500 (sim->hdf5_in)[slen-3]='\0';
501 }
502 else {
503 strcpy(sim->hdf5_in, optarg);
504 }
505 break;
506 case 2:
507 /* The .hdf5 filename can be specified with or without the
508 * trailing .h5 */
509 slen = strlen(optarg);
510 if ( slen > 3 && !strcmp(optarg+slen-3, ".h5") ) {
511 strcpy(sim->hdf5_out, optarg);
512 (sim->hdf5_out)[slen-3]='\0';
513 }
514 else {
515 strcpy(sim->hdf5_out, optarg);
516 }
517 break;
518 case 3:
519 sim->mpi_size = atoi(optarg);
520 break;
521 case 4:
522 sim->mpi_rank = atoi(optarg);
523 break;
524 case 5:
525 strcpy(sim->description, optarg);
526 break;
527 case 6:
528 strcpy(sim->qid_options, optarg);
529 break;
530 case 7:
531 strcpy(sim->qid_bfield, optarg);
532 break;
533 case 8:
534 strcpy(sim->qid_efield, optarg);
535 break;
536 case 9:
537 strcpy(sim->qid_marker, optarg);
538 break;
539 case 10:
540 strcpy(sim->qid_wall, optarg);
541 break;
542 case 11:
543 strcpy(sim->qid_plasma, optarg);
544 break;
545 case 12:
546 strcpy(sim->qid_neutral, optarg);
547 break;
548 case 13:
549 strcpy(sim->qid_boozer, optarg);
550 break;
551 case 14:
552 strcpy(sim->qid_mhd, optarg);
553 break;
554 case 15:
555 strcpy(sim->qid_asigma, optarg);
556 break;
557 default:
558 // Unregonizable argument(s). Tell user how to run ascot5_main
560 "\nUnrecognized argument. The valid arguments are:\n");
562 "--in input file (default: ascot.h5)\n");
564 "--out output file (default: same as input)\n");
566 "--mpi_size number of independent processes\n");
568 "--mpi_rank rank of independent process\n");
570 "--d run description maximum of 250 characters\n");
571 return 1;
572 }
573 }
574
575 /* Default value for input file is ascot.h5, and for output same as input
576 * file. Adujust hdf5_in and hdf5_out accordingly. For output file, we don't
577 * add the .h5 extension here. */
578 if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] == '\0') {
579 /* No input, use default values for both */
580 strcpy(sim->hdf5_in, "ascot.h5");
581 strcpy(sim->hdf5_out, "ascot.h5");
582 }
583 else if(sim->hdf5_in[0] == '\0' && sim->hdf5_out[0] != '\0') {
584 /* Output file is given but the input file is not */
585 strcpy(sim->hdf5_in, "ascot.h5");
586 strcat(sim->hdf5_out, ".h5");
587 }
588 else if(sim->hdf5_in[0] != '\0' && sim->hdf5_out[0] == '\0') {
589 /* Input file is given but the output is not */
590 strcat(sim->hdf5_in, ".h5");
591 strcpy(sim->hdf5_out, sim->hdf5_in);
592 }
593 else {
594 /* Both input and output files are given */
595 strcat(sim->hdf5_in, ".h5");
596 strcat(sim->hdf5_out, ".h5");
597 }
598 return 0;
599}
600
616
617 print_out(VERBOSE_MINIMAL, "\nSummary of results:\n");
618
619 /* Temporary arrays that are needed to store unique end conditions and
620 * errors. We can have at most n_tot different values. */
621 int* temp = (int*)malloc(n_tot*sizeof(int));
622 int* unique = (int*)malloc(n_tot*sizeof(int));
623 int* count = (int*)malloc((n_tot+1)*sizeof(int));
624
625 /* First we find out what the end conditions are */
626 for(int i=0; i<n_tot; i++) {
627 temp[i] = ps[i].endcond;
628 }
629 math_uniquecount(temp, unique, count, n_tot);
630 count[n_tot] = 0;/* This ensures the following while loops are terminated.*/
631
632 /* Print the end conditions, if marker has multiple end conditions, separate
633 * those with "and". */
634 int i = 0;
635 while(count[i] > 0) {
636 /* Initialize */
637 int endconds[32];
638 for(int j=0; j<32;j++) {
639 endconds[j] = 0;
640 }
641 char endcondstr[256];
642 endcondstr[0] = '\0';
643
644 /* Represent all end conditions with a single string and print it */
645 int j = 0;
646 endcond_parse(unique[i], endconds);
647 while(endconds[j]) {
648 if(j>0) {
649 strcat(endcondstr, " and ");
650 }
651 char temp[256];
652 endcond_parse2str(endconds[j], temp);
653 strcat(endcondstr, temp);
654 j++;
655 }
656 if(j == 0) {
657 sprintf(endcondstr, "Aborted");
658 }
659 print_out(VERBOSE_MINIMAL, "%9d markers had end condition %s\n",
660 count[i], endcondstr);
661 i++;
662 }
663
664 /* Empty line between end conditions and errors */
666
667 /* Find all errors */
668 for(int i=0; i<n_tot; i++) {
669 temp[i] = (int)(ps[i].err);
670 }
671 math_uniquecount(temp, unique, count, n_tot);
672
673 /* Go through each unique error and represent is a string */
674 i = 0;
675 while(count[i] > 0) {
676 if(unique[i] == 0) {
677 /* Value 0 indicates no error occurred so skip that */
678 i++;
679 continue;
680 }
681 char msg[256];
682 char line[256];
683 char file[256];
684 error_parse2str(unique[i], msg, line, file);
686 "%9d markers were aborted with an error message:\n"
687 " %s\n"
688 " at line %s in %s\n",
689 count[i], msg, line, file);
690 i++;
691 }
692
693 /* If count[0] equals to number of markers and their error field is zero,
694 * we have no markers that were aborted. */
695 if(count[0] == n_tot && unique[0] == 0) {
697 " No markers were aborted.\n");
698 }
699
700 /* Free temporary arrays */
701 free(temp);
702 free(unique);
703 free(count);
704}
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.
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
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
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:58
int mpi_size
Definition simulate.h:137
char qid[256]
Definition simulate.h:132
char qid_wall[256]
Definition simulate.h:144
char qid_asigma[256]
Definition simulate.h:149
plasma_data plasma_data
Definition simulate.h:62
mhd_data mhd_data
Definition simulate.h:66
char hdf5_in[256]
Definition simulate.h:130
rfof_data rfof_data
Definition simulate.h:70
char qid_plasma[256]
Definition simulate.h:145
char qid_marker[256]
Definition simulate.h:143
char qid_nbi[256]
Definition simulate.h:150
E_field_data E_data
Definition simulate.h:61
int mpi_rank
Definition simulate.h:136
char qid_bfield[256]
Definition simulate.h:141
char qid_options[256]
Definition simulate.h:140
char qid_boozer[256]
Definition simulate.h:147
neutral_data neutral_data
Definition simulate.h:63
boozer_data boozer_data
Definition simulate.h:65
char description[256]
Definition simulate.h:133
B_field_data B_data
Definition simulate.h:60
char qid_mhd[256]
Definition simulate.h:148
char hdf5_out[256]
Definition simulate.h:131
char qid_efield[256]
Definition simulate.h:142
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
char qid_neutral[256]
Definition simulate.h:146
diag_data diag_data
Definition simulate.h:69
void wall_free(wall_data *data)
Free allocated resources.
Definition wall.c:29
Header file for wall.c.