/*******************************************************************************
* 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 "cell.h"
/**
* @brief Pack the data of the given cell and all it's sub-cells.
*
* @param c The #cell.
* @param pc Pointer to an array of packed cells in which the
* cells will be packed.
* @param with_gravity Are we running with gravity and hence need
* to exchange multipoles?
*
* @return The number of packed cells.
*/
int cell_pack(struct cell *restrict c, struct pcell *restrict pc,
const int with_gravity) {
#ifdef WITH_MPI
/* Start by packing the data of the current cell. */
pc->hydro.h_max = c->hydro.h_max;
pc->stars.h_max = c->stars.h_max;
pc->black_holes.h_max = c->black_holes.h_max;
pc->sinks.h_max = c->sinks.h_max;
pc->hydro.ti_end_min = c->hydro.ti_end_min;
pc->grav.ti_end_min = c->grav.ti_end_min;
pc->stars.ti_end_min = c->stars.ti_end_min;
pc->sinks.ti_end_min = c->sinks.ti_end_min;
pc->black_holes.ti_end_min = c->black_holes.ti_end_min;
pc->rt.ti_rt_end_min = c->rt.ti_rt_end_min;
pc->rt.ti_rt_min_step_size = c->rt.ti_rt_min_step_size;
pc->hydro.ti_old_part = c->hydro.ti_old_part;
pc->grav.ti_old_part = c->grav.ti_old_part;
pc->grav.ti_old_multipole = c->grav.ti_old_multipole;
pc->stars.ti_old_part = c->stars.ti_old_part;
pc->black_holes.ti_old_part = c->black_holes.ti_old_part;
pc->sinks.ti_old_part = c->sinks.ti_old_part;
pc->hydro.count = c->hydro.count;
pc->grav.count = c->grav.count;
pc->stars.count = c->stars.count;
pc->sinks.count = c->sinks.count;
pc->black_holes.count = c->black_holes.count;
pc->maxdepth = c->maxdepth;
pc->grid.self_completeness = c->grid.self_completeness;
/* Copy the Multipole related information */
if (with_gravity) {
const struct gravity_tensors *mp = c->grav.multipole;
pc->grav.m_pole = mp->m_pole;
pc->grav.CoM[0] = mp->CoM[0];
pc->grav.CoM[1] = mp->CoM[1];
pc->grav.CoM[2] = mp->CoM[2];
pc->grav.CoM_rebuild[0] = mp->CoM_rebuild[0];
pc->grav.CoM_rebuild[1] = mp->CoM_rebuild[1];
pc->grav.CoM_rebuild[2] = mp->CoM_rebuild[2];
pc->grav.r_max = mp->r_max;
pc->grav.r_max_rebuild = mp->r_max_rebuild;
}
#ifdef SWIFT_DEBUG_CHECKS
pc->cellID = c->cellID;
#endif
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
pc->progeny[k] = count;
count += cell_pack(c->progeny[k], &pc[count], with_gravity);
} else {
pc->progeny[k] = -1;
}
/* Return the number of packed cells used. */
c->mpi.pcell_size = count;
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the tag of the given cell and all it's sub-cells.
*
* @param c The #cell.
* @param tags Pointer to an array of packed tags.
*
* @return The number of packed tags.
*/
int cell_pack_tags(const struct cell *c, int *tags) {
#ifdef WITH_MPI
/* Start by packing the data of the current cell. */
tags[0] = c->mpi.tag;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL)
count += cell_pack_tags(c->progeny[k], &tags[count]);
#ifdef SWIFT_DEBUG_CHECKS
if (c->mpi.pcell_size != count) error("Inconsistent tag and pcell count!");
#endif // SWIFT_DEBUG_CHECKS
/* Return the number of packed tags used. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the extra grid info of the given cell and all it's sub-cells.
*
* @param c The #cell.
* @param info Pointer to an array of packed extra grid info (construction
* levels).
*
* @return The number of packed tags.
*/
int cell_pack_grid_extra(const struct cell *c,
enum grid_construction_level *info) {
#ifdef WITH_MPI
/* Start by packing the construction level of the current cell. */
if (c->grid.construction_level == NULL) {
info[0] = grid_above_construction_level;
} else if (c->grid.construction_level == c) {
info[0] = grid_on_construction_level;
} else {
info[0] = grid_below_construction_level;
}
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL)
count += cell_pack_grid_extra(c->progeny[k], &info[count]);
#ifdef SWIFT_DEBUG_CHECKS
if (c->mpi.pcell_size != count) error("Inconsistent info and pcell count!");
#endif // SWIFT_DEBUG_CHECKS
/* Return the number of packed tags used. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
void cell_pack_part_swallow(const struct cell *c,
struct black_holes_part_data *data) {
const size_t count = c->hydro.count;
const struct part *parts = c->hydro.parts;
for (size_t i = 0; i < count; ++i) {
data[i] = parts[i].black_holes_data;
}
}
void cell_unpack_part_swallow(struct cell *c,
const struct black_holes_part_data *data) {
const size_t count = c->hydro.count;
struct part *parts = c->hydro.parts;
for (size_t i = 0; i < count; ++i) {
parts[i].black_holes_data = data[i];
}
}
void cell_pack_bpart_swallow(const struct cell *c,
struct black_holes_bpart_data *data) {
const size_t count = c->black_holes.count;
const struct bpart *bparts = c->black_holes.parts;
for (size_t i = 0; i < count; ++i) {
data[i] = bparts[i].merger_data;
}
}
void cell_unpack_bpart_swallow(struct cell *c,
const struct black_holes_bpart_data *data) {
const size_t count = c->black_holes.count;
struct bpart *bparts = c->black_holes.parts;
for (size_t i = 0; i < count; ++i) {
bparts[i].merger_data = data[i];
}
}
/**
* @brief Unpack the data of a given cell and its sub-cells.
*
* @param pc An array of packed #pcell.
* @param c The #cell in which to unpack the #pcell.
* @param s The #space in which the cells are created.
* @param with_gravity Are we running with gravity and hence need
* to exchange multipoles?
*
* @return The number of cells created.
*/
int cell_unpack(struct pcell *restrict pc, struct cell *restrict c,
struct space *restrict s, const int with_gravity) {
#ifdef WITH_MPI
/* Unpack the current pcell. */
c->hydro.h_max = pc->hydro.h_max;
c->stars.h_max = pc->stars.h_max;
c->black_holes.h_max = pc->black_holes.h_max;
c->sinks.h_max = pc->sinks.h_max;
c->hydro.ti_end_min = pc->hydro.ti_end_min;
c->grav.ti_end_min = pc->grav.ti_end_min;
c->stars.ti_end_min = pc->stars.ti_end_min;
c->black_holes.ti_end_min = pc->black_holes.ti_end_min;
c->sinks.ti_end_min = pc->sinks.ti_end_min;
c->rt.ti_rt_end_min = pc->rt.ti_rt_end_min;
c->rt.ti_rt_min_step_size = pc->rt.ti_rt_min_step_size;
c->hydro.ti_old_part = pc->hydro.ti_old_part;
c->grav.ti_old_part = pc->grav.ti_old_part;
c->grav.ti_old_multipole = pc->grav.ti_old_multipole;
c->stars.ti_old_part = pc->stars.ti_old_part;
c->black_holes.ti_old_part = pc->black_holes.ti_old_part;
c->sinks.ti_old_part = pc->sinks.ti_old_part;
c->hydro.count = pc->hydro.count;
c->grav.count = pc->grav.count;
c->stars.count = pc->stars.count;
c->sinks.count = pc->sinks.count;
c->black_holes.count = pc->black_holes.count;
c->maxdepth = pc->maxdepth;
c->grid.self_completeness = pc->grid.self_completeness;
#ifdef SWIFT_DEBUG_CHECKS
c->cellID = pc->cellID;
#endif
/* Copy the Multipole related information */
if (with_gravity) {
struct gravity_tensors *mp = c->grav.multipole;
mp->m_pole = pc->grav.m_pole;
mp->CoM[0] = pc->grav.CoM[0];
mp->CoM[1] = pc->grav.CoM[1];
mp->CoM[2] = pc->grav.CoM[2];
mp->CoM_rebuild[0] = pc->grav.CoM_rebuild[0];
mp->CoM_rebuild[1] = pc->grav.CoM_rebuild[1];
mp->CoM_rebuild[2] = pc->grav.CoM_rebuild[2];
mp->r_max = pc->grav.r_max;
mp->r_max_rebuild = pc->grav.r_max_rebuild;
}
/* Number of new cells created. */
int count = 1;
/* Fill the progeny recursively, depth-first. */
c->split = 0;
for (int k = 0; k < 8; k++)
if (pc->progeny[k] >= 0) {
struct cell *temp;
space_getcells(s, 1, &temp, 0);
temp->hydro.count = 0;
temp->grav.count = 0;
temp->stars.count = 0;
temp->sinks.count = 0;
temp->loc[0] = c->loc[0];
temp->loc[1] = c->loc[1];
temp->loc[2] = c->loc[2];
temp->width[0] = c->width[0] / 2;
temp->width[1] = c->width[1] / 2;
temp->width[2] = c->width[2] / 2;
temp->dmin = c->dmin / 2;
temp->h_min_allowed = temp->dmin * 0.5 * (1. / kernel_gamma);
temp->h_max_allowed = temp->dmin * (1. / kernel_gamma);
if (k & 4) temp->loc[0] += temp->width[0];
if (k & 2) temp->loc[1] += temp->width[1];
if (k & 1) temp->loc[2] += temp->width[2];
temp->depth = c->depth + 1;
temp->split = 0;
temp->hydro.dx_max_part = 0.f;
temp->hydro.dx_max_sort = 0.f;
temp->stars.dx_max_part = 0.f;
temp->stars.dx_max_sort = 0.f;
temp->sinks.dx_max_part = 0.f;
temp->black_holes.dx_max_part = 0.f;
temp->nodeID = c->nodeID;
temp->parent = c;
temp->top = c->top;
c->progeny[k] = temp;
c->split = 1;
count += cell_unpack(&pc[pc->progeny[k]], temp, s, with_gravity);
}
/* Return the total number of unpacked cells. */
c->mpi.pcell_size = count;
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the tags of a given cell and its sub-cells.
*
* @param tags An array of tags.
* @param c The #cell in which to unpack the tags.
*
* @return The number of tags created.
*/
int cell_unpack_tags(const int *tags, struct cell *restrict c) {
#ifdef WITH_MPI
/* Unpack the current pcell. */
c->mpi.tag = tags[0];
/* Number of new cells created. */
int count = 1;
/* Fill the progeny recursively, depth-first. */
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_tags(&tags[count], c->progeny[k]);
}
#ifdef SWIFT_DEBUG_CHECKS
if (c->mpi.pcell_size != count) error("Inconsistent tag and pcell count!");
#endif // SWIFT_DEBUG_CHECKS
/* Return the total number of unpacked tags. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the extra grid info of a given cell and its sub-cells.
*
* @param tags An array of extra grid info (construction levels).
* @param c The #cell in which to unpack the tags.
*
* @return The number of tags created.
*/
int cell_unpack_grid_extra(const enum grid_construction_level *info,
struct cell *c, struct cell *construction_level) {
#ifdef WITH_MPI
/* Unpack the current pcell. */
if (info[0] == grid_on_construction_level) {
construction_level = c;
} else if (info[0] == grid_above_construction_level) {
#ifdef SWIFT_DEBUG_CHECKS
if (construction_level != NULL)
error(
"Above construction level, but construction level cell pointer is "
"not NULL!");
#endif
} else {
#ifdef SWIFT_DEBUG_CHECKS
if (info[0] != grid_below_construction_level)
error("Invalid construction level!");
if (construction_level == NULL || construction_level == c)
error("Invalid construction level cell pointer!");
#endif
}
c->grid.construction_level = construction_level;
/* Number of new cells created. */
int count = 1;
/* Fill the progeny recursively, depth-first. */
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_grid_extra(&info[count], c->progeny[k],
construction_level);
}
#ifdef SWIFT_DEBUG_CHECKS
if (c->mpi.pcell_size != count) error("Inconsistent info and pcell count!");
#endif // SWIFT_DEBUG_CHECKS
/* Return the total number of unpacked tags. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the cell information about time-step sizes and displacements
* of a cell hierarchy.
*
* @param c The #cell's to pack.
* @param pcells the packed cell structures to pack into.
*
* @return The number of cells that were packed.
*/
int cell_pack_end_step(const struct cell *c, struct pcell_step *pcells) {
#ifdef WITH_MPI
/* Pack this cell's data. */
pcells[0].hydro.ti_end_min = c->hydro.ti_end_min;
pcells[0].hydro.dx_max_part = c->hydro.dx_max_part;
pcells[0].rt.ti_rt_end_min = c->rt.ti_rt_end_min;
pcells[0].rt.ti_rt_min_step_size = c->rt.ti_rt_min_step_size;
pcells[0].grav.ti_end_min = c->grav.ti_end_min;
pcells[0].stars.ti_end_min = c->stars.ti_end_min;
pcells[0].stars.dx_max_part = c->stars.dx_max_part;
pcells[0].black_holes.ti_end_min = c->black_holes.ti_end_min;
pcells[0].black_holes.dx_max_part = c->black_holes.dx_max_part;
pcells[0].sinks.ti_end_min = c->sinks.ti_end_min;
pcells[0].sinks.dx_max_part = c->sinks.dx_max_part;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_pack_end_step(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the cell information about time-step sizes and displacements
* of a cell hierarchy.
*
* @param c The #cell's to unpack into.
* @param pcells the packed cell structures to unpack from.
*
* @return The number of cells that were packed.
*/
int cell_unpack_end_step(struct cell *c, const struct pcell_step *pcells) {
#ifdef WITH_MPI
/* Unpack this cell's data. */
c->hydro.ti_end_min = pcells[0].hydro.ti_end_min;
c->hydro.dx_max_part = pcells[0].hydro.dx_max_part;
c->rt.ti_rt_end_min = pcells[0].rt.ti_rt_end_min;
c->rt.ti_rt_min_step_size = pcells[0].rt.ti_rt_min_step_size;
c->grav.ti_end_min = pcells[0].grav.ti_end_min;
c->stars.ti_end_min = pcells[0].stars.ti_end_min;
c->stars.dx_max_part = pcells[0].stars.dx_max_part;
c->black_holes.ti_end_min = pcells[0].black_holes.ti_end_min;
c->black_holes.dx_max_part = pcells[0].black_holes.dx_max_part;
c->sinks.ti_end_min = pcells[0].sinks.ti_end_min;
c->sinks.dx_max_part = pcells[0].sinks.dx_max_part;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_end_step(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the hydro timebin information of the given cell.
*
* t needs to be aligned on SWIFT_CACHE_ALIGNMENT.
*
* @param c The #cell.
* @param t (output) The array of timebins we pack into.
*/
void cell_pack_timebin(const struct cell *const c, timebin_t *const t) {
#ifdef WITH_MPI
swift_declare_aligned_ptr(timebin_t, t_align, t, SWIFT_CACHE_ALIGNMENT);
for (int i = 0; i < c->hydro.count; ++i)
t_align[i] = c->hydro.parts[i].time_bin;
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Unpack the hydro timebin information of a given cell.
*
* t needs to be aligned on SWIFT_CACHE_ALIGNMENT.
*
* @param c The #cell
* @param t The array of timebins we unpack from.
*/
void cell_unpack_timebin(struct cell *const c, timebin_t *const t) {
#ifdef WITH_MPI
swift_declare_aligned_ptr(timebin_t, t_align, t, SWIFT_CACHE_ALIGNMENT);
for (int i = 0; i < c->hydro.count; ++i)
c->hydro.parts[i].time_bin = t_align[i];
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Pack the multipole information of the given cell and all it's
* sub-cells.
*
* @param c The #cell.
* @param pcells (output) The multipole information we pack into
*
* @return The number of packed cells.
*/
int cell_pack_multipoles(struct cell *restrict c,
struct gravity_tensors *restrict pcells) {
#ifdef WITH_MPI
/* Pack this cell's data. */
pcells[0] = *c->grav.multipole;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_pack_multipoles(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the multipole information of a given cell and its sub-cells.
*
* @param c The #cell
* @param pcells The multipole information to unpack
*
* @return The number of cells created.
*/
int cell_unpack_multipoles(struct cell *restrict c,
struct gravity_tensors *restrict pcells) {
#ifdef WITH_MPI
/* Unpack this cell's data. */
*c->grav.multipole = pcells[0];
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_multipoles(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the counts for star formation of the given cell and all it's
* sub-cells.
*
* @param c The #cell.
* @param pcells (output) The multipole information we pack into
*
* @return The number of packed cells.
*/
int cell_pack_sf_counts(struct cell *c, struct pcell_sf_stars *pcells) {
#ifdef WITH_MPI
/* Pack this cell's data. */
pcells[0].delta_from_rebuild = c->stars.parts - c->stars.parts_rebuild;
pcells[0].count = c->stars.count;
pcells[0].dx_max_part = c->stars.dx_max_part;
#ifdef SWIFT_DEBUG_CHECKS
/* Stars */
if (c->stars.parts_rebuild == NULL)
error("Star particles array at rebuild is NULL! c->depth=%d", c->depth);
if (pcells[0].delta_from_rebuild < 0)
error("Stars part pointer moved in the wrong direction!");
if (pcells[0].delta_from_rebuild > 0 && c->depth == 0)
error("Shifting the top-level pointer is not allowed!");
#endif
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_pack_sf_counts(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the counts for star formation of a given cell and its
* sub-cells.
*
* @param c The #cell
* @param pcells The multipole information to unpack
*
* @return The number of cells created.
*/
int cell_unpack_sf_counts(struct cell *c, struct pcell_sf_stars *pcells) {
#ifdef WITH_MPI
#ifdef SWIFT_DEBUG_CHECKS
if (c->stars.parts_rebuild == NULL)
error("Star particles array at rebuild is NULL!");
#endif
/* Unpack this cell's data. */
c->stars.count = pcells[0].count;
c->stars.parts = c->stars.parts_rebuild + pcells[0].delta_from_rebuild;
c->stars.dx_max_part = pcells[0].dx_max_part;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_sf_counts(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Pack the counts for star formation of the given cell and all it's
* sub-cells.
*
* @param c The #cell.
* @param pcells (output) The multipole information we pack into
*
* @return The number of packed cells.
*/
int cell_pack_grav_counts(struct cell *c, struct pcell_sf_grav *pcells) {
#ifdef WITH_MPI
/* Pack this cell's data. */
pcells[0].delta_from_rebuild = c->grav.parts - c->grav.parts_rebuild;
pcells[0].count = c->grav.count;
#ifdef SWIFT_DEBUG_CHECKS
/* Grav */
if (c->grav.parts_rebuild == NULL)
error("Grav. particles array at rebuild is NULL! c->depth=%d", c->depth);
if (pcells[0].delta_from_rebuild < 0)
error("Grav part pointer moved in the wrong direction!");
if (pcells[0].delta_from_rebuild > 0 && c->depth == 0)
error("Shifting the top-level pointer is not allowed!");
#endif
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_pack_grav_counts(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}
/**
* @brief Unpack the counts for star formation of a given cell and its
* sub-cells.
*
* @param c The #cell
* @param pcells The multipole information to unpack
*
* @return The number of cells created.
*/
int cell_unpack_grav_counts(struct cell *c, struct pcell_sf_grav *pcells) {
#ifdef WITH_MPI
#ifdef SWIFT_DEBUG_CHECKS
if (c->stars.parts_rebuild == NULL)
error("Star particles array at rebuild is NULL!");
#endif
/* Unpack this cell's data. */
c->grav.count = pcells[0].count;
c->grav.parts = c->grav.parts_rebuild + pcells[0].delta_from_rebuild;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
if (c->progeny[k] != NULL) {
count += cell_unpack_grav_counts(c->progeny[k], &pcells[count]);
}
/* Return the number of packed values. */
return count;
#else
error("SWIFT was not compiled with MPI support.");
return 0;
#endif
}