diff --git a/examples/main.c b/examples/main.c index 9aa4de717624d1d6f73516e38a2748db0faebf43..04fe027dbd3c7875ab802f16aeea678b2bc65a8a 100644 --- a/examples/main.c +++ b/examples/main.c @@ -23,6 +23,7 @@ #include "../config.h" /* Some standard headers. */ +#include <fenv.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -41,6 +42,26 @@ #define ENGINE_POLICY engine_policy_none #endif +void print_help_message() { + + printf("\nUsage: swift [OPTION] PARAMFILE\n\n"); + printf("Valid options are:\n"); + printf(" %2s %8s %s\n", "-c", "", "Run with cosmological time integration"); + printf(" %2s %8s %s\n", "-f", "[value] ", + "Overwrites the CPU frequency (Hz) to be used for time measurements"); + printf(" %2s %8s %s\n", "-g", "", + "Run with an external gravitational potential"); + printf(" %2s %8s %s\n", "-G", "", "Run with self-gravity"); + printf(" %2s %8s %s\n", "-s", "", "Run with SPH"); + printf(" %2s %8s %s\n", "-v", "[12] ", + "Increase the level of verbosity 1: MPI-rank 0 writes " + "2: All MPI ranks write"); + printf(" %2s %8s %s\n", "-y", "", + "Time-step frequency at which task graphs are dumped"); + printf(" %2s %8s %s\n", "-h", "", "Prints this help message and exits"); + printf("\nSee the file example.yml for an example of parameter file.\n"); +} + /** * @brief Main routine that loads a few particles and generates some output. * @@ -49,31 +70,15 @@ int main(int argc, char *argv[]) { int c, icount, periodic = 1; size_t Ngas = 0, Ngpart = 0; - long long N_total[2] = {0, 0}; int nr_threads = 1, nr_queues = -1; - int dump_tasks = 0; - int data[2]; double dim[3] = {1.0, 1.0, 1.0}, shift[3] = {0.0, 0.0, 0.0}; double h_max = -1.0, scaling = 1.0; double time_end = DBL_MAX; - struct part *parts = NULL; - struct gpart *gparts = NULL; - struct space s; - struct engine e; - struct UnitSystem us; struct clocks_time tic, toc; char ICfileName[200] = ""; - char dumpfile[30]; float dt_max = 0.0f, dt_min = 0.0f; int nr_nodes = 1, myrank = 0; - FILE *file_thread; - int with_outputs = 1; - int with_external_gravity = 0; - int with_self_gravity = 0; - int with_hydro = 0; - int engine_policies = 0; - int verbose = 0, talking = 0; - unsigned long long cpufreq = 0; + int with_outputs = 0; #ifdef WITH_MPI struct partition initial_partition; @@ -90,11 +95,8 @@ int main(int argc, char *argv[]) { #endif #endif - /* Choke on FP-exceptions. */ - // feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW ); - - /* Initialize CPU frequency, this also starts time. */ - clocks_set_cpufreq(cpufreq); +/* Choke on FP-exceptions. */ +// feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); #ifdef WITH_MPI /* Start by initializing MPI. */ @@ -113,7 +115,8 @@ int main(int argc, char *argv[]) { if ((res = MPI_Comm_set_errhandler(MPI_COMM_WORLD, MPI_ERRORS_RETURN)) != MPI_SUCCESS) error("Call to MPI_Comm_set_errhandler failed with error %i.", res); - if (myrank == 0) message("MPI is up and running with %i node(s).", nr_nodes); + if (myrank == 0) + printf("[00000.0] MPI is up and running with %i node(s).\n", nr_nodes); fflush(stdout); /* Set a default grid so that grid[0]*grid[1]*grid[2] == nr_nodes. */ @@ -138,42 +141,31 @@ int main(int argc, char *argv[]) { CPU_ZERO(&affinity); CPU_SET(sched_getcpu(), &affinity); if (sched_setaffinity(0, sizeof(cpu_set_t), &affinity) != 0) { - message("failed to set entry thread's affinity"); - } else { - message("set entry thread's affinity"); + error("failed to set entry thread's affinity"); } } #endif - /* Parse the options */ - while ((c = getopt(argc, argv, "a:c:d:e:f:gGh:m:oP:q:R:s:t:v:w:y:z:")) != -1) - switch (c) { - case 'a': - if (sscanf(optarg, "%lf", &scaling) != 1) - error("Error parsing cutoff scaling."); - if (myrank == 0) message("scaling cutoff by %.3f.", scaling); - fflush(stdout); - break; + int dump_tasks = 0; + int with_cosmology = 0; + int with_external_gravity = 0; + int with_self_gravity = 0; + int with_hydro = 0; + int verbose = 0; + char paramFileName[200] = ""; + unsigned long long cpufreq = 0; + + /* Parse the parameters */ + while ((c = getopt(argc, argv, "cf:gGhsv:y")) != -1) switch (c) { case 'c': - if (sscanf(optarg, "%lf", &time_end) != 1) - error("Error parsing final time."); - if (myrank == 0) message("time_end set to %.3e.", time_end); - fflush(stdout); - break; - case 'd': - if (sscanf(optarg, "%f", &dt_min) != 1) - error("Error parsing minimal timestep."); - if (myrank == 0) message("dt_min set to %e.", dt_min); - fflush(stdout); - break; - case 'e': - if (sscanf(optarg, "%f", &dt_max) != 1) - error("Error parsing maximal timestep."); - if (myrank == 0) message("dt_max set to %e.", dt_max); - fflush(stdout); + with_cosmology = 1; break; case 'f': - if (!strcpy(ICfileName, optarg)) error("Error parsing IC file name."); + if (sscanf(optarg, "%llu", &cpufreq) != 1) { + if (myrank == 0) printf("Error parsing CPU frequency (-f).\n"); + if (myrank == 0) print_help_message(); + exit(1); + } break; case 'g': with_external_gravity = 1; @@ -182,132 +174,51 @@ int main(int argc, char *argv[]) { with_self_gravity = 1; break; case 'h': - if (sscanf(optarg, "%llu", &cpufreq) != 1) - error("Error parsing CPU frequency."); - if (myrank == 0) message("CPU frequency set to %llu.", cpufreq); - fflush(stdout); - break; - case 'm': - if (sscanf(optarg, "%lf", &h_max) != 1) error("Error parsing h_max."); - if (myrank == 0) message("maximum h set to %e.", h_max); - fflush(stdout); - break; - case 'o': - with_outputs = 0; - break; - case 'P': -/* Partition type is one of "g", "m", "w", or "v"; "g" can be - * followed by three numbers defining the grid. */ -#ifdef WITH_MPI - switch (optarg[0]) { - case 'g': - initial_partition.type = INITPART_GRID; - if (strlen(optarg) > 2) { - if (sscanf(optarg, "g %i %i %i", &initial_partition.grid[0], - &initial_partition.grid[1], - &initial_partition.grid[2]) != 3) - error("Error parsing grid."); - } - break; -#ifdef HAVE_METIS - case 'm': - initial_partition.type = INITPART_METIS_NOWEIGHT; - break; - case 'w': - initial_partition.type = INITPART_METIS_WEIGHT; - break; -#endif - case 'v': - initial_partition.type = INITPART_VECTORIZE; - break; - } -#endif - break; - case 'q': - if (sscanf(optarg, "%d", &nr_queues) != 1) - error("Error parsing number of queues."); - break; - case 'R': -/* Repartition type "n", "b", "v", "e" or "x". - * Note only none is available without METIS. */ -#ifdef WITH_MPI - switch (optarg[0]) { - case 'n': - reparttype = REPART_NONE; - break; -#ifdef HAVE_METIS - case 'b': - reparttype = REPART_METIS_BOTH; - break; - case 'v': - reparttype = REPART_METIS_VERTEX; - break; - case 'e': - reparttype = REPART_METIS_EDGE; - break; - case 'x': - reparttype = REPART_METIS_VERTEX_EDGE; - break; -#endif - } -#endif - break; + if (myrank == 0) print_help_message(); + exit(0); case 's': - if (sscanf(optarg, "%lf %lf %lf", &shift[0], &shift[1], &shift[2]) != 3) - error("Error parsing shift."); - if (myrank == 0) - message("will shift parts by [ %.3f %.3f %.3f ].", shift[0], shift[1], - shift[2]); - break; - case 't': - if (sscanf(optarg, "%d", &nr_threads) != 1) - error("Error parsing number of threads."); + with_hydro = 1; break; case 'v': - /* verbose = 1: MPI rank 0 writes - verbose = 2: all MPI ranks write */ - if (sscanf(optarg, "%d", &verbose) != 1) - error("Error parsing verbosity level."); - break; - case 'w': - if (sscanf(optarg, "%d", &space_subsize) != 1) - error("Error parsing sub size."); - if (myrank == 0) message("sub size set to %i.", space_subsize); + if (sscanf(optarg, "%d", &verbose) != 1) { + if (myrank == 0) printf("Error parsing verbosity level (-v).\n"); + if (myrank == 0) print_help_message(); + exit(1); + } break; case 'y': - if (sscanf(optarg, "%d", &dump_tasks) != 1) - error("Error parsing dump_tasks (-y)"); - break; - case 'z': - if (sscanf(optarg, "%d", &space_splitsize) != 1) - error("Error parsing split size."); - if (myrank == 0) message("split size set to %i.", space_splitsize); + if (sscanf(optarg, "%d", &dump_tasks) != 1) { + if (myrank == 0) printf("Error parsing dump_tasks (-y). \n"); + if (myrank == 0) print_help_message(); + exit(1); + } break; case '?': - error("Unknown option."); + if (myrank == 0) print_help_message(); + exit(1); break; } + if (optind == argc - 1) { + if (!strcpy(paramFileName, argv[optind++])) + error("Error reading parameter file name."); + } else if (optind > argc - 1) { + if (myrank == 0) printf("Error: A parameter file name must be provided\n"); + if (myrank == 0) print_help_message(); + exit(1); + } else { + if (myrank == 0) printf("Error: Too many parameters given\n"); + if (myrank == 0) print_help_message(); + exit(1); + } -/* Some initial information about domain decomposition */ -#ifdef WITH_MPI - if (myrank == 0) { - message("Running with %i thread(s) per node.", nr_threads); - message("Using initial partition %s", - initial_partition_name[initial_partition.type]); - if (initial_partition.type == INITPART_GRID) - message("grid set to [ %i %i %i ].", initial_partition.grid[0], - initial_partition.grid[1], initial_partition.grid[2]); - message("Using %s repartitioning", repartition_name[reparttype]); + /* And then, there was time ! */ + clocks_set_cpufreq(cpufreq); - if (nr_nodes == 1) { - message("WARNING: you are running with one MPI rank."); - message("WARNING: you should use the non-MPI version of this program."); - } - fflush(stdout); + /* Report CPU frequency. */ + if (myrank == 0) { + cpufreq = clocks_get_cpufreq(); + message("CPU frequency used for tick conversion: %llu Hz", cpufreq); } -#else - if (myrank == 0) message("Running with %i thread(s).", nr_threads); -#endif /* How large are the parts? */ if (myrank == 0) { @@ -316,8 +227,17 @@ int main(int argc, char *argv[]) { message("sizeof(struct gpart) is %zi bytes.", sizeof(struct gpart)); } + /* Read the parameter file */ + struct swift_params params; + message("Reading parameter file '%s'", paramFileName); + parser_read_file(paramFileName, ¶ms); + // parser_print_params(¶ms); + + parser_write_params_to_file(¶ms, "used_parameters.yml"); + /* Initialize unit system */ - initUnitSystem(&us); + struct UnitSystem us; + initUnitSystem(&us, ¶ms); if (myrank == 0) { message("Unit system: U_M = %e g.", us.UnitMass_in_cgs); message("Unit system: U_L = %e cm.", us.UnitLength_in_cgs); @@ -332,17 +252,32 @@ int main(int argc, char *argv[]) { aFactor(&us, UNIT_CONV_ENTROPY), hFactor(&us, UNIT_CONV_ENTROPY)); } - /* Report CPU frequency. */ +/* Some initial information about domain decomposition */ +#ifdef WITH_MPI if (myrank == 0) { - cpufreq = clocks_get_cpufreq(); - message("CPU frequency used for tick conversion: %llu Hz", cpufreq); + message("Running with %i thread(s) per node.", nr_threads); + message("Using initial partition %s", + initial_partition_name[initial_partition.type]); + if (initial_partition.type == INITPART_GRID) + message("grid set to [ %i %i %i ].", initial_partition.grid[0], + initial_partition.grid[1], initial_partition.grid[2]); + message("Using %s repartitioning", repartition_name[reparttype]); + + if (nr_nodes == 1) { + message("WARNING: you are running with one MPI rank."); + message("WARNING: you should use the non-MPI version of this program."); + } + fflush(stdout); } +#else + if (myrank == 0) message("Running with %i thread(s).", nr_threads); +#endif - /* Check whether an IC file has been provided */ - if (strcmp(ICfileName, "") == 0) - error("An IC file name must be provided via the option -f"); + return 0; /* Read particles and space information from (GADGET) ICs */ + struct part *parts = NULL; + struct gpart *gparts = NULL; if (myrank == 0) clocks_gettime(&tic); #if defined(WITH_MPI) #if defined(HAVE_PARALLEL_HDF5) @@ -362,7 +297,8 @@ int main(int argc, char *argv[]) { fflush(stdout); } -/* Get the total number of particles across all nodes. */ + /* Get the total number of particles across all nodes. */ + long long N_total[2] = {0, 0}; #if defined(WITH_MPI) long long N_long[2] = {Ngas, Ngpart}; MPI_Reduce(&N_long, &N_total, 2, MPI_LONG_LONG, MPI_SUM, 0, MPI_COMM_WORLD); @@ -424,9 +360,10 @@ int main(int argc, char *argv[]) { if (nr_queues < 0) nr_queues = nr_threads; /* How vocal are we ? */ - talking = (verbose == 1 && myrank == 0) || (verbose == 2); + const int talking = (verbose == 1 && myrank == 0) || (verbose == 2); /* Initialize the space with this data. */ + struct space s; bzero(&s, sizeof(struct space)); if (myrank == 0) clocks_gettime(&tic); space_init(&s, dim, parts, gparts, Ngas, Ngpart, periodic, h_max, @@ -459,21 +396,23 @@ int main(int argc, char *argv[]) { /* Verify the maximal depth of cells. */ if (myrank == 0) { - data[0] = s.maxdepth; - data[1] = 0; + int data[2] = {s.maxdepth, 0}; space_map_cells_pre(&s, 0, &map_maxdepth, data); message("nr of cells at depth %i is %i.", data[0], data[1]); } /* Construct the engine policy */ - engine_policies = ENGINE_POLICY | engine_policy_steal; + int engine_policies = ENGINE_POLICY | engine_policy_steal; if (with_hydro) engine_policies |= engine_policy_hydro; - if (with_external_gravity) engine_policies |= engine_policy_external_gravity; if (with_self_gravity) engine_policies |= engine_policy_self_gravity; + if (with_external_gravity) engine_policies |= engine_policy_external_gravity; + if (with_cosmology) engine_policies |= engine_policy_cosmology; /* Initialize the engine with this space. */ if (myrank == 0) clocks_gettime(&tic); if (myrank == 0) message("nr_nodes is %i.", nr_nodes); + struct engine e; + bzero(&e, sizeof(struct engine)); engine_init(&e, &s, dt_max, nr_threads, nr_queues, nr_nodes, myrank, engine_policies, 0, time_end, dt_min, dt_max, talking); if (myrank == 0 && verbose) { @@ -579,7 +518,9 @@ int main(int argc, char *argv[]) { #ifdef WITH_MPI /* Make sure output file is empty, only on one rank. */ + char dumpfile[30]; sprintf(dumpfile, "thread_info_MPI-step%d.dat", j); + FILE *file_thread; if (myrank == 0) { file_thread = fopen(dumpfile, "w"); fclose(file_thread); @@ -624,7 +565,9 @@ int main(int argc, char *argv[]) { } #else + char dumpfile[30]; sprintf(dumpfile, "thread_info-step%d.dat", j); + FILE *file_thread; file_thread = fopen(dumpfile, "w"); for (int l = 0; l < e.sched.nr_tasks; l++) if (!e.sched.tasks[l].skip && !e.sched.tasks[l].implicit)