/*******************************************************************************
* 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"
/* Local headers. */
#include "active.h"
#include "engine.h"
#include "hydro.h"
#include "sink_properties.h"
/**
* @brief Recursively update the pointer and counter for #spart after the
* addition of a new particle.
*
* @param c The cell we are working on.
* @param progeny_list The list of the progeny index at each level for the
* leaf-cell where the particle was added.
* @param main_branch Are we in a cell directly above the leaf where the new
* particle was added?
*/
void cell_recursively_shift_sparts(struct cell *c,
const int progeny_list[space_cell_maxdepth],
const int main_branch) {
if (c->split) {
/* No need to recurse in progenies located before the insestion point */
const int first_progeny = main_branch ? progeny_list[(int)c->depth] : 0;
for (int k = first_progeny; k < 8; ++k) {
if (c->progeny[k] != NULL)
cell_recursively_shift_sparts(c->progeny[k], progeny_list,
main_branch && (k == first_progeny));
}
}
/* When directly above the leaf with the new particle: increase the particle
* count */
/* When after the leaf with the new particle: shift by one position */
if (main_branch) {
c->stars.count++;
/* Indicate that the cell is not sorted and cancel the pointer sorting
* arrays. */
c->stars.sorted = 0;
cell_free_stars_sorts(c);
} else {
c->stars.parts++;
}
}
/**
* @brief Recursively update the pointer and counter for #sink after the
* addition of a new particle.
*
* @param c The cell we are working on.
* @param progeny_list The list of the progeny index at each level for the
* leaf-cell where the particle was added.
* @param main_branch Are we in a cell directly above the leaf where the new
* particle was added?
*/
void cell_recursively_shift_sinks(struct cell *c,
const int progeny_list[space_cell_maxdepth],
const int main_branch) {
if (c->split) {
/* No need to recurse in progenies located before the insestion point */
const int first_progeny = main_branch ? progeny_list[(int)c->depth] : 0;
for (int k = first_progeny; k < 8; ++k) {
if (c->progeny[k] != NULL)
cell_recursively_shift_sinks(c->progeny[k], progeny_list,
main_branch && (k == first_progeny));
}
}
/* When directly above the leaf with the new particle: increase the particle
* count */
/* When after the leaf with the new particle: shift by one position */
if (main_branch) {
c->sinks.count++;
} else {
c->sinks.parts++;
}
}
/**
* @brief Recursively update the pointer and counter for #gpart after the
* addition of a new particle.
*
* @param c The cell we are working on.
* @param progeny_list The list of the progeny index at each level for the
* leaf-cell where the particle was added.
* @param main_branch Are we in a cell directly above the leaf where the new
* particle was added?
*/
void cell_recursively_shift_gparts(struct cell *c,
const int progeny_list[space_cell_maxdepth],
const int main_branch) {
if (c->split) {
/* No need to recurse in progenies located before the insestion point */
const int first_progeny = main_branch ? progeny_list[(int)c->depth] : 0;
for (int k = first_progeny; k < 8; ++k) {
if (c->progeny[k] != NULL)
cell_recursively_shift_gparts(c->progeny[k], progeny_list,
main_branch && (k == first_progeny));
}
}
/* When directly above the leaf with the new particle: increase the particle
* count */
/* When after the leaf with the new particle: shift by one position */
if (main_branch) {
c->grav.count++;
} else {
c->grav.parts++;
}
}
/**
* @brief "Add" a #spart in a given #cell.
*
* This function will add a #spart at the start of the current cell's array by
* shifting all the #spart in the top-level cell by one position. All the
* pointers and cell counts are updated accordingly.
*
* @param e The #engine.
* @param c The leaf-cell in which to add the #spart.
*
* @return A pointer to the newly added #spart. The spart has a been zeroed
* and given a position within the cell as well as set to the minimal active
* time bin.
*/
struct spart *cell_add_spart(struct engine *e, struct cell *const c) {
/* Perform some basic consitency checks */
if (c->nodeID != engine_rank) error("Adding spart on a foreign node");
if (c->stars.ti_old_part != e->ti_current) error("Undrifted cell!");
if (c->split) error("Addition of spart performed above the leaf level");
/* Progeny number at each level */
int progeny[space_cell_maxdepth];
#ifdef SWIFT_DEBUG_CHECKS
for (int i = 0; i < space_cell_maxdepth; ++i) progeny[i] = -1;
#endif
/* Get the top-level this leaf cell is in and compute the progeny indices at
each level */
struct cell *top = c;
while (top->parent != NULL) {
/* What is the progeny index of the cell? */
for (int k = 0; k < 8; ++k) {
if (top->parent->progeny[k] == top) {
progeny[(int)top->parent->depth] = k;
}
}
/* Check that the cell was indeed drifted to this point to avoid future
* issues */
#ifdef SWIFT_DEBUG_CHECKS
if (top->hydro.super != NULL && top->stars.count > 0 &&
top->stars.ti_old_part != e->ti_current) {
error("Cell had not been correctly drifted before star formation");
}
#endif
/* Climb up */
top = top->parent;
}
/* Lock the top-level cell as we are going to operate on it */
lock_lock(&top->stars.star_formation_lock);
/* Are there any extra particles left? */
if (top->stars.count == top->stars.count_total) {
message("We ran out of free star particles!");
/* Release the local lock before exiting. */
if (lock_unlock(&top->stars.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
atomic_inc(&e->forcerebuild);
return NULL;
}
/* Number of particles to shift in order to get a free space. */
const size_t n_copy = &top->stars.parts[top->stars.count] - c->stars.parts;
#ifdef SWIFT_DEBUG_CHECKS
if (c->stars.parts + n_copy > top->stars.parts + top->stars.count)
error("Copying beyond the allowed range");
#endif
if (n_copy > 0) {
// MATTHIEU: This can be improved. We don't need to copy everything, just
// need to swap a few particles.
memmove(&c->stars.parts[1], &c->stars.parts[0],
n_copy * sizeof(struct spart));
/* Update the spart->gpart links (shift by 1) */
for (size_t i = 0; i < n_copy; ++i) {
#ifdef SWIFT_DEBUG_CHECKS
if (c->stars.parts[i + 1].gpart == NULL) {
error("Incorrectly linked spart!");
}
#endif
c->stars.parts[i + 1].gpart->id_or_neg_offset--;
}
}
/* Recursively shift all the stars to get a free spot at the start of the
* current cell*/
cell_recursively_shift_sparts(top, progeny, /* main_branch=*/1);
/* Make sure the gravity will be recomputed for this particle in the next
* step
*/
struct cell *top2 = c;
while (top2->parent != NULL) {
top2->stars.ti_old_part = e->ti_current;
top2 = top2->parent;
}
top2->stars.ti_old_part = e->ti_current;
/* Release the lock */
if (lock_unlock(&top->stars.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
/* We now have an empty spart as the first particle in that cell */
struct spart *sp = &c->stars.parts[0];
bzero(sp, sizeof(struct spart));
/* Give it a decent position */
sp->x[0] = c->loc[0] + 0.5 * c->width[0];
sp->x[1] = c->loc[1] + 0.5 * c->width[1];
sp->x[2] = c->loc[2] + 0.5 * c->width[2];
/* Set it to the current time-bin */
sp->time_bin = e->min_active_bin;
#ifdef SWIFT_DEBUG_CHECKS
/* Specify it was drifted to this point */
sp->ti_drift = e->ti_current;
#endif
/* Give the new particle the correct depth */
cell_set_spart_h_depth(sp, c);
/* Register that we used one of the free slots. */
const size_t one = 1;
atomic_sub(&e->s->nr_extra_sparts, one);
return sp;
}
/**
* @brief "Add" a #sink in a given #cell.
*
* This function will add a #sink at the start of the current cell's array by
* shifting all the #sink in the top-level cell by one position. All the
* pointers and cell counts are updated accordingly.
*
* @param e The #engine.
* @param c The leaf-cell in which to add the #sink.
*
* @return A pointer to the newly added #sink. The sink has a been zeroed
* and given a position within the cell as well as set to the minimal active
* time bin.
*/
struct sink *cell_add_sink(struct engine *e, struct cell *const c) {
/* Perform some basic consitency checks */
if (c->nodeID != engine_rank) error("Adding sink on a foreign node");
if (c->sinks.ti_old_part != e->ti_current) error("Undrifted cell!");
if (c->split) error("Addition of sink performed above the leaf level");
/* Progeny number at each level */
int progeny[space_cell_maxdepth];
#ifdef SWIFT_DEBUG_CHECKS
for (int i = 0; i < space_cell_maxdepth; ++i) progeny[i] = -1;
#endif
/* Get the top-level this leaf cell is in and compute the progeny indices at
each level */
struct cell *top = c;
while (top->parent != NULL) {
/* What is the progeny index of the cell? */
for (int k = 0; k < 8; ++k) {
if (top->parent->progeny[k] == top) {
progeny[(int)top->parent->depth] = k;
}
}
/* Check that the cell was indeed drifted to this point to avoid future
* issues */
#ifdef SWIFT_DEBUG_CHECKS
if (top->hydro.super != NULL && top->sinks.count > 0 &&
top->sinks.ti_old_part != e->ti_current) {
error("Cell had not been correctly drifted before sink formation");
}
#endif
/* Climb up */
top = top->parent;
}
/* Lock the top-level cell as we are going to operate on it */
lock_lock(&top->sinks.sink_formation_lock);
/* Are there any extra particles left? */
if (top->sinks.count == top->sinks.count_total) {
error("We ran out of free sink particles!");
/* Release the local lock before exiting. */
if (lock_unlock(&top->sinks.sink_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
atomic_inc(&e->forcerebuild);
return NULL;
}
/* Number of particles to shift in order to get a free space. */
const size_t n_copy = &top->sinks.parts[top->sinks.count] - c->sinks.parts;
#ifdef SWIFT_DEBUG_CHECKS
if (c->sinks.parts + n_copy > top->sinks.parts + top->sinks.count)
error("Copying beyond the allowed range");
#endif
if (n_copy > 0) {
// MATTHIEU: This can be improved. We don't need to copy everything, just
// need to swap a few particles.
memmove(&c->sinks.parts[1], &c->sinks.parts[0],
n_copy * sizeof(struct sink));
/* Update the sink->gpart links (shift by 1) */
for (size_t i = 0; i < n_copy; ++i) {
// TODO: Matthieu figure out whether this is strictly needed
/* Skip inhibited (swallowed) sink particles */
if (sink_is_inhibited(&c->sinks.parts[i + 1], e)) continue;
#ifdef SWIFT_DEBUG_CHECKS
if (c->sinks.parts[i + 1].gpart == NULL) {
error("Incorrectly linked sink!");
}
#endif
c->sinks.parts[i + 1].gpart->id_or_neg_offset--;
}
}
/* Recursively shift all the sinks to get a free spot at the start of the
* current cell*/
cell_recursively_shift_sinks(top, progeny, /* main_branch=*/1);
/* Make sure the gravity will be recomputed for this particle in the next
* step
*/
struct cell *top2 = c;
while (top2->parent != NULL) {
top2->sinks.ti_old_part = e->ti_current;
top2 = top2->parent;
}
top2->sinks.ti_old_part = e->ti_current;
/* Release the lock */
if (lock_unlock(&top->sinks.sink_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
/* We now have an empty spart as the first particle in that cell */
struct sink *sp = &c->sinks.parts[0];
bzero(sp, sizeof(struct sink));
/* Give it a decent position */
sp->x[0] = c->loc[0] + 0.5 * c->width[0];
sp->x[1] = c->loc[1] + 0.5 * c->width[1];
sp->x[2] = c->loc[2] + 0.5 * c->width[2];
/* Set it to the current time-bin */
sp->time_bin = e->min_active_bin;
#ifdef SWIFT_DEBUG_CHECKS
/* Specify it was drifted to this point */
sp->ti_drift = e->ti_current;
#endif
/* Give the new particle the correct depth */
cell_set_sink_h_depth(sp, c);
/* Register that we used one of the free slots. */
const size_t one = 1;
atomic_sub(&e->s->nr_extra_sinks, one);
return sp;
}
/**
* @brief "Add" a #gpart in a given #cell.
*
* This function will add a #gpart at the start of the current cell's array by
* shifting all the #gpart in the top-level cell by one position. All the
* pointers and cell counts are updated accordingly.
*
* @param e The #engine.
* @param c The leaf-cell in which to add the #gpart.
*
* @return A pointer to the newly added #gpart. The gpart has a been zeroed
* and given a position within the cell as well as set to the minimal active
* time bin.
*/
struct gpart *cell_add_gpart(struct engine *e, struct cell *c) {
/* Perform some basic consitency checks */
if (c->nodeID != engine_rank) error("Adding gpart on a foreign node");
if (c->grav.ti_old_part != e->ti_current) error("Undrifted cell!");
if (c->split) error("Addition of gpart performed above the leaf level");
struct space *s = e->s;
/* Progeny number at each level */
int progeny[space_cell_maxdepth];
#ifdef SWIFT_DEBUG_CHECKS
for (int i = 0; i < space_cell_maxdepth; ++i) progeny[i] = -1;
#endif
/* Get the top-level this leaf cell is in and compute the progeny indices at
each level */
struct cell *top = c;
while (top->parent != NULL) {
/* What is the progeny index of the cell? */
for (int k = 0; k < 8; ++k) {
if (top->parent->progeny[k] == top) {
progeny[(int)top->parent->depth] = k;
}
}
/* Check that the cell was indeed drifted to this point to avoid future
* issues */
#ifdef SWIFT_DEBUG_CHECKS
if (top->grav.super != NULL && top->grav.count > 0 &&
top->grav.ti_old_part != e->ti_current) {
error("Cell had not been correctly drifted before adding a gpart");
}
#endif
/* Climb up */
top = top->parent;
}
/* Lock the top-level cell as we are going to operate on it */
lock_lock(&top->grav.star_formation_lock);
/* Are there any extra particles left? */
if (top->grav.count == top->grav.count_total) {
message("We ran out of free gravity particles!");
/* Release the local lock before exiting. */
if (lock_unlock(&top->grav.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
atomic_inc(&e->forcerebuild);
return NULL;
}
/* Number of particles to shift in order to get a free space. */
const size_t n_copy = &top->grav.parts[top->grav.count] - c->grav.parts;
#ifdef SWIFT_DEBUG_CHECKS
if (c->grav.parts + n_copy > top->grav.parts + top->grav.count)
error("Copying beyond the allowed range");
#endif
if (n_copy > 0) {
// MATTHIEU: This can be improved. We don't need to copy everything, just
// need to swap a few particles.
memmove(&c->grav.parts[1], &c->grav.parts[0],
n_copy * sizeof(struct gpart));
/* Update the gpart->spart links (shift by 1) */
struct gpart *gparts = c->grav.parts;
for (size_t i = 0; i < n_copy; ++i) {
/* Skip inhibited particles */
if (gpart_is_inhibited(&c->grav.parts[i + 1], e)) continue;
if (gparts[i + 1].type == swift_type_gas) {
s->parts[-gparts[i + 1].id_or_neg_offset].gpart++;
} else if (gparts[i + 1].type == swift_type_stars) {
s->sparts[-gparts[i + 1].id_or_neg_offset].gpart++;
} else if (gparts[i + 1].type == swift_type_sink) {
s->sinks[-gparts[i + 1].id_or_neg_offset].gpart++;
} else if (gparts[i + 1].type == swift_type_black_hole) {
s->bparts[-gparts[i + 1].id_or_neg_offset].gpart++;
}
}
}
/* Recursively shift all the gpart to get a free spot at the start of the
* current cell*/
cell_recursively_shift_gparts(top, progeny, /* main_branch=*/1);
/* Make sure the gravity will be recomputed for this particle in the next
* step
*/
struct cell *top2 = c;
while (top2->parent != NULL) {
top2->grav.ti_old_part = e->ti_current;
top2 = top2->parent;
}
top2->grav.ti_old_part = e->ti_current;
/* Release the lock */
if (lock_unlock(&top->grav.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
/* We now have an empty gpart as the first particle in that cell */
struct gpart *gp = &c->grav.parts[0];
bzero(gp, sizeof(struct gpart));
/* Give it a decent position */
gp->x[0] = c->loc[0] + 0.5 * c->width[0];
gp->x[1] = c->loc[1] + 0.5 * c->width[1];
gp->x[2] = c->loc[2] + 0.5 * c->width[2];
/* Set it to the current time-bin */
gp->time_bin = e->min_active_bin;
#ifdef SWIFT_DEBUG_CHECKS
/* Specify it was drifted to this point */
gp->ti_drift = e->ti_current;
#endif
/* Register that we used one of the free slots. */
const size_t one = 1;
atomic_sub(&e->s->nr_extra_gparts, one);
return gp;
}
/**
* @brief "Remove" a gas particle from the calculation.
*
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param p The #part to remove.
* @param xp The extended data of the particle to remove.
*/
void cell_remove_part(const struct engine *e, struct cell *c, struct part *p,
struct xpart *xp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
/* Don't remove a particle twice */
if (p->time_bin == time_bin_inhibited) return;
/* Mark the particle as inhibited */
p->time_bin = time_bin_inhibited;
/* Mark the RT time bin as inhibited as well,
* so part_is_rt_active() checks work as intended */
p->rt_time_data.time_bin = time_bin_inhibited;
/* Mark the gpart as inhibited and stand-alone */
if (p->gpart) {
p->gpart->time_bin = time_bin_inhibited;
p->gpart->id_or_neg_offset = 1;
p->gpart->type = swift_type_dark_matter;
}
/* Update the space-wide counters */
const size_t one = 1;
atomic_add(&e->s->nr_inhibited_parts, one);
if (p->gpart) {
atomic_add(&e->s->nr_inhibited_gparts, one);
}
/* Un-link the part */
p->gpart = NULL;
}
/**
* @brief "Remove" a gravity particle from the calculation.
*
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param gp The #gpart to remove.
*/
void cell_remove_gpart(const struct engine *e, struct cell *c,
struct gpart *gp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
/* Don't remove a particle twice */
if (gp->time_bin == time_bin_inhibited) return;
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
if (gp->type == swift_type_dark_matter_background)
error("Can't remove a DM background particle!");
/* Mark the particle as inhibited */
gp->time_bin = time_bin_inhibited;
/* Update the space-wide counters */
const size_t one = 1;
atomic_add(&e->s->nr_inhibited_gparts, one);
}
/**
* @brief "Remove" a star particle from the calculation.
*
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param sp The #spart to remove.
*/
void cell_remove_spart(const struct engine *e, struct cell *c,
struct spart *sp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
/* Don't remove a particle twice */
if (sp->time_bin == time_bin_inhibited) return;
/* Mark the particle as inhibited and stand-alone */
sp->time_bin = time_bin_inhibited;
if (sp->gpart) {
sp->gpart->time_bin = time_bin_inhibited;
sp->gpart->id_or_neg_offset = 1;
sp->gpart->type = swift_type_dark_matter;
}
/* Update the space-wide counters */
const size_t one = 1;
atomic_add(&e->s->nr_inhibited_sparts, one);
if (sp->gpart) {
atomic_add(&e->s->nr_inhibited_gparts, one);
}
/* Un-link the spart */
sp->gpart = NULL;
}
/**
* @brief "Remove" a black hole particle from the calculation.
*
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param bp The #bpart to remove.
*/
void cell_remove_bpart(const struct engine *e, struct cell *c,
struct bpart *bp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
/* Don't remove a particle twice */
if (bp->time_bin == time_bin_inhibited) return;
/* Mark the particle as inhibited and stand-alone */
bp->time_bin = time_bin_inhibited;
if (bp->gpart) {
bp->gpart->time_bin = time_bin_inhibited;
bp->gpart->id_or_neg_offset = 1;
bp->gpart->type = swift_type_dark_matter;
}
/* Update the space-wide counters */
const size_t one = 1;
atomic_add(&e->s->nr_inhibited_bparts, one);
if (bp->gpart) {
atomic_add(&e->s->nr_inhibited_gparts, one);
}
/* Un-link the bpart */
bp->gpart = NULL;
}
/**
* @brief "Remove" a sink particle from the calculation.
*
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param sp The #sink to remove.
*/
void cell_remove_sink(const struct engine *e, struct cell *c,
struct sink *sink) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
/* Don't remove a particle twice */
if (sink->time_bin == time_bin_inhibited) return;
/* Mark the particle as inhibited and stand-alone */
sink->time_bin = time_bin_inhibited;
if (sink->gpart) {
sink->gpart->time_bin = time_bin_inhibited;
sink->gpart->id_or_neg_offset = 1;
sink->gpart->type = swift_type_dark_matter;
}
/* Update the space-wide counters */
const size_t one = 1;
atomic_add(&e->s->nr_inhibited_sinks, one);
if (sink->gpart) {
atomic_add(&e->s->nr_inhibited_gparts, one);
}
/* Un-link the sink */
sink->gpart = NULL;
}
/**
* @brief "Remove" a gas particle from the calculation and convert its gpart
* friend to a dark matter particle.
*
* Note that the #part is not destroyed. The pointer is still valid
* after this call and the properties of the #part are not altered
* apart from the time-bin and #gpart pointer.
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param p The #part to remove.
* @param xp The extended data of the particle to remove.
*
* @return Pointer to the #gpart the #part has become. It carries the
* ID of the #part and has a dark matter type.
*/
struct gpart *cell_convert_part_to_gpart(const struct engine *e, struct cell *c,
struct part *p, struct xpart *xp) {
/* Quick cross-checks */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
if (p->gpart == NULL)
error("Trying to convert part without gpart friend to dark matter!");
/* Get a handle */
struct gpart *gp = p->gpart;
/* Mark the particle as inhibited */
p->time_bin = time_bin_inhibited;
/* Un-link the part */
p->gpart = NULL;
/* Mark the gpart as dark matter */
gp->type = swift_type_dark_matter;
gp->id_or_neg_offset = p->id;
#ifdef SWIFT_DEBUG_CHECKS
gp->ti_kick = p->ti_kick;
#endif
/* Update the space-wide counters */
atomic_inc(&e->s->nr_inhibited_parts);
return gp;
}
/**
* @brief "Remove" a spart particle from the calculation and convert its gpart
* friend to a dark matter particle.
*
* Note that the #spart is not destroyed. The pointer is still valid
* after this call and the properties of the #spart are not altered
* apart from the time-bin and #gpart pointer.
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine running on this node.
* @param c The #cell from which to remove the particle.
* @param sp The #spart to remove.
*
* @return Pointer to the #gpart the #spart has become. It carries the
* ID of the #spart and has a dark matter type.
*/
struct gpart *cell_convert_spart_to_gpart(const struct engine *e,
struct cell *c, struct spart *sp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
if (sp->gpart == NULL)
error("Trying to convert spart without gpart friend to dark matter!");
/* Get a handle */
struct gpart *gp = sp->gpart;
/* Mark the particle as inhibited */
sp->time_bin = time_bin_inhibited;
/* Un-link the spart */
sp->gpart = NULL;
/* Mark the gpart as dark matter */
gp->type = swift_type_dark_matter;
gp->id_or_neg_offset = sp->id;
#ifdef SWIFT_DEBUG_CHECKS
gp->ti_kick = sp->ti_kick;
#endif
/* Update the space-wide counters */
atomic_inc(&e->s->nr_inhibited_sparts);
return gp;
}
/**
* @brief "Remove" a #part from a #cell and replace it with a #spart
* connected to the same #gpart.
*
* Note that the #part is not destroyed. The pointer is still valid
* after this call and the properties of the #part are not altered
* apart from the time-bin and #gpart pointer.
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine.
* @param c The #cell from which to remove the #part.
* @param p The #part to remove (must be inside c).
* @param xp The extended data of the #part.
*
* @return A fresh #spart with the same ID, position, velocity and
* time-bin as the original #part.
*/
struct spart *cell_convert_part_to_spart(struct engine *e, struct cell *c,
struct part *p, struct xpart *xp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
if (p->gpart == NULL)
error("Trying to convert part without gpart friend to star!");
/* Create a fresh (empty) spart */
struct spart *sp = cell_add_spart(e, c);
/* Did we run out of free spart slots? */
if (sp == NULL) return NULL;
/* Copy over the distance since rebuild */
sp->x_diff[0] = xp->x_diff[0];
sp->x_diff[1] = xp->x_diff[1];
sp->x_diff[2] = xp->x_diff[2];
/* Destroy the gas particle and get it's gpart friend */
struct gpart *gp = cell_convert_part_to_gpart(e, c, p, xp);
/* Assign the ID back */
sp->id = gp->id_or_neg_offset;
gp->type = swift_type_stars;
/* Re-link things */
sp->gpart = gp;
gp->id_or_neg_offset = -(sp - e->s->sparts);
/* Synchronize clocks */
gp->time_bin = sp->time_bin;
/* Synchronize masses, positions and velocities */
sp->mass = gp->mass;
sp->x[0] = gp->x[0];
sp->x[1] = gp->x[1];
sp->x[2] = gp->x[2];
sp->v[0] = gp->v_full[0];
sp->v[1] = gp->v_full[1];
sp->v[2] = gp->v_full[2];
#ifdef SWIFT_DEBUG_CHECKS
sp->ti_kick = gp->ti_kick;
gp->ti_drift = sp->ti_drift;
#endif
/* Set a smoothing length */
sp->h = p->h;
/* Give the new particle the correct depth */
cell_set_spart_h_depth(sp, c);
/* Here comes the Sun! */
return sp;
}
/**
* @brief Add a new #spart based on a #part and link it to a new #gpart.
* The part and xpart are not changed.
*
* @param e The #engine.
* @param c The #cell from which to remove the #part.
* @param p The #part to remove (must be inside c).
* @param xp The extended data of the #part.
*
* @return A fresh #spart with a different ID, but same position,
* velocity and time-bin as the original #part.
*/
struct spart *cell_spawn_new_spart_from_part(struct engine *e, struct cell *c,
const struct part *p,
const struct xpart *xp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't spawn a particle in a foreign cell.");
if (p->gpart == NULL)
error("Trying to create a new spart from a part without gpart friend!");
/* Create a fresh (empty) spart */
struct spart *sp = cell_add_spart(e, c);
/* Did we run out of free spart slots? */
if (sp == NULL) return NULL;
/* Copy over the distance since rebuild */
sp->x_diff[0] = xp->x_diff[0];
sp->x_diff[1] = xp->x_diff[1];
sp->x_diff[2] = xp->x_diff[2];
/* Create a new gpart */
struct gpart *gp = cell_add_gpart(e, c);
/* Did we run out of free gpart slots? */
if (gp == NULL) {
/* Remove the particle created */
cell_remove_spart(e, c, sp);
return NULL;
}
/* Copy the gpart */
*gp = *p->gpart;
/* Assign the ID. */
sp->id = space_get_new_unique_id(e->s);
gp->type = swift_type_stars;
/* Re-link things */
sp->gpart = gp;
gp->id_or_neg_offset = -(sp - e->s->sparts);
/* Synchronize clocks */
gp->time_bin = sp->time_bin;
/* Synchronize masses, positions and velocities */
sp->mass = hydro_get_mass(p);
sp->x[0] = p->x[0];
sp->x[1] = p->x[1];
sp->x[2] = p->x[2];
sp->v[0] = xp->v_full[0];
sp->v[1] = xp->v_full[1];
sp->v[2] = xp->v_full[2];
#ifdef SWIFT_DEBUG_CHECKS
sp->ti_kick = p->ti_kick;
sp->ti_drift = p->ti_drift;
#endif
/* Set a smoothing length */
sp->h = p->h;
/* Give the new particle the correct depth */
cell_set_spart_h_depth(sp, c);
/* Here comes the Sun! */
return sp;
}
/**
* @brief "Remove" a #part from a #cell and replace it with a #sink
* connected to the same #gpart.
*
* Note that the #part is not destroyed. The pointer is still valid
* after this call and the properties of the #part are not altered
* apart from the time-bin and #gpart pointer.
* The particle is inhibited and will officially be removed at the next
* rebuild.
*
* @param e The #engine.
* @param c The #cell from which to remove the #part.
* @param p The #part to remove (must be inside c).
* @param xp The extended data of the #part.
*
* @return A fresh #sink with the same ID, position, velocity and
* time-bin as the original #part.
*/
struct sink *cell_convert_part_to_sink(struct engine *e, struct cell *c,
struct part *p, struct xpart *xp) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't remove a particle in a foreign cell.");
if (p->gpart == NULL)
error("Trying to convert part without gpart friend to sink!");
/* Create a fresh (empty) sink */
struct sink *sp = cell_add_sink(e, c);
/* Did we run out of free sink slots? */
if (sp == NULL) return NULL;
/* Copy over the distance since rebuild */
sp->x_diff[0] = xp->x_diff[0];
sp->x_diff[1] = xp->x_diff[1];
sp->x_diff[2] = xp->x_diff[2];
/* Destroy the gas particle and get it's gpart friend */
struct gpart *gp = cell_convert_part_to_gpart(e, c, p, xp);
/* Assign the ID back */
sp->id = p->id;
gp->type = swift_type_sink;
/* Re-link things */
sp->gpart = gp;
gp->id_or_neg_offset = -(sp - e->s->sinks);
/* Synchronize clocks */
gp->time_bin = sp->time_bin;
/* Synchronize masses, positions and velocities */
sp->mass = gp->mass;
sp->x[0] = gp->x[0];
sp->x[1] = gp->x[1];
sp->x[2] = gp->x[2];
sp->v[0] = gp->v_full[0];
sp->v[1] = gp->v_full[1];
sp->v[2] = gp->v_full[2];
#ifdef SWIFT_DEBUG_CHECKS
sp->ti_kick = gp->ti_kick;
gp->ti_drift = sp->ti_drift;
message("A new sink (%lld) is born !", sp->id);
#endif
/* Here comes the Sink! */
return sp;
}
/**
* @brief Spawn a new #spart along with its related #gpart from a #sink.
* The sink is not changed.
*
* @param e The #engine.
* @param c The #cell from which to remove the #part.
* @param s The #sink particle that spawns the #spart.
*
* @return A fresh #spart with a different ID, but same position,
* velocity and time-bin as the original #sink.
*/
struct spart *cell_spawn_new_spart_from_sink(struct engine *e, struct cell *c,
const struct sink *s) {
/* Quick cross-check */
if (c->nodeID != e->nodeID)
error("Can't spawn a particle in a foreign cell.");
if (s->gpart == NULL)
error("Trying to create a new spart from a part without gpart friend!");
/* Create a fresh (empty) spart */
struct spart *sp = cell_add_spart(e, c);
/* Did we run out of free spart slots? */
if (sp == NULL) return NULL;
/* Copy over the distance since rebuild */
sp->x_diff[0] = s->x_diff[0];
sp->x_diff[1] = s->x_diff[1];
sp->x_diff[2] = s->x_diff[2];
/* Create a new gpart */
struct gpart *gp = cell_add_gpart(e, c);
/* Did we run out of free gpart slots? */
if (gp == NULL) {
/* Remove the particle created */
cell_remove_spart(e, c, sp);
return NULL;
}
/* Copy the gpart */
*gp = *s->gpart;
/* Assign the ID. */
sp->id = space_get_new_unique_id(e->s);
gp->type = swift_type_stars;
/* Re-link things */
sp->gpart = gp;
gp->id_or_neg_offset = -(sp - e->s->sparts);
/* Synchronize clocks */
gp->time_bin = sp->time_bin;
/* Synchronize masses, positions and velocities */
sp->mass = s->mass;
sp->x[0] = s->x[0];
sp->x[1] = s->x[1];
sp->x[2] = s->x[2];
sp->v[0] = s->v[0];
sp->v[1] = s->v[1];
sp->v[2] = s->v[2];
#ifdef SWIFT_DEBUG_CHECKS
sp->ti_kick = s->ti_kick;
sp->ti_drift = s->ti_drift;
#endif
/* Set a smoothing length */
sp->h = s->h;
/* Give the new particle the correct depth */
cell_set_spart_h_depth(sp, c);
/* Here comes the Sun! */
return sp;
}