/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
* Matthieu Schaller (schaller@strw.leidenuniv.nl)
* 2015 Peter W. Draper (p.w.draper@durham.ac.uk)
* Angus Lepper (angus.lepper@ed.ac.uk)
* 2016 John A. Regan (john.a.regan@durham.ac.uk)
* Tom Theuns (tom.theuns@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
/* This object's header. */
#include "engine.h"
#include "lightcone/lightcone_array.h"
/**
* @brief Mapper function to drift *all* the #part to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_part_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_top[ind]];
if (c->nodeID == e->nodeID) {
/* Drift all the particles */
cell_drift_part(c, e, /* force the drift=*/1, NULL);
}
}
}
/**
* @brief Mapper function to drift *all* the #gpart to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_gpart_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_top[ind]];
if (c->nodeID == e->nodeID) {
/* Drift all the particles */
cell_drift_gpart(c, e, /* force the drift=*/1, /*replication_list=*/NULL);
}
}
}
/**
* @brief Mapper function to drift *all* the #spart to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_spart_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_top[ind]];
if (c->nodeID == e->nodeID) {
/* Drift all the particles */
cell_drift_spart(c, e, /* force the drift=*/1, NULL);
}
}
}
/**
* @brief Mapper function to drift *all* the #bpart to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_bpart_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_top[ind]];
if (c->nodeID == e->nodeID) {
/* Drift all the particles */
cell_drift_bpart(c, e, /* force the drift=*/1, NULL);
}
}
}
/**
* @brief Mapper function to drift *all* the #sink to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_sink_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_top[ind]];
if (c->nodeID == e->nodeID) {
/* Drift all the particles */
cell_drift_sink(c, e, /* force the drift=*/1);
}
}
}
/**
* @brief Mapper function to drift *all* the multipoles to the current time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_all_multipole_mapper(void *map_data, int num_elements,
void *extra_data) {
const struct engine *e = (const struct engine *)extra_data;
const int restarting = e->restarting;
struct space *s = e->s;
struct cell *cells_top;
int *local_cells_with_tasks_top;
if (restarting) {
/* When restarting, we loop over all top-level cells */
cells_top = (struct cell *)map_data;
local_cells_with_tasks_top = NULL;
} else {
/* In any other case, we use the list of local cells with tasks */
cells_top = s->cells_top;
local_cells_with_tasks_top = (int *)map_data;
}
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c;
/* When restarting, the list of local cells does not
yet exist. We use the raw list of top-level cells instead */
if (restarting)
c = &cells_top[ind];
else
c = &cells_top[local_cells_with_tasks_top[ind]];
cell_drift_all_multipoles(c, e);
}
}
/**
* @brief Drift *all* particles and multipoles at all levels
* forward to the current time.
*
* @param e The #engine.
* @param drift_mpoles Do we want to drift all the multipoles as well?
*/
void engine_drift_all(struct engine *e, const int drift_mpoles) {
const ticks tic = getticks();
if (e->nodeID == 0 && e->verbose) {
if (e->policy & engine_policy_cosmology)
message("Drifting all to a=%15.12e",
exp(e->ti_current * e->time_base) * e->cosmology->a_begin);
else
message("Drifting all to t=%15.12e",
e->ti_current * e->time_base + e->time_begin);
}
#ifdef WITH_LIGHTCONE
/* Determine which periodic replications could contribute to the lightcone
during this time step */
lightcone_array_prepare_for_step(e->lightcone_array_properties, e->cosmology,
e->ti_earliest_undrifted, e->ti_current);
#endif
if (!e->restarting) {
/* Normal case: We have a list of local cells with tasks to play with */
if (e->s->nr_parts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_part_mapper,
e->s->local_cells_top, e->s->nr_local_cells, sizeof(int),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_gparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_gpart_mapper,
e->s->local_cells_top, e->s->nr_local_cells, sizeof(int),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_sparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_spart_mapper,
e->s->local_cells_top, e->s->nr_local_cells, sizeof(int),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_sinks > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_sink_mapper,
e->s->local_cells_top, e->s->nr_local_cells, sizeof(int),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_bparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_bpart_mapper,
e->s->local_cells_top, e->s->nr_local_cells, sizeof(int),
threadpool_auto_chunk_size, e);
}
if (drift_mpoles && (e->policy & engine_policy_self_gravity)) {
threadpool_map(&e->threadpool, engine_do_drift_all_multipole_mapper,
e->s->local_cells_with_tasks_top,
e->s->nr_local_cells_with_tasks, sizeof(int),
threadpool_auto_chunk_size, e);
}
} else {
/* When restarting, the list of local cells with tasks does not yet
exist. We use the raw list of top-level cells instead */
if (e->s->nr_parts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_part_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_sparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_spart_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_sinks > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_sink_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_bparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_bpart_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
if (e->s->nr_gparts > 0) {
threadpool_map(&e->threadpool, engine_do_drift_all_gpart_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
if (e->policy & engine_policy_self_gravity) {
threadpool_map(&e->threadpool, engine_do_drift_all_multipole_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
}
}
/* Synchronize particle positions */
space_synchronize_particle_positions(e->s);
#ifdef SWIFT_DEBUG_CHECKS
/* Check that all cells have been drifted to the current time. */
space_check_drift_point(
e->s, e->ti_current,
drift_mpoles && (e->policy & engine_policy_self_gravity));
part_verify_links(e->s->parts, e->s->gparts, e->s->sinks, e->s->sparts,
e->s->bparts, e->s->nr_parts, e->s->nr_gparts,
e->s->nr_sinks, e->s->nr_sparts, e->s->nr_bparts,
e->verbose);
#endif
/* All particles have now been drifted to ti_current */
e->ti_earliest_undrifted = e->ti_current;
if (e->verbose)
message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
clocks_getunit());
#ifdef WITH_LIGHTCONE
/* Drifting all of the particles can cause many particles to cross
the lightcone, so flush buffers now to reduce peak memory use . */
lightcone_array_flush(e->lightcone_array_properties, &e->threadpool,
e->cosmology, e->internal_units, e->snapshot_units,
/*flush_map_updates=*/1, /*flush_particles=*/1,
/*end_file=*/0, /*dump_all_shells=*/0);
#endif
}
/**
* @brief Mapper function to drift *all* top-level multipoles forward in
* time.
*
* @param map_data An array of #cell%s.
* @param num_elements Chunk size.
* @param extra_data Pointer to an #engine.
*/
void engine_do_drift_top_multipoles_mapper(void *map_data, int num_elements,
void *extra_data) {
struct engine *e = (struct engine *)extra_data;
struct cell *cells = (struct cell *)map_data;
for (int ind = 0; ind < num_elements; ind++) {
struct cell *c = &cells[ind];
if (c != NULL) {
/* Drift the multipole at this level only */
if (c->grav.ti_old_multipole != e->ti_current) cell_drift_multipole(c, e);
}
}
}
/**
* @brief Drift *all* top-level multipoles forward to the current time.
*
* @param e The #engine.
*/
void engine_drift_top_multipoles(struct engine *e) {
const ticks tic = getticks();
threadpool_map(&e->threadpool, engine_do_drift_top_multipoles_mapper,
e->s->cells_top, e->s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, e);
#ifdef SWIFT_DEBUG_CHECKS
/* Check that all cells have been drifted to the current time. */
space_check_top_multipoles_drift_point(e->s, e->ti_current);
#endif
if (e->verbose)
message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
clocks_getunit());
}