/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2017 Peter W. Draper (p.w.draper@durham.ac.uk)
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Config parameters. */
#include
/* MPI headers. */
#ifdef WITH_MPI
#include
#endif
/* This object's header. */
#include "collectgroup.h"
/* Local headers. */
#include "engine.h"
#include "error.h"
#include "star_formation_logger.h"
#ifdef WITH_MPI
/* Local collections for MPI reduces. */
struct mpicollectgroup1 {
long long updated, g_updated, s_updated, sink_updated, b_updated;
long long inhibited, g_inhibited, s_inhibited, sink_inhibited, b_inhibited;
integertime_t ti_hydro_end_min;
integertime_t ti_rt_end_min;
integertime_t ti_gravity_end_min;
integertime_t ti_stars_end_min;
integertime_t ti_sinks_end_min;
integertime_t ti_black_holes_end_min;
integertime_t ti_hydro_beg_max;
integertime_t ti_rt_beg_max;
integertime_t ti_gravity_beg_max;
integertime_t ti_stars_beg_max;
integertime_t ti_sinks_beg_max;
integertime_t ti_black_holes_beg_max;
int forcerebuild;
long long total_nr_cells;
long long total_nr_tasks;
float tasks_per_cell_max;
struct star_formation_history sfh;
float runtime;
int flush_lightcone_maps;
double deadtime;
#ifdef WITH_CSDS
float csds_file_size_gb;
#endif
};
/* Forward declarations. */
static void mpicollect_create_MPI_type(void);
/**
* @brief MPI datatype for the #mpicollectgroup1 structure.
*/
static MPI_Datatype mpicollectgroup1_type;
/**
* @brief MPI operator to reduce #mpicollectgroup1 structures.
*/
static MPI_Op mpicollectgroup1_reduce_op;
#endif
/**
* @brief Perform any once only initialisations. Must be called once.
*/
void collectgroup_init(void) {
#ifdef WITH_MPI
/* Initialise the MPI types. */
mpicollect_create_MPI_type();
#endif
}
/**
* @brief Apply the collectgroup1 values to the engine by copying all the
* values to the engine fields.
*
* @param grp1 The #collectgroup1
* @param e The #engine
*/
void collectgroup1_apply(const struct collectgroup1 *grp1, struct engine *e) {
e->ti_hydro_end_min = grp1->ti_hydro_end_min;
e->ti_hydro_beg_max = grp1->ti_hydro_beg_max;
e->ti_rt_end_min = grp1->ti_rt_end_min;
e->ti_rt_beg_max = grp1->ti_rt_beg_max;
e->ti_gravity_end_min = grp1->ti_gravity_end_min;
e->ti_gravity_beg_max = grp1->ti_gravity_beg_max;
e->ti_stars_end_min = grp1->ti_stars_end_min;
e->ti_stars_beg_max = grp1->ti_stars_beg_max;
e->ti_black_holes_end_min = grp1->ti_black_holes_end_min;
e->ti_black_holes_beg_max = grp1->ti_black_holes_beg_max;
e->ti_sinks_end_min = grp1->ti_sinks_end_min;
e->ti_sinks_beg_max = grp1->ti_sinks_beg_max;
e->ti_end_min =
min5(e->ti_hydro_end_min, e->ti_gravity_end_min, e->ti_sinks_end_min,
e->ti_stars_end_min, e->ti_black_holes_end_min);
e->ti_beg_max =
max5(e->ti_hydro_beg_max, e->ti_gravity_beg_max, e->ti_sinks_beg_max,
e->ti_stars_beg_max, e->ti_black_holes_beg_max);
e->updates = grp1->updated;
e->g_updates = grp1->g_updated;
e->s_updates = grp1->s_updated;
e->b_updates = grp1->b_updated;
e->sink_updates = grp1->sink_updated;
e->nr_inhibited_parts = grp1->inhibited;
e->nr_inhibited_gparts = grp1->g_inhibited;
e->nr_inhibited_sparts = grp1->s_inhibited;
e->nr_inhibited_bparts = grp1->b_inhibited;
e->nr_inhibited_sinks = grp1->sink_inhibited;
e->forcerebuild = grp1->forcerebuild;
e->total_nr_cells = grp1->total_nr_cells;
e->total_nr_tasks = grp1->total_nr_tasks;
e->tasks_per_cell_max = grp1->tasks_per_cell_max;
star_formation_logger_add_to_accumulator(&e->sfh, &grp1->sfh);
e->runtime = grp1->runtime;
e->flush_lightcone_maps = grp1->flush_lightcone_maps;
e->global_deadtime = grp1->deadtime;
}
/**
* @brief Initialises a collectgroup1 struct ready for processing.
*
* @param grp1 The #collectgroup1 to initialise
* @param updated the number of updated hydro particles on this node this step.
* @param g_updated the number of updated gravity particles on this node this
* step.
* @param s_updated the number of updated star particles on this node this step.
* @param sink_updated the number of updated sink particles on this node this
* step.
* @param b_updated the number of updated black hole particles on this node this
* step.
* @param inhibited the number of inhibited hydro particles on this node this
* step.
* @param g_inhibited the number of inhibited gravity particles on this node
* this step.
* @param s_inhibited the number of inhibited star particles on this node this
* step.
* @param sink_inhibited the number of inhibited sink particles on this node
* this step.
* @param b_inhibited the number of inhibited black hole particles on this node
* this step.
* @param ti_hydro_end_min the minimum end time for next hydro time step after
* this step.
* @param ti_hydro_end_max the maximum end time for next hydro time step after
* this step.
* @param ti_hydro_beg_max the maximum begin time for next hydro time step after
* this step.
* @param ti_gravity_end_min the minimum end time for next gravity time step
* after this step.
* @param ti_gravity_end_max the maximum end time for next gravity time step
* after this step.
* @param ti_gravity_beg_max the maximum begin time for next gravity time step
* after this step.
* @param ti_stars_end_min the minimum end time for next stars time step
* after this step.
* @param ti_stars_end_max the maximum end time for next stars time step
* after this step.
* @param ti_stars_beg_max the maximum begin time for next stars time step
* after this step.
* @param ti_sinks_end_min the minimum end time for next sinks time step
* after this step.
* @param ti_sinks_end_max the maximum end time for next sinks time step
* after this step.
* @param ti_sinks_beg_max the maximum begin time for next sinks time step
* after this step.
* @param ti_black_holes_end_min the minimum end time for next black holes time
* step after this step.
* @param ti_black_holes_end_max the maximum end time for next black holes time
* step after this step.
* @param ti_black_holes_beg_max the maximum begin time for next black holes
* time step after this step.
* @param forcerebuild whether a rebuild is required after this step.
* @param total_nr_cells total number of all cells on rank.
* @param total_nr_tasks total number of tasks on rank.
* @param tasks_per_cell the used number of tasks per cell.
* @param sfh The star formation history logger
* @param runtime The runtime of rank in hours.
* @param flush_lightcone_maps Flag whether lightcone maps should be updated
* @param deadtime The deadtime of rank.
* @param csds_file_size_gb The current size of the CSDS.
*/
void collectgroup1_init(
struct collectgroup1 *grp1, size_t updated, size_t g_updated,
size_t s_updated, size_t sink_updated, size_t b_updated, size_t inhibited,
size_t g_inhibited, size_t s_inhibited, size_t sink_inhibited,
size_t b_inhibited, integertime_t ti_hydro_end_min,
integertime_t ti_hydro_beg_max, integertime_t ti_rt_end_min,
integertime_t ti_rt_beg_max, integertime_t ti_gravity_end_min,
integertime_t ti_gravity_beg_max, integertime_t ti_stars_end_min,
integertime_t ti_stars_beg_max, integertime_t ti_sinks_end_min,
integertime_t ti_sinks_beg_max, integertime_t ti_black_holes_end_min,
integertime_t ti_black_holes_beg_max, int forcerebuild,
long long total_nr_cells, long long total_nr_tasks, float tasks_per_cell,
const struct star_formation_history sfh, float runtime,
int flush_lightcone_maps, double deadtime, float csds_file_size_gb) {
grp1->updated = updated;
grp1->g_updated = g_updated;
grp1->s_updated = s_updated;
grp1->b_updated = b_updated;
grp1->sink_updated = sink_updated;
grp1->inhibited = inhibited;
grp1->g_inhibited = g_inhibited;
grp1->s_inhibited = s_inhibited;
grp1->b_inhibited = b_inhibited;
grp1->sink_inhibited = sink_inhibited;
grp1->ti_hydro_end_min = ti_hydro_end_min;
grp1->ti_hydro_beg_max = ti_hydro_beg_max;
grp1->ti_rt_end_min = ti_rt_end_min;
grp1->ti_rt_beg_max = ti_rt_beg_max;
grp1->ti_gravity_end_min = ti_gravity_end_min;
grp1->ti_gravity_beg_max = ti_gravity_beg_max;
grp1->ti_stars_end_min = ti_stars_end_min;
grp1->ti_stars_beg_max = ti_stars_beg_max;
grp1->ti_black_holes_end_min = ti_black_holes_end_min;
grp1->ti_black_holes_beg_max = ti_black_holes_beg_max;
grp1->ti_sinks_end_min = ti_sinks_end_min;
grp1->ti_sinks_beg_max = ti_sinks_beg_max;
grp1->forcerebuild = forcerebuild;
grp1->total_nr_cells = total_nr_cells;
grp1->total_nr_tasks = total_nr_tasks;
grp1->tasks_per_cell_max = tasks_per_cell;
grp1->sfh = sfh;
grp1->runtime = runtime;
grp1->flush_lightcone_maps = flush_lightcone_maps;
grp1->deadtime = deadtime;
#ifdef WITH_CSDS
grp1->csds_file_size_gb = csds_file_size_gb;
#endif
}
/**
* @brief Do any processing necessary to the group before it can be used.
*
* This may involve an MPI reduction across all nodes.
*
* @param grp1 the #collectgroup1 struct already initialised by a call
* to collectgroup1_init.
*/
void collectgroup1_reduce(struct collectgroup1 *grp1) {
#ifdef WITH_MPI
/* Populate an MPI group struct and reduce this across all nodes. */
struct mpicollectgroup1 mpigrp11;
mpigrp11.updated = grp1->updated;
mpigrp11.g_updated = grp1->g_updated;
mpigrp11.s_updated = grp1->s_updated;
mpigrp11.sink_updated = grp1->sink_updated;
mpigrp11.b_updated = grp1->b_updated;
mpigrp11.inhibited = grp1->inhibited;
mpigrp11.g_inhibited = grp1->g_inhibited;
mpigrp11.s_inhibited = grp1->s_inhibited;
mpigrp11.sink_inhibited = grp1->sink_inhibited;
mpigrp11.b_inhibited = grp1->b_inhibited;
mpigrp11.ti_hydro_end_min = grp1->ti_hydro_end_min;
mpigrp11.ti_rt_end_min = grp1->ti_rt_end_min;
mpigrp11.ti_gravity_end_min = grp1->ti_gravity_end_min;
mpigrp11.ti_stars_end_min = grp1->ti_stars_end_min;
mpigrp11.ti_sinks_end_min = grp1->ti_sinks_end_min;
mpigrp11.ti_black_holes_end_min = grp1->ti_black_holes_end_min;
mpigrp11.ti_hydro_beg_max = grp1->ti_hydro_beg_max;
mpigrp11.ti_rt_beg_max = grp1->ti_rt_beg_max;
mpigrp11.ti_gravity_beg_max = grp1->ti_gravity_beg_max;
mpigrp11.ti_stars_beg_max = grp1->ti_stars_beg_max;
mpigrp11.ti_sinks_beg_max = grp1->ti_sinks_beg_max;
mpigrp11.ti_black_holes_beg_max = grp1->ti_black_holes_beg_max;
mpigrp11.forcerebuild = grp1->forcerebuild;
mpigrp11.total_nr_cells = grp1->total_nr_cells;
mpigrp11.total_nr_tasks = grp1->total_nr_tasks;
mpigrp11.tasks_per_cell_max = grp1->tasks_per_cell_max;
mpigrp11.sfh = grp1->sfh;
mpigrp11.runtime = grp1->runtime;
mpigrp11.flush_lightcone_maps = grp1->flush_lightcone_maps;
mpigrp11.deadtime = grp1->deadtime;
#ifdef WITH_CSDS
mpigrp11.csds_file_size_gb = grp1->csds_file_size_gb;
#endif
struct mpicollectgroup1 mpigrp12;
if (MPI_Allreduce(&mpigrp11, &mpigrp12, 1, mpicollectgroup1_type,
mpicollectgroup1_reduce_op, MPI_COMM_WORLD) != MPI_SUCCESS)
error("Failed to reduce mpicollection1.");
/* And update. */
grp1->updated = mpigrp12.updated;
grp1->g_updated = mpigrp12.g_updated;
grp1->sink_updated = mpigrp12.sink_updated;
grp1->s_updated = mpigrp12.s_updated;
grp1->b_updated = mpigrp12.b_updated;
grp1->inhibited = mpigrp12.inhibited;
grp1->g_inhibited = mpigrp12.g_inhibited;
grp1->s_inhibited = mpigrp12.s_inhibited;
grp1->sink_inhibited = mpigrp12.sink_inhibited;
grp1->b_inhibited = mpigrp12.b_inhibited;
grp1->ti_hydro_end_min = mpigrp12.ti_hydro_end_min;
grp1->ti_rt_end_min = mpigrp12.ti_rt_end_min;
grp1->ti_gravity_end_min = mpigrp12.ti_gravity_end_min;
grp1->ti_stars_end_min = mpigrp12.ti_stars_end_min;
grp1->ti_sinks_end_min = mpigrp12.ti_sinks_end_min;
grp1->ti_black_holes_end_min = mpigrp12.ti_black_holes_end_min;
grp1->ti_hydro_beg_max = mpigrp12.ti_hydro_beg_max;
grp1->ti_rt_beg_max = mpigrp12.ti_rt_beg_max;
grp1->ti_gravity_beg_max = mpigrp12.ti_gravity_beg_max;
grp1->ti_stars_beg_max = mpigrp12.ti_stars_beg_max;
grp1->ti_sinks_beg_max = mpigrp12.ti_sinks_beg_max;
grp1->ti_black_holes_beg_max = mpigrp12.ti_black_holes_beg_max;
grp1->forcerebuild = mpigrp12.forcerebuild;
grp1->total_nr_cells = mpigrp12.total_nr_cells;
grp1->total_nr_tasks = mpigrp12.total_nr_tasks;
grp1->tasks_per_cell_max = mpigrp12.tasks_per_cell_max;
grp1->sfh = mpigrp12.sfh;
grp1->runtime = mpigrp12.runtime;
grp1->flush_lightcone_maps = mpigrp12.flush_lightcone_maps;
grp1->deadtime = mpigrp12.deadtime;
#ifdef WITH_CSDS
grp1->csds_file_size_gb = mpigrp12.csds_file_size_gb;
#endif
#endif
}
#ifdef WITH_MPI
/**
* @brief Do the reduction of two structs.
*
* @param mpigrp11 the first struct, this is updated on exit.
* @param mpigrp12 the second struct
*/
static void doreduce1(struct mpicollectgroup1 *mpigrp11,
const struct mpicollectgroup1 *mpigrp12) {
/* Do what is needed for each part of the collection. */
/* Sum of updates. */
mpigrp11->updated += mpigrp12->updated;
mpigrp11->g_updated += mpigrp12->g_updated;
mpigrp11->s_updated += mpigrp12->s_updated;
mpigrp11->sink_updated += mpigrp12->sink_updated;
mpigrp11->b_updated += mpigrp12->b_updated;
/* Sum of inhibited */
mpigrp11->inhibited += mpigrp12->inhibited;
mpigrp11->g_inhibited += mpigrp12->g_inhibited;
mpigrp11->s_inhibited += mpigrp12->s_inhibited;
mpigrp11->sink_inhibited += mpigrp12->sink_inhibited;
mpigrp11->b_inhibited += mpigrp12->b_inhibited;
/* Minimum end time. */
mpigrp11->ti_hydro_end_min =
min(mpigrp11->ti_hydro_end_min, mpigrp12->ti_hydro_end_min);
mpigrp11->ti_rt_end_min =
min(mpigrp11->ti_rt_end_min, mpigrp12->ti_rt_end_min);
mpigrp11->ti_gravity_end_min =
min(mpigrp11->ti_gravity_end_min, mpigrp12->ti_gravity_end_min);
mpigrp11->ti_stars_end_min =
min(mpigrp11->ti_stars_end_min, mpigrp12->ti_stars_end_min);
mpigrp11->ti_sinks_end_min =
min(mpigrp11->ti_sinks_end_min, mpigrp12->ti_sinks_end_min);
mpigrp11->ti_black_holes_end_min =
min(mpigrp11->ti_black_holes_end_min, mpigrp12->ti_black_holes_end_min);
/* Maximum beg time. */
mpigrp11->ti_hydro_beg_max =
max(mpigrp11->ti_hydro_beg_max, mpigrp12->ti_hydro_beg_max);
mpigrp11->ti_rt_beg_max =
max(mpigrp11->ti_rt_beg_max, mpigrp12->ti_rt_beg_max);
mpigrp11->ti_gravity_beg_max =
max(mpigrp11->ti_gravity_beg_max, mpigrp12->ti_gravity_beg_max);
mpigrp11->ti_stars_beg_max =
max(mpigrp11->ti_stars_beg_max, mpigrp12->ti_stars_beg_max);
mpigrp11->ti_sinks_beg_max =
max(mpigrp11->ti_sinks_beg_max, mpigrp12->ti_sinks_beg_max);
mpigrp11->ti_black_holes_beg_max =
max(mpigrp11->ti_black_holes_beg_max, mpigrp12->ti_black_holes_beg_max);
/* Everyone must agree to not rebuild. */
if (mpigrp11->forcerebuild || mpigrp12->forcerebuild)
mpigrp11->forcerebuild = 1;
/* Totals of all tasks and cells. */
mpigrp11->total_nr_cells += mpigrp12->total_nr_cells;
mpigrp11->total_nr_tasks += mpigrp12->total_nr_tasks;
/* Maximum value of tasks_per_cell. */
mpigrp11->tasks_per_cell_max =
max(mpigrp11->tasks_per_cell_max, mpigrp12->tasks_per_cell_max);
/* Star formation history */
star_formation_logger_add(&mpigrp11->sfh, &mpigrp12->sfh);
/* Use the maximum runtime as the global runtime. */
mpigrp11->runtime = max(mpigrp11->runtime, mpigrp12->runtime);
/* Lightcone maps are all updated if any need to be updated */
if (mpigrp11->flush_lightcone_maps || mpigrp12->flush_lightcone_maps)
mpigrp11->flush_lightcone_maps = 1;
/* Sum the deadtime. */
mpigrp11->deadtime += mpigrp12->deadtime;
#ifdef WITH_CSDS
mpigrp11->csds_file_size_gb += mpigrp12->csds_file_size_gb;
#endif
}
/**
* @brief MPI reduce operator for #mpicollectgroup1 structures.
*/
static void mpicollectgroup1_reduce(void *in, void *inout, int *len,
MPI_Datatype *datatype) {
for (int i = 0; i < *len; ++i)
doreduce1(&((struct mpicollectgroup1 *)inout)[i],
&((const struct mpicollectgroup1 *)in)[i]);
}
/**
* @brief Registers any MPI collection types and reduction functions.
*/
static void mpicollect_create_MPI_type(void) {
if (MPI_Type_contiguous(sizeof(struct mpicollectgroup1), MPI_BYTE,
&mpicollectgroup1_type) != MPI_SUCCESS ||
MPI_Type_commit(&mpicollectgroup1_type) != MPI_SUCCESS) {
error("Failed to create MPI type for mpicollection1.");
}
/* Create the reduction operation */
MPI_Op_create(mpicollectgroup1_reduce, 1, &mpicollectgroup1_reduce_op);
}
void mpicollect_free_MPI_type(void) {
MPI_Type_free(&mpicollectgroup1_type);
MPI_Op_free(&mpicollectgroup1_reduce_op);
}
#endif