main.c 46.9 KB
Newer Older
1
/*******************************************************************************
2
 * This file is part of SWIFT.
3
 * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
4
 *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
5
 *               2015 Peter W. Draper (p.w.draper@durham.ac.uk)
6
7
8
 *                    Angus Lepper (angus.lepper@ed.ac.uk)
 *               2016 John A. Regan (john.a.regan@durham.ac.uk)
 *                    Tom Theuns (tom.theuns@durham.ac.uk)
9
 *
10
11
12
13
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
14
 *
15
16
17
18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20
21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 *
23
24
 ******************************************************************************/

Pedro Gonnet's avatar
Pedro Gonnet committed
25
26
/* Config parameters. */
#include "../config.h"
Pedro Gonnet's avatar
Pedro Gonnet committed
27
28

/* Some standard headers. */
29
#include <errno.h>
30
#include <fenv.h>
31
#include <libgen.h>
Pedro Gonnet's avatar
Pedro Gonnet committed
32
33
34
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
35
#include <sys/stat.h>
36
#include <unistd.h>
Pedro Gonnet's avatar
Pedro Gonnet committed
37

38
39
/* MPI headers. */
#ifdef WITH_MPI
40
#include <mpi.h>
41
42
#endif

Pedro Gonnet's avatar
Pedro Gonnet committed
43
/* Local headers. */
44
#include "argparse.h"
45
#include "swift.h"
Pedro Gonnet's avatar
Pedro Gonnet committed
46

47
48
/* Engine policy flags. */
#ifndef ENGINE_POLICY
49
#define ENGINE_POLICY engine_policy_none
50
51
#endif

James Willis's avatar
James Willis committed
52
53
54
/* Global profiler. */
struct profiler prof;

55
/*  Usage string. */
56
static const char *const swift_usage[] = {
Peter W. Draper's avatar
Peter W. Draper committed
57
58
59
60
61
    "swift [options] [[--] param-file]",
    "swift [options] param-file",
    "swift_mpi [options] [[--] param-file]",
    "swift_mpi [options] param-file",
    NULL,
62
63
};

64
/* Function to handle multiple -P arguments. */
65
66
67
68
69
70
71
72
73
74
75
struct cmdparams {
  const char *param[PARSER_MAX_NO_OF_PARAMS];
  int nparam;
};

static int handle_cmdparam(struct argparse *self,
                           const struct argparse_option *opt) {
  struct cmdparams *cmdps = (struct cmdparams *)opt->data;
  cmdps->param[cmdps->nparam] = *(char **)opt->value;
  cmdps->nparam++;
  return 1;
76
77
}

Pedro Gonnet's avatar
Pedro Gonnet committed
78
79
80
81
/**
 * @brief Main routine that loads a few particles and generates some output.
 *
 */
82
83
int main(int argc, char *argv[]) {

84
  struct clocks_time tic, toc;
85
  struct engine e;
86

87
88
  /* Structs used by the engine. Declare now to make sure these are always in
   * scope.  */
lhausamm's avatar
lhausamm committed
89
  struct chemistry_global_data chemistry;
90
  struct cooling_function_data cooling_func;
91
  struct cosmology cosmo;
92
  struct external_potential potential;
93
  struct star_formation starform;
94
  struct pm_mesh mesh;
95
96
97
  struct gpart *gparts = NULL;
  struct gravity_props gravity_properties;
  struct hydro_props hydro_properties;
Loic Hausammann's avatar
Loic Hausammann committed
98
  struct stars_props stars_properties;
99
  struct feedback_props feedback_properties;
100
  struct entropy_floor_properties entropy_floor;
101
  struct black_holes_props black_holes_properties;
102
  struct fof_props fof_properties;
103
104
105
106
  struct part *parts = NULL;
  struct phys_const prog_const;
  struct space s;
  struct spart *sparts = NULL;
107
  struct bpart *bparts = NULL;
108
  struct unit_system us;
109

110
  int nr_nodes = 1, myrank = 0;
111

112
#ifdef WITH_MPI
113
  /* Start by initializing MPI. */
114
  int res = 0, prov = 0;
115
116
  if ((res = MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &prov)) !=
      MPI_SUCCESS)
117
118
    error("Call to MPI_Init failed with error %i.", res);
  if (prov != MPI_THREAD_MULTIPLE)
119
    error(
120
121
        "MPI does not provide the level of threading"
        " required (MPI_THREAD_MULTIPLE).");
122
  if ((res = MPI_Comm_size(MPI_COMM_WORLD, &nr_nodes)) != MPI_SUCCESS)
123
124
125
    error("MPI_Comm_size failed with error %i.", res);
  if ((res = MPI_Comm_rank(MPI_COMM_WORLD, &myrank)) != MPI_SUCCESS)
    error("Call to MPI_Comm_rank failed with error %i.", res);
126

127
  /* Make sure messages are stamped with the correct rank and step. */
128
  engine_rank = myrank;
129
  engine_current_step = 0;
130

131
132
133
  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);
134
135
  if (myrank == 0)
    printf("[0000] [00000.0] main: MPI is up and running with %i node(s).\n\n",
Peter W. Draper's avatar
Peter W. Draper committed
136
           nr_nodes);
137
138
139
140
  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.");
  }
141
  fflush(stdout);
142

143
#endif
144

145
  /* Welcome to SWIFT, you made the right choice */
146
  if (myrank == 0) greetings(/*fof=*/0);
147

148
  int with_aff = 0;
149
  int dry_run = 0;
150
  int dump_tasks = 0;
151
  int dump_threadpool = 0;
152
  int nsteps = -2;
153
  int restart = 0;
154
155
  int with_cosmology = 0;
  int with_external_gravity = 0;
156
  int with_temperature = 0;
157
  int with_cooling = 0;
158
159
  int with_self_gravity = 0;
  int with_hydro = 0;
160
  int with_stars = 0;
161
  int with_fof = 0;
162
  int with_star_formation = 0;
Loic Hausammann's avatar
Loic Hausammann committed
163
  int with_feedback = 0;
164
  int with_black_holes = 0;
165
  int with_limiter = 0;
166
  int with_fp_exceptions = 0;
167
  int with_drift_all = 0;
168
  int with_mpole_reconstruction = 0;
169
  int with_structure_finding = 0;
170
  int verbose = 0;
171
  int nr_threads = 1;
172
  int with_verbose_timers = 0;
173
  char *output_parameters_filename = NULL;
174
  char *cpufreqarg = NULL;
175
  char *param_filename = NULL;
176
  char restart_file[200] = "";
177
  unsigned long long cpufreq = 0;
178
179
180
181
  struct cmdparams cmdps;
  cmdps.nparam = 0;
  cmdps.param[0] = NULL;
  char *buffer = NULL;
182

183
184
185
  /* Parse the command-line parameters. */
  struct argparse_option options[] = {
      OPT_HELP(),
186

187
188
      OPT_GROUP("  Simulation options:\n"),
      OPT_BOOLEAN('b', "feedback", &with_feedback, "Run with stars feedback.",
189
190
191
                  NULL, 0, 0),
      OPT_BOOLEAN('c', "cosmology", &with_cosmology,
                  "Run with cosmological time integration.", NULL, 0, 0),
192
193
194
      OPT_BOOLEAN(0, "temperature", &with_temperature,
                  "Run with temperature calculation.", NULL, 0, 0),
      OPT_BOOLEAN('C', "cooling", &with_cooling,
195
196
                  "Run with cooling (also switches on --temperature).", NULL, 0,
                  0),
197
198
199
200
201
      OPT_BOOLEAN('D', "drift-all", &with_drift_all,
                  "Always drift all particles even the ones far from active "
                  "particles. This emulates Gadget-[23] and GIZMO's default "
                  "behaviours.",
                  NULL, 0, 0),
202
      OPT_BOOLEAN('F', "star-formation", &with_star_formation,
203
                  "Run with star formation.", NULL, 0, 0),
204
205
206
207
208
209
      OPT_BOOLEAN('g', "external-gravity", &with_external_gravity,
                  "Run with an external gravitational potential.", NULL, 0, 0),
      OPT_BOOLEAN('G', "self-gravity", &with_self_gravity,
                  "Run with self-gravity.", NULL, 0, 0),
      OPT_BOOLEAN('M', "multipole-reconstruction", &with_mpole_reconstruction,
                  "Reconstruct the multipoles every time-step.", NULL, 0, 0),
210
211
      OPT_BOOLEAN('s', "hydro", &with_hydro, "Run with hydrodynamics.", NULL, 0,
                  0),
212
      OPT_BOOLEAN('S', "stars", &with_stars, "Run with stars.", NULL, 0, 0),
213
214
      OPT_BOOLEAN('B', "black-holes", &with_black_holes,
                  "Run with black holes.", NULL, 0, 0),
215
216
217
218
      OPT_BOOLEAN(
          'u', "fof", &with_fof,
          "Run Friends-of-Friends algorithm to perform black hole seeding.",
          NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
219
      OPT_BOOLEAN('x', "velociraptor", &with_structure_finding,
220
                  "Run with structure finding.", NULL, 0, 0),
221
222
      OPT_BOOLEAN(0, "limiter", &with_limiter, "Run with time-step limiter.",
                  NULL, 0, 0),
223

224
      OPT_GROUP("  Control options:\n"),
225
      OPT_BOOLEAN('a', "pin", &with_aff,
226
                  "Pin runners using processor affinity.", NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
227
228
229
230
231
      OPT_BOOLEAN('d', "dry-run", &dry_run,
                  "Dry run. Read the parameter file, allocates memory but does "
                  "not read the particles from ICs. Exits before the start of "
                  "time integration. Checks the validity of parameters and IC "
                  "files as well as memory limits.",
232
                  NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
233
234
235
236
237
238
239
240
      OPT_BOOLEAN('e', "fpe", &with_fp_exceptions,
                  "Enable floating-point exceptions (debugging mode).", NULL, 0,
                  0),
      OPT_STRING('f', "cpu-frequency", &cpufreqarg,
                 "Overwrite the CPU "
                 "frequency (Hz) to be used for time measurements.",
                 NULL, 0, 0),
      OPT_INTEGER('n', "steps", &nsteps,
241
242
                  "Execute a fixed number of time steps. When unset use the "
                  "time_end parameter to stop.",
243
                  NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
244
      OPT_STRING('o', "output-params", &output_parameters_filename,
245
246
247
                 "Generate a parameter file with the options for selecting the "
                 "output fields.",
                 NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
248
      OPT_STRING('P', "param", &buffer,
249
250
                 "Set parameter value, overiding the value read from the "
                 "parameter file. Can be used more than once {sec:par:value}.",
251
252
253
                 handle_cmdparam, (intptr_t)&cmdps, 0),
      OPT_BOOLEAN('r', "restart", &restart, "Continue using restart files.",
                  NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
254
      OPT_INTEGER('t', "threads", &nr_threads,
255
256
                  "The number of threads to use on each MPI rank. Defaults to "
                  "1 if not specified.",
257
258
                  NULL, 0, 0),
      OPT_INTEGER('T', "timers", &with_verbose_timers,
Peter W. Draper's avatar
Peter W. Draper committed
259
260
261
                  "Print timers every time-step.", NULL, 0, 0),
      OPT_INTEGER('v', "verbose", &verbose,
                  "Run in verbose mode, in MPI mode 2 outputs from all ranks.",
262
                  NULL, 0, 0),
Peter W. Draper's avatar
Peter W. Draper committed
263
264
265
266
      OPT_INTEGER('y', "task-dumps", &dump_tasks,
                  "Time-step frequency at which task graphs are dumped.", NULL,
                  0, 0),
      OPT_INTEGER('Y', "threadpool-dumps", &dump_threadpool,
267
268
                  "Time-step frequency at which threadpool tasks are dumped.",
                  NULL, 0, 0),
269
      OPT_END(),
270
271
  };
  struct argparse argparse;
272
  argparse_init(&argparse, options, swift_usage, 0);
Peter W. Draper's avatar
Peter W. Draper committed
273
274
275
  argparse_describe(&argparse, "\nParameters:",
                    "\nSee the file examples/parameter_example.yml for an "
                    "example of parameter file.");
276
277
  int nargs = argparse_parse(&argparse, argc, (const char **)argv);

278
279
280
281
282
283
284
  /* Write output parameter file */
  if (myrank == 0 && output_parameters_filename != NULL) {
    io_write_output_field_parameter(output_parameters_filename);
    printf("End of run.\n");
    return 0;
  }

285
286
  /* Need a parameter file. */
  if (nargs != 1) {
Peter W. Draper's avatar
Peter W. Draper committed
287
288
289
    if (myrank == 0) argparse_usage(&argparse);
    printf("\nError: no parameter file was supplied.\n");
    return 1;
290
291
  }
  param_filename = argv[0];
292

293
  /* Checks of options. */
Peter W. Draper's avatar
Peter W. Draper committed
294
#if !defined(HAVE_SETAFFINITY) || !defined(HAVE_LIBNUMA)
295
  if (with_aff) {
Peter W. Draper's avatar
Peter W. Draper committed
296
297
    printf("Error: no NUMA support for thread affinity\n");
    return 1;
298
  }
299
#endif
300
301

#ifndef HAVE_FE_ENABLE_EXCEPT
302
  if (with_fp_exceptions) {
Peter W. Draper's avatar
Peter W. Draper committed
303
304
    printf("Error: no support for floating point exceptions\n");
    return 1;
305
  }
306
#endif
307
308

#ifndef HAVE_VELOCIRAPTOR
309
  if (with_structure_finding) {
Peter W. Draper's avatar
Peter W. Draper committed
310
311
    printf("Error: VELOCIraptor is not available\n");
    return 1;
312
  }
313
#endif
314

315
#ifndef SWIFT_DEBUG_TASKS
316
  if (dump_tasks) {
317
    if (myrank == 0) {
Peter W. Draper's avatar
Peter W. Draper committed
318
319
320
      message(
          "WARNING: complete task dumps are only created when "
          "configured with --enable-task-debugging.");
321
322
      message("         Basic task statistics will be output.");
    }
323
  }
324
#endif
325

326
#ifndef SWIFT_DEBUG_THREADPOOL
327
  if (dump_threadpool) {
Peter W. Draper's avatar
Peter W. Draper committed
328
329
330
331
    printf(
        "Error: threadpool dumping is only possible if SWIFT was "
        "configured with the --enable-threadpool-debugging option.\n");
    return 1;
332
  }
333
#endif
334

335
336
337
  /* The CPU frequency is a long long, so we need to parse that ourselves. */
  if (cpufreqarg != NULL) {
    if (sscanf(cpufreqarg, "%llu", &cpufreq) != 1) {
Peter W. Draper's avatar
Peter W. Draper committed
338
339
      if (myrank == 0)
        printf("Error parsing CPU frequency (%s).\n", cpufreqarg);
340
      return 1;
341
    }
342
  }
343

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
344
  if (!with_self_gravity && !with_hydro && !with_external_gravity) {
Peter W. Draper's avatar
Peter W. Draper committed
345
346
347
348
    if (myrank == 0) {
      argparse_usage(&argparse);
      printf("\nError: At least one of -s, -g or -G must be chosen.\n");
    }
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
349
350
    return 1;
  }
351
  if (with_stars && !with_external_gravity && !with_self_gravity) {
Peter W. Draper's avatar
Peter W. Draper committed
352
353
    if (myrank == 0) {
      argparse_usage(&argparse);
354
      printf(
Peter W. Draper's avatar
Peter W. Draper committed
355
356
357
          "\nError: Cannot process stars without gravity, -g or -G "
          "must be chosen.\n");
    }
358
359
    return 1;
  }
360

361
  if (with_black_holes && !with_self_gravity) {
362
363
364
    if (myrank == 0) {
      argparse_usage(&argparse);
      printf(
365
366
          "\nError: Cannot process black holes without self-gravity, -G must "
          "be chosen.\n");
367
368
369
370
    }
    return 1;
  }

371
372
373
374
375
376
  if (with_fof) {
#ifndef WITH_FOF
    error("Running with FOF but compiled without it!");
#endif
  }

377
  if (with_fof && !with_self_gravity) {
378
379
380
381
382
383
    if (myrank == 0)
      printf(
          "Error: Cannot perform FOF search without gravity, -g or -G must be "
          "chosen.\n");
    return 1;
  }
384

385
386
387
388
389
390
391
392
  if (with_fof && !with_black_holes) {
    if (myrank == 0)
      printf(
          "Error: Cannot perform FOF seeding without black holes being in use, "
          "-B must be chosen.\n");
    return 1;
  }

393
394
395
396
397
398
399
400
401
402
  if (!with_stars && with_star_formation) {
    if (myrank == 0) {
      argparse_usage(&argparse);
      printf(
          "\nError: Cannot process star formation without stars, --stars must "
          "be chosen.\n");
    }
    return 1;
  }

Loic Hausammann's avatar
Loic Hausammann committed
403
  if (!with_stars && with_feedback) {
Peter W. Draper's avatar
Peter W. Draper committed
404
405
    if (myrank == 0) {
      argparse_usage(&argparse);
Loic Hausammann's avatar
Loic Hausammann committed
406
      printf(
407
408
409
410
411
412
413
414
415
416
417
          "\nError: Cannot process feedback without stars, --stars must be "
          "chosen.\n");
    }
    return 1;
  }

  if (!with_hydro && with_feedback) {
    if (myrank == 0) {
      argparse_usage(&argparse);
      printf(
          "\nError: Cannot process feedback without gas, --hydro must be "
Loic Hausammann's avatar
Loic Hausammann committed
418
          "chosen.\n");
Peter W. Draper's avatar
Peter W. Draper committed
419
    }
Loic Hausammann's avatar
Loic Hausammann committed
420
421
422
    return 1;
  }

423
424
425
426
427
428
429
430
431
432
  if (!with_hydro && with_black_holes) {
    if (myrank == 0) {
      argparse_usage(&argparse);
      printf(
          "\nError: Cannot process black holes without gas, --hydro must be "
          "chosen.\n");
    }
    return 1;
  }

433
434
/* Let's pin the main thread, now we know if affinity will be used. */
#if defined(HAVE_SETAFFINITY) && defined(HAVE_LIBNUMA) && defined(_GNU_SOURCE)
435
436
  if (with_aff &&
      ((ENGINE_POLICY)&engine_policy_setaffinity) == engine_policy_setaffinity)
437
438
439
    engine_pin();
#endif

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
440
441
  /* Genesis 1.1: And then, there was time ! */
  clocks_set_cpufreq(cpufreq);
442

443
444
445
  /* How vocal are we ? */
  const int talking = (verbose == 1 && myrank == 0) || (verbose == 2);

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
446
447
448
  if (myrank == 0 && dry_run)
    message(
        "Executing a dry run. No i/o or time integration will be performed.");
449

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
450
451
452
453
454
  /* Report CPU frequency.*/
  cpufreq = clocks_get_cpufreq();
  if (myrank == 0) {
    message("CPU frequency used for tick conversion: %llu Hz", cpufreq);
  }
455

Matthieu Schaller's avatar
Matthieu Schaller committed
456
/* Report host name(s). */
457
#ifdef WITH_MPI
458
  if (talking) {
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
459
460
    message("Rank %d running on: %s", myrank, hostname());
  }
461
#else
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
462
  message("Running on: %s", hostname());
463
464
#endif

465
466
/* Do we have debugging checks ? */
#ifdef SWIFT_DEBUG_CHECKS
467
468
  if (myrank == 0)
    message("WARNING: Debugging checks activated. Code will be slower !");
469
470
#endif

471
472
473
474
475
476
477
/* Do we have debugging checks ? */
#ifdef SWIFT_USE_NAIVE_INTERACTIONS
  if (myrank == 0)
    message(
        "WARNING: Naive cell interactions activated. Code will be slower !");
#endif

478
479
480
481
482
483
484
485
486
/* Do we have gravity accuracy checks ? */
#ifdef SWIFT_GRAVITY_FORCE_CHECKS
  if (myrank == 0)
    message(
        "WARNING: Checking 1/%d of all gpart for gravity accuracy. Code will "
        "be slower !",
        SWIFT_GRAVITY_FORCE_CHECKS);
#endif

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
487
488
  /* Do we choke on FP-exceptions ? */
  if (with_fp_exceptions) {
489
#ifdef HAVE_FE_ENABLE_EXCEPT
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
490
    feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
491
#endif
492
493
    if (myrank == 0)
      message("WARNING: Floating point exceptions will be reported.");
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
494
  }
495

496
/* Do we have slow barriers? */
497
#ifndef HAVE_PTHREAD_BARRIERS
498
  if (myrank == 0)
499
    message("WARNING: Non-optimal thread barriers are being used.");
500
501
#endif

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
502
503
  /* How large are the parts? */
  if (myrank == 0) {
504
505
506
    message("sizeof(part)        is %4zi bytes.", sizeof(struct part));
    message("sizeof(xpart)       is %4zi bytes.", sizeof(struct xpart));
    message("sizeof(spart)       is %4zi bytes.", sizeof(struct spart));
507
    message("sizeof(bpart)       is %4zi bytes.", sizeof(struct bpart));
508
509
510
511
512
    message("sizeof(gpart)       is %4zi bytes.", sizeof(struct gpart));
    message("sizeof(multipole)   is %4zi bytes.", sizeof(struct multipole));
    message("sizeof(grav_tensor) is %4zi bytes.", sizeof(struct grav_tensor));
    message("sizeof(task)        is %4zi bytes.", sizeof(struct task));
    message("sizeof(cell)        is %4zi bytes.", sizeof(struct cell));
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
513
  }
514

Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
515
  /* Read the parameter file */
Matthieu Schaller's avatar
Matthieu Schaller committed
516
517
  struct swift_params *params =
      (struct swift_params *)malloc(sizeof(struct swift_params));
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
518
519
  if (params == NULL) error("Error allocating memory for the parameter file.");
  if (myrank == 0) {
520
521
    message("Reading runtime parameters from file '%s'", param_filename);
    parser_read_file(param_filename, params);
522
523

    /* Handle any command-line overrides. */
524
    if (cmdps.nparam > 0) {
525
526
527
      message(
          "Overwriting values read from the YAML file with command-line "
          "values.");
Peter W. Draper's avatar
Peter W. Draper committed
528
529
      for (int k = 0; k < cmdps.nparam; k++)
        parser_set_param(params, cmdps.param[k]);
530
    }
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
531
  }
532
#ifdef WITH_MPI
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
533
534
  /* Broadcast the parameter file */
  MPI_Bcast(params, sizeof(struct swift_params), MPI_BYTE, 0, MPI_COMM_WORLD);
535
#endif
536

537
538
  /* Temporary early aborts for modes not supported over MPI. */
#ifdef WITH_MPI
Matthieu Schaller's avatar
Matthieu Schaller committed
539
540
  if (with_mpole_reconstruction && nr_nodes > 1)
    error("Cannot reconstruct m-poles every step over MPI (yet).");
541
  if (with_limiter) error("Can't run with time-step limiter over MPI (yet)");
542
543
#endif

544
    /* Temporary early aborts for modes not supported with hand-vec. */
545
546
#if defined(WITH_VECTORIZATION) && defined(GADGET2_SPH) && \
    !defined(CHEMISTRY_NONE)
547
548
549
  error(
      "Cannot run with chemistry and hand-vectorization (yet). "
      "Use --disable-hand-vec at configure time.");
550
551
#endif

552
  /* Check that we can write the snapshots by testing if the output
553
   * directory exists and is searchable and writable. */
554
555
556
  char basename[PARSER_MAX_LINE_SIZE];
  parser_get_param_string(params, "Snapshots:basename", basename);
  const char *dirp = dirname(basename);
557
558
  if (access(dirp, W_OK | X_OK) != 0) {
    error("Cannot write snapshots in directory %s (%s)", dirp, strerror(errno));
559
560
  }

Matthieu Schaller's avatar
Matthieu Schaller committed
561
  /* Check that we can write the structure finding catalogues by testing if the
562
   * output directory exists and is searchable and writable. */
Matthieu Schaller's avatar
Matthieu Schaller committed
563
  if (with_structure_finding) {
564
    char stfbasename[PARSER_MAX_LINE_SIZE];
565
    parser_get_param_string(params, "StructureFinding:basename", stfbasename);
566
567
    const char *stfdirp = dirname(stfbasename);
    if (access(stfdirp, W_OK | X_OK) != 0) {
Matthieu Schaller's avatar
Matthieu Schaller committed
568
569
      error("Cannot write stf catalogues in directory %s (%s)", stfdirp,
            strerror(errno));
570
571
    }
  }
572

573
  /* Prepare the domain decomposition scheme */
574
  struct repartition reparttype;
575
#ifdef WITH_MPI
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
576
577
578
579
580
  struct partition initial_partition;
  partition_init(&initial_partition, &reparttype, params, nr_nodes);

  /* Let's report what we did */
  if (myrank == 0) {
581
582
#if defined(HAVE_PARMETIS)
    if (reparttype.usemetis)
Matthieu Schaller's avatar
Matthieu Schaller committed
583
      message("Using METIS serial partitioning:");
584
    else
Matthieu Schaller's avatar
Matthieu Schaller committed
585
      message("Using ParMETIS partitioning:");
586
#elif defined(HAVE_METIS)
587
    message("Using METIS serial partitioning:");
588
589
#else
    message("Non-METIS partitioning:");
590
591
#endif
    message("  initial partitioning: %s",
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
592
593
            initial_partition_name[initial_partition.type]);
    if (initial_partition.type == INITPART_GRID)
594
      message("    grid set to [ %i %i %i ].", initial_partition.grid[0],
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
595
              initial_partition.grid[1], initial_partition.grid[2]);
596
    message("  repartitioning: %s", repartition_name[reparttype.type]);
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
597
  }
598
#endif
599

600
  /* Common variables for restart and IC sections. */
601
  int clean_smoothing_length_values = 0;
602
603
604
  int flag_entropy_ICs = 0;

  /* Work out where we will read and write restart files. */
605
  char restart_dir[PARSER_MAX_LINE_SIZE];
Peter W. Draper's avatar
Peter W. Draper committed
606
607
  parser_get_opt_param_string(params, "Restarts:subdir", restart_dir,
                              "restart");
608
609

  /* The directory must exist. */
610
  if (myrank == 0) {
611
    if (access(restart_dir, W_OK | X_OK) != 0) {
612
      if (restart) {
613
        error("Cannot restart as no restart subdirectory: %s (%s)", restart_dir,
614
              strerror(errno));
615
      } else {
Peter W. Draper's avatar
Peter W. Draper committed
616
617
618
        if (mkdir(restart_dir, 0777) != 0)
          error("Failed to create restart directory: %s (%s)", restart_dir,
                strerror(errno));
619
      }
620
    }
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
621
622
  }

623
  /* Basename for any restart files. */
624
625
  char restart_name[PARSER_MAX_LINE_SIZE];
  parser_get_opt_param_string(params, "Restarts:basename", restart_name,
626
                              "swift");
627

628
629
  /* How often to check for the stop file and dump restarts and exit the
   * application. */
630
  const int restart_stop_steps =
Peter W. Draper's avatar
Peter W. Draper committed
631
      parser_get_opt_param_int(params, "Restarts:stop_steps", 100);
632

633
634
635
636
637
638
639
640
641
642
643
  /* Get the maximal wall-clock time of this run */
  const float restart_max_hours_runtime =
      parser_get_opt_param_float(params, "Restarts:max_run_time", FLT_MAX);

  /* Do we want to resubmit when we hit the limit? */
  const int resubmit_after_max_hours =
      parser_get_opt_param_int(params, "Restarts:resubmit_on_exit", 0);

  /* What command should we run to resubmit at the end? */
  char resubmit_command[PARSER_MAX_LINE_SIZE];
  if (resubmit_after_max_hours)
644
645
    parser_get_param_string(params, "Restarts:resubmit_command",
                            resubmit_command);
646

647
  /* If restarting, look for the restart files. */
648
  if (restart) {
649

650
    /* Attempting a restart. */
651
652
    char **restart_files = NULL;
    int restart_nfiles = 0;
653
654

    if (myrank == 0) {
655
      message("Restarting SWIFT");
656

657
      /* Locate the restart files. */
Peter W. Draper's avatar
Peter W. Draper committed
658
659
      restart_files =
          restart_locate(restart_dir, restart_name, &restart_nfiles);
660
661
      if (restart_nfiles == 0)
        error("Failed to locate any restart files in %s", restart_dir);
662
663

      /* We need one file per rank. */
664
      if (restart_nfiles != nr_nodes)
665
        error("Incorrect number of restart files, expected %d found %d",
666
              nr_nodes, restart_nfiles);
667
668

      if (verbose > 0)
669
670
        for (int i = 0; i < restart_nfiles; i++)
          message("found restart file: %s", restart_files[i]);
671
672
673
    }

#ifdef WITH_MPI
674
    /* Distribute the restart files, need one for each rank. */
675
676
677
    if (myrank == 0) {

      for (int i = 1; i < nr_nodes; i++) {
678
679
        strcpy(restart_file, restart_files[i]);
        MPI_Send(restart_file, 200, MPI_BYTE, i, 0, MPI_COMM_WORLD);
680
681
682
      }

      /* Keep local file. */
683
      strcpy(restart_file, restart_files[0]);
684
685

      /* Finished with the list. */
686
      restart_locate_free(restart_nfiles, restart_files);
687
688

    } else {
689
      MPI_Recv(restart_file, 200, MPI_BYTE, 0, 0, MPI_COMM_WORLD,
690
691
               MPI_STATUS_IGNORE);
    }
692
    if (verbose > 1) message("local restart file = %s", restart_file);
693
#else
694

695
    /* Just one restart file. */
696
    strcpy(restart_file, restart_files[0]);
697
698
#endif

699
    /* Now read it. */
700
    restart_read(&e, restart_file);
701
702
703

    /* And initialize the engine with the space and policies. */
    if (myrank == 0) clocks_gettime(&tic);
704
705
    engine_config(/*restart=*/1, /*fof=*/0, &e, params, nr_nodes, myrank,
                  nr_threads, with_aff, talking, restart_file);
706
707
    if (myrank == 0) {
      clocks_gettime(&toc);
708
      message("engine_config took %.3f %s.", clocks_diff(&tic, &toc),
709
710
711
712
              clocks_getunit());
      fflush(stdout);
    }

713
714
    /* Check if we are already done when given steps on the command-line. */
    if (e.step >= nsteps && nsteps > 0)
715
      error("Not restarting, already completed %d steps", e.step);
716

717
  } else {
718

719
    /* Not restarting so look for the ICs. */
720
    /* Initialize unit system and constants */
721
    units_init_from_params(&us, params, "InternalUnitSystem");
722
    phys_const_init(&us, params, &prog_const);
723
    if (myrank == 0) {
724
725
726
727
728
729
730
      message("Internal unit system: U_M = %e g.", us.UnitMass_in_cgs);
      message("Internal unit system: U_L = %e cm.", us.UnitLength_in_cgs);
      message("Internal unit system: U_t = %e s.", us.UnitTime_in_cgs);
      message("Internal unit system: U_I = %e A.", us.UnitCurrent_in_cgs);
      message("Internal unit system: U_T = %e K.", us.UnitTemperature_in_cgs);
      phys_const_print(&prog_const);
    }
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
731

732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
    /* Read particles and space information from ICs */
    char ICfileName[200] = "";
    parser_get_param_string(params, "InitialConditions:file_name", ICfileName);
    const int periodic =
        parser_get_param_int(params, "InitialConditions:periodic");
    const int replicate =
        parser_get_opt_param_int(params, "InitialConditions:replicate", 1);
    clean_smoothing_length_values = parser_get_opt_param_int(
        params, "InitialConditions:cleanup_smoothing_lengths", 0);
    const int cleanup_h = parser_get_opt_param_int(
        params, "InitialConditions:cleanup_h_factors", 0);
    const int cleanup_sqrt_a = parser_get_opt_param_int(
        params, "InitialConditions:cleanup_velocity_factors", 0);
    const int generate_gas_in_ics = parser_get_opt_param_int(
        params, "InitialConditions:generate_gas_in_ics", 0);

    /* Some checks that we are not doing something stupid */
    if (generate_gas_in_ics && flag_entropy_ICs)
      error("Can't generate gas if the entropy flag is set in the ICs.");
    if (generate_gas_in_ics && !with_cosmology)
      error("Can't generate gas if the run is not cosmological.");

754
    /* Initialise the cosmology */
755
756
757
    if (with_cosmology)
      cosmology_init(params, &us, &prog_const, &cosmo);
    else
758
      cosmology_init_no_cosmo(&cosmo);
759
    if (myrank == 0 && with_cosmology) cosmology_print(&cosmo);
760

761
    /* Initialise the hydro properties */
762
763
    if (with_hydro)
      hydro_props_init(&hydro_properties, &prog_const, &us, params);
764
765
766
767
768
769
770
771
    else
      bzero(&hydro_properties, sizeof(struct hydro_props));

    /* Initialise the equation of state */
    if (with_hydro)
      eos_init(&eos, &prog_const, &us, params);
    else
      bzero(&eos, sizeof(struct eos_parameters));
772

773
774
775
776
777
778
779
    /* Initialise the entropy floor */
    if (with_hydro)
      entropy_floor_init(&entropy_floor, &prog_const, &us, &hydro_properties,
                         params);
    else
      bzero(&entropy_floor, sizeof(struct entropy_floor_properties));

Loic Hausammann's avatar
Loic Hausammann committed
780
781
    /* Initialise the stars properties */
    if (with_stars)
782
      stars_props_init(&stars_properties, &prog_const, &us, params,
783
                       &hydro_properties, &cosmo);
Loic Hausammann's avatar
Loic Hausammann committed
784
785
786
    else
      bzero(&stars_properties, sizeof(struct stars_props));

787
788
789
790
791
792
    /* Initialise the feedback properties */
    if (with_feedback) {
#ifdef FEEDBACK_NONE
      error("ERROR: Running with feedback but compiled without it.");
#endif
      feedback_props_init(&feedback_properties, &prog_const, &us, params,
793
794
                          &hydro_properties, &cosmo);
    } else
795
      bzero(&feedback_properties, sizeof(struct feedback_props));
796

797
798
799
800
801
802
803
804
805
806
    /* Initialise the black holes properties */
    if (with_black_holes) {
#ifdef BLACK_HOLES_NONE
      error("ERROR: Running with black_holes but compiled without it.");
#endif
      black_holes_props_init(&black_holes_properties, &prog_const, &us, params,
                             &hydro_properties, &cosmo);
    } else
      bzero(&black_holes_properties, sizeof(struct black_holes_props));

807
    /* Initialise the gravity properties */
808
    bzero(&gravity_properties, sizeof(struct gravity_props));
809
    if (with_self_gravity)
810
811
      gravity_props_init(&gravity_properties, params, &prog_const, &cosmo,
                         with_cosmology, periodic);
812

Peter W. Draper's avatar
Peter W. Draper committed
813
      /* Initialise the cooling function properties */
814
#ifdef COOLING_NONE
815
    if (with_cooling || with_temperature) {
Peter W. Draper's avatar
Peter W. Draper committed
816
817
818
      error(
          "ERROR: Running with cooling / temperature calculation"
          " but compiled without it.");
819
820
821
    }
#else
    if (!with_cooling && !with_temperature) {
Peter W. Draper's avatar
Peter W. Draper committed
822
823
824
      error(
          "ERROR: Compiled with cooling but running without it. "
          "Did you forget the --cooling or --temperature flags?");
825
    }
826
#endif
827
828
    bzero(&cooling_func, sizeof(struct cooling_function_data));
    if (with_cooling || with_temperature) {
829
      cooling_init(params, &us, &prog_const, &hydro_properties, &cooling_func);
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
    }
    if (myrank == 0) cooling_print(&cooling_func);

    /* Initialise the star formation law and its properties */
    bzero(&starform, sizeof(struct star_formation));
    if (with_star_formation) {
#ifdef STAR_FORMATION_NONE
      error("ERROR: Running with star formation but compiled without it!");
#endif
      starformation_init(params, &prog_const, &us, &hydro_properties,
                         &starform);
    }
    if (with_star_formation && myrank == 0) starformation_print(&starform);

    /* Initialise the chemistry */
    bzero(&chemistry, sizeof(struct chemistry_global_data));
    chemistry_init(params, &us, &prog_const, &chemistry);
    if (myrank == 0) chemistry_print(&chemistry);

849
850
    /* Initialise the FOF properties */
    bzero(&fof_properties, sizeof(struct fof_props));
851
#ifdef WITH_FOF
852
    if (with_fof) fof_init(&fof_properties, params, &prog_const, &us);
853
#endif
854

855
    /* Be verbose about what happens next */
856
    if (myrank == 0) message("Reading ICs from file '%s'", ICfileName);
857
858
    if (myrank == 0 && cleanup_h)
      message("Cleaning up h-factors (h=%f)", cosmo.h);
859
860
    if (myrank == 0 && cleanup_sqrt_a)
      message("Cleaning up a-factors from velocity (a=%f)", cosmo.a);
861
    fflush(stdout);
Pedro Gonnet's avatar
oops.    
Pedro Gonnet committed
862

863
    /* Get ready to read particles of all kinds */
864
    size_t Ngas = 0, Ngpart = 0, Ngpart_background = 0, Nspart = 0, Nbpart = 0;
865
866
    double dim[3] = {0., 0., 0.};
    if (myrank == 0) clocks_gettime(&tic);
867
#if defined(HAVE_HDF5)
868
869
#if defined(WITH_MPI)
#if defined(HAVE_PARALLEL_HDF5)