/*******************************************************************************
* 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)
*
* 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 "space.h"
/* Local headers. */
#include "cell.h"
#include "engine.h"
#include "star_formation_logger.h"
#include "threadpool.h"
/**
* @brief Recursively dismantle a cell tree.
*
* @param s The #space.
* @param c The #cell to recycle.
* @param cell_rec_begin Pointer to the start of the list of cells to recycle.
* @param cell_rec_end Pointer to the end of the list of cells to recycle.
* @param multipole_rec_begin Pointer to the start of the list of multipoles to
* recycle.
* @param multipole_rec_end Pointer to the end of the list of multipoles to
* recycle.
*/
void space_rebuild_recycle_rec(struct space *s, struct cell *c,
struct cell **cell_rec_begin,
struct cell **cell_rec_end,
struct gravity_tensors **multipole_rec_begin,
struct gravity_tensors **multipole_rec_end) {
if (c->split)
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
space_rebuild_recycle_rec(s, c->progeny[k], cell_rec_begin,
cell_rec_end, multipole_rec_begin,
multipole_rec_end);
c->progeny[k]->next = *cell_rec_begin;
*cell_rec_begin = c->progeny[k];
if (s->with_self_gravity) {
c->progeny[k]->grav.multipole->next = *multipole_rec_begin;
*multipole_rec_begin = c->progeny[k]->grav.multipole;
}
if (*cell_rec_end == NULL) *cell_rec_end = *cell_rec_begin;
if (s->with_self_gravity && *multipole_rec_end == NULL)
*multipole_rec_end = *multipole_rec_begin;
c->progeny[k]->grav.multipole = NULL;
c->progeny[k] = NULL;
}
}
void space_rebuild_recycle_mapper(void *map_data, int num_elements,
void *extra_data) {
struct space *s = (struct space *)extra_data;
struct cell *cells = (struct cell *)map_data;
for (int k = 0; k < num_elements; k++) {
struct cell *c = &cells[k];
struct cell *cell_rec_begin = NULL, *cell_rec_end = NULL;
struct gravity_tensors *multipole_rec_begin = NULL,
*multipole_rec_end = NULL;
space_rebuild_recycle_rec(s, c, &cell_rec_begin, &cell_rec_end,
&multipole_rec_begin, &multipole_rec_end);
if (cell_rec_begin != NULL)
space_recycle_list(s, cell_rec_begin, cell_rec_end, multipole_rec_begin,
multipole_rec_end);
c->hydro.sorts = NULL;
c->stars.sorts = NULL;
#ifdef SWIFT_DEBUG_CHECKS
c->nr_tasks = 0;
#endif
c->grav.nr_mm_tasks = 0;
c->hydro.density = NULL;
c->hydro.gradient = NULL;
c->hydro.force = NULL;
c->hydro.limiter = NULL;
c->grav.grav = NULL;
c->grav.mm = NULL;
c->hydro.dx_max_part = 0.0f;
c->hydro.dx_max_sort = 0.0f;
c->sinks.dx_max_part = 0.f;
c->stars.dx_max_part = 0.f;
c->stars.dx_max_sort = 0.f;
c->black_holes.dx_max_part = 0.f;
c->hydro.sorted = 0;
c->hydro.sort_allocated = 0;
c->stars.sorted = 0;
c->hydro.count = 0;
c->hydro.count_total = 0;
c->hydro.updated = 0;
c->grav.count = 0;
c->grav.count_total = 0;
c->grav.updated = 0;
c->sinks.count = 0;
c->stars.count = 0;
c->stars.count_total = 0;
c->stars.updated = 0;
c->black_holes.count = 0;
c->black_holes.count_total = 0;
c->black_holes.updated = 0;
c->grav.init = NULL;
c->grav.init_out = NULL;
c->hydro.extra_ghost = NULL;
c->hydro.ghost_in = NULL;
c->hydro.ghost_out = NULL;
c->hydro.ghost = NULL;
c->hydro.prep1_ghost = NULL;
c->hydro.star_formation = NULL;
c->sinks.sink_formation = NULL;
c->sinks.star_formation_sink = NULL;
c->hydro.stars_resort = NULL;
c->stars.density_ghost = NULL;
c->stars.prep1_ghost = NULL;
c->stars.prep2_ghost = NULL;
c->stars.density = NULL;
c->stars.feedback = NULL;
c->stars.prepare1 = NULL;
c->stars.prepare2 = NULL;
c->sinks.density = NULL;
c->sinks.swallow = NULL;
c->sinks.do_sink_swallow = NULL;
c->sinks.do_gas_swallow = NULL;
c->black_holes.density_ghost = NULL;
c->black_holes.swallow_ghost_1 = NULL;
c->black_holes.swallow_ghost_2 = NULL;
c->black_holes.swallow_ghost_3 = NULL;
c->black_holes.density = NULL;
c->black_holes.swallow = NULL;
c->black_holes.do_gas_swallow = NULL;
c->black_holes.do_bh_swallow = NULL;
c->black_holes.feedback = NULL;
#ifdef WITH_CSDS
c->csds = NULL;
#endif
c->kick1 = NULL;
c->kick2 = NULL;
c->timestep = NULL;
c->timestep_limiter = NULL;
c->timestep_sync = NULL;
c->timestep_collect = NULL;
c->hydro.end_force = NULL;
c->hydro.drift = NULL;
c->sinks.drift = NULL;
c->stars.drift = NULL;
c->stars.stars_in = NULL;
c->stars.stars_out = NULL;
c->black_holes.drift = NULL;
c->black_holes.black_holes_in = NULL;
c->black_holes.black_holes_out = NULL;
c->sinks.sink_in = NULL;
c->sinks.density_ghost = NULL;
c->sinks.sink_ghost1 = NULL;
c->sinks.sink_ghost2 = NULL;
c->sinks.sink_out = NULL;
c->grav.drift = NULL;
c->grav.drift_out = NULL;
c->hydro.cooling_in = NULL;
c->hydro.cooling_out = NULL;
c->hydro.cooling = NULL;
c->grav.long_range = NULL;
c->grav.down_in = NULL;
c->grav.down = NULL;
c->grav.end_force = NULL;
c->grav.neutrino_weight = NULL;
c->top = c;
c->super = c;
c->hydro.super = c;
c->grav.super = c;
c->hydro.parts = NULL;
c->hydro.xparts = NULL;
c->grav.parts = NULL;
c->grav.parts_rebuild = NULL;
c->sinks.parts = NULL;
c->sinks.parts_rebuild = NULL;
c->stars.parts = NULL;
c->stars.parts_rebuild = NULL;
c->black_holes.parts = NULL;
c->flags = 0;
c->hydro.ti_end_min = -1;
c->grav.ti_end_min = -1;
c->sinks.ti_end_min = -1;
c->stars.ti_end_min = -1;
c->black_holes.ti_end_min = -1;
c->rt.rt_in = NULL;
c->rt.rt_ghost1 = NULL;
c->rt.rt_gradient = NULL;
c->rt.rt_ghost2 = NULL;
c->rt.rt_transport = NULL;
c->rt.rt_transport_out = NULL;
c->rt.rt_tchem = NULL;
c->rt.rt_advance_cell_time = NULL;
c->rt.rt_sorts = NULL;
c->rt.rt_out = NULL;
c->rt.rt_collect_times = NULL;
c->rt.ti_rt_end_min = -1;
c->rt.ti_rt_min_step_size = -1;
c->rt.updated = 0;
#ifdef SWIFT_RT_DEBUG_CHECKS
c->rt.advanced_time = 0;
#endif
star_formation_logger_init(&c->stars.sfh);
#if defined(SWIFT_DEBUG_CHECKS) || defined(SWIFT_CELL_GRAPH)
c->cellID = 0;
#endif
if (s->with_self_gravity)
bzero(c->grav.multipole, sizeof(struct gravity_tensors));
cell_free_hydro_sorts(c);
cell_free_stars_sorts(c);
#if WITH_MPI
c->mpi.tag = -1;
c->mpi.recv = NULL;
c->mpi.send = NULL;
#endif
}
}
/**
* @brief Return a used cell to the buffer of unused sub-cells.
*
* @param s The #space.
* @param c The #cell.
*/
void space_recycle(struct space *s, struct cell *c) {
/* Clear the cell. */
if (lock_destroy(&c->hydro.lock) != 0 || lock_destroy(&c->grav.plock) != 0 ||
lock_destroy(&c->grav.mlock) != 0 || lock_destroy(&c->stars.lock) != 0 ||
lock_destroy(&c->sinks.lock) != 0 ||
lock_destroy(&c->hydro.extra_sort_lock) != 0 ||
lock_destroy(&c->sinks.sink_formation_lock) != 0 ||
lock_destroy(&c->black_holes.lock) != 0 ||
lock_destroy(&c->grav.star_formation_lock) != 0 ||
lock_destroy(&c->stars.star_formation_lock) != 0)
error("Failed to destroy spinlocks.");
/* Hook the multipole back in the buffer */
if (s->with_self_gravity) {
c->grav.multipole->next = s->multipoles_sub[c->tpid];
s->multipoles_sub[c->tpid] = c->grav.multipole;
}
/* Hook this cell into the buffer. */
c->next = s->cells_sub[c->tpid];
s->cells_sub[c->tpid] = c;
atomic_dec(&s->tot_cells);
}
/**
* @brief Return a list of used cells to the buffer of unused sub-cells.
*
* @param s The #space.
* @param cell_list_begin Pointer to the first #cell in the linked list of
* cells joined by their @c next pointers.
* @param cell_list_end Pointer to the last #cell in the linked list of
* cells joined by their @c next pointers. It is assumed that this
* cell's @c next pointer is @c NULL.
* @param multipole_list_begin Pointer to the first #multipole in the linked
* list of
* multipoles joined by their @c next pointers.
* @param multipole_list_end Pointer to the last #multipole in the linked list
* of
* multipoles joined by their @c next pointers. It is assumed that this
* multipole's @c next pointer is @c NULL.
*/
void space_recycle_list(struct space *s, struct cell *cell_list_begin,
struct cell *cell_list_end,
struct gravity_tensors *multipole_list_begin,
struct gravity_tensors *multipole_list_end) {
int count = 0;
/* Clean up the list of cells. */
for (struct cell *c = cell_list_begin; c != NULL; c = c->next) {
/* Clear the cell. */
if (lock_destroy(&c->hydro.lock) != 0 ||
lock_destroy(&c->grav.plock) != 0 ||
lock_destroy(&c->grav.mlock) != 0 ||
lock_destroy(&c->stars.lock) != 0 ||
lock_destroy(&c->sinks.lock) != 0 ||
lock_destroy(&c->hydro.extra_sort_lock) != 0 ||
lock_destroy(&c->sinks.sink_formation_lock) != 0 ||
lock_destroy(&c->black_holes.lock) != 0 ||
lock_destroy(&c->stars.star_formation_lock) != 0 ||
lock_destroy(&c->grav.star_formation_lock) != 0)
error("Failed to destroy spinlocks.");
/* Count this cell. */
count += 1;
}
/* Lock the space. */
lock_lock(&s->lock);
/* Hook the cells into the buffer keeping tpid if we can. */
short int tpid = cell_list_begin->tpid;
if (tpid < 0) tpid = 0;
cell_list_end->next = s->cells_sub[tpid];
s->cells_sub[tpid] = cell_list_begin;
atomic_sub(&s->tot_cells, count);
/* Hook the multipoles into the buffer. */
if (s->with_self_gravity) {
multipole_list_end->next = s->multipoles_sub[tpid];
s->multipoles_sub[tpid] = multipole_list_begin;
}
/* Unlock the space. */
lock_unlock_blind(&s->lock);
}
/**
* @brief Free up any allocated cells.
*
* @param s The #space.
*/
void space_free_cells(struct space *s) {
ticks tic = getticks();
threadpool_map(&s->e->threadpool, space_rebuild_recycle_mapper, s->cells_top,
s->nr_cells, sizeof(struct cell), threadpool_auto_chunk_size,
s);
s->maxdepth = 0;
if (s->e->verbose)
message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
clocks_getunit());
}