/*******************************************************************************
* 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 "error.h"
#include "memswap.h"
#include "memuse.h"
#include "space.h"
/**
* @brief Sort the particles and condensed particles according to the given
* indices.
*
* @param parts The array of #part to sort.
* @param xparts The corresponding #xpart array to sort as well.
* @param ind The indices with respect to which the parts are sorted.
* @param counts Number of particles per index.
* @param num_bins Total number of bins (length of count).
* @param parts_offset Offset of the #part array from the global #part array.
*/
void space_parts_sort(struct part *parts, struct xpart *xparts,
int *restrict ind, int *restrict counts, int num_bins,
ptrdiff_t parts_offset) {
/* Create the offsets array. */
size_t *offsets = NULL;
if (swift_memalign("parts_offsets", (void **)&offsets, SWIFT_STRUCT_ALIGNMENT,
sizeof(size_t) * (num_bins + 1)) != 0)
error("Failed to allocate temporary cell offsets array.");
offsets[0] = 0;
for (int k = 1; k <= num_bins; k++) {
offsets[k] = offsets[k - 1] + counts[k - 1];
counts[k - 1] = 0;
}
/* Loop over local cells. */
for (int cid = 0; cid < num_bins; cid++) {
for (size_t k = offsets[cid] + counts[cid]; k < offsets[cid + 1]; k++) {
counts[cid]++;
int target_cid = ind[k];
if (target_cid == cid) {
continue;
}
struct part temp_part = parts[k];
struct xpart temp_xpart = xparts[k];
while (target_cid != cid) {
size_t j = offsets[target_cid] + counts[target_cid]++;
while (ind[j] == target_cid) {
j = offsets[target_cid] + counts[target_cid]++;
}
memswap(&parts[j], &temp_part, sizeof(struct part));
memswap(&xparts[j], &temp_xpart, sizeof(struct xpart));
memswap(&ind[j], &target_cid, sizeof(int));
if (parts[j].gpart)
parts[j].gpart->id_or_neg_offset = -(j + parts_offset);
}
parts[k] = temp_part;
xparts[k] = temp_xpart;
ind[k] = target_cid;
if (parts[k].gpart)
parts[k].gpart->id_or_neg_offset = -(k + parts_offset);
}
}
#ifdef SWIFT_DEBUG_CHECKS
for (int k = 0; k < num_bins; k++)
if (offsets[k + 1] != offsets[k] + counts[k])
error("Bad offsets after shuffle.");
#endif /* SWIFT_DEBUG_CHECKS */
swift_free("parts_offsets", offsets);
}
/**
* @brief Sort the s-particles according to the given indices.
*
* @param sparts The array of #spart to sort.
* @param ind The indices with respect to which the #spart are sorted.
* @param counts Number of particles per index.
* @param num_bins Total number of bins (length of counts).
* @param sparts_offset Offset of the #spart array from the global #spart.
* array.
*/
void space_sparts_sort(struct spart *sparts, int *restrict ind,
int *restrict counts, int num_bins,
ptrdiff_t sparts_offset) {
/* Create the offsets array. */
size_t *offsets = NULL;
if (swift_memalign("sparts_offsets", (void **)&offsets,
SWIFT_STRUCT_ALIGNMENT,
sizeof(size_t) * (num_bins + 1)) != 0)
error("Failed to allocate temporary cell offsets array.");
offsets[0] = 0;
for (int k = 1; k <= num_bins; k++) {
offsets[k] = offsets[k - 1] + counts[k - 1];
counts[k - 1] = 0;
}
/* Loop over local cells. */
for (int cid = 0; cid < num_bins; cid++) {
for (size_t k = offsets[cid] + counts[cid]; k < offsets[cid + 1]; k++) {
counts[cid]++;
int target_cid = ind[k];
if (target_cid == cid) {
continue;
}
struct spart temp_spart = sparts[k];
while (target_cid != cid) {
size_t j = offsets[target_cid] + counts[target_cid]++;
while (ind[j] == target_cid) {
j = offsets[target_cid] + counts[target_cid]++;
}
memswap(&sparts[j], &temp_spart, sizeof(struct spart));
memswap(&ind[j], &target_cid, sizeof(int));
if (sparts[j].gpart)
sparts[j].gpart->id_or_neg_offset = -(j + sparts_offset);
}
sparts[k] = temp_spart;
ind[k] = target_cid;
if (sparts[k].gpart)
sparts[k].gpart->id_or_neg_offset = -(k + sparts_offset);
}
}
#ifdef SWIFT_DEBUG_CHECKS
for (int k = 0; k < num_bins; k++)
if (offsets[k + 1] != offsets[k] + counts[k])
error("Bad offsets after shuffle.");
#endif /* SWIFT_DEBUG_CHECKS */
swift_free("sparts_offsets", offsets);
}
/**
* @brief Sort the b-particles according to the given indices.
*
* @param bparts The array of #bpart to sort.
* @param ind The indices with respect to which the #bpart are sorted.
* @param counts Number of particles per index.
* @param num_bins Total number of bins (length of counts).
* @param bparts_offset Offset of the #bpart array from the global #bpart.
* array.
*/
void space_bparts_sort(struct bpart *bparts, int *restrict ind,
int *restrict counts, int num_bins,
ptrdiff_t bparts_offset) {
/* Create the offsets array. */
size_t *offsets = NULL;
if (swift_memalign("bparts_offsets", (void **)&offsets,
SWIFT_STRUCT_ALIGNMENT,
sizeof(size_t) * (num_bins + 1)) != 0)
error("Failed to allocate temporary cell offsets array.");
offsets[0] = 0;
for (int k = 1; k <= num_bins; k++) {
offsets[k] = offsets[k - 1] + counts[k - 1];
counts[k - 1] = 0;
}
/* Loop over local cells. */
for (int cid = 0; cid < num_bins; cid++) {
for (size_t k = offsets[cid] + counts[cid]; k < offsets[cid + 1]; k++) {
counts[cid]++;
int target_cid = ind[k];
if (target_cid == cid) {
continue;
}
struct bpart temp_bpart = bparts[k];
while (target_cid != cid) {
size_t j = offsets[target_cid] + counts[target_cid]++;
while (ind[j] == target_cid) {
j = offsets[target_cid] + counts[target_cid]++;
}
memswap(&bparts[j], &temp_bpart, sizeof(struct bpart));
memswap(&ind[j], &target_cid, sizeof(int));
if (bparts[j].gpart)
bparts[j].gpart->id_or_neg_offset = -(j + bparts_offset);
}
bparts[k] = temp_bpart;
ind[k] = target_cid;
if (bparts[k].gpart)
bparts[k].gpart->id_or_neg_offset = -(k + bparts_offset);
}
}
#ifdef SWIFT_DEBUG_CHECKS
for (int k = 0; k < num_bins; k++)
if (offsets[k + 1] != offsets[k] + counts[k])
error("Bad offsets after shuffle.");
#endif /* SWIFT_DEBUG_CHECKS */
swift_free("bparts_offsets", offsets);
}
/**
* @brief Sort the sink-particles according to the given indices.
*
* @param sinks The array of #sink to sort.
* @param ind The indices with respect to which the #sink are sorted.
* @param counts Number of particles per index.
* @param num_bins Total number of bins (length of counts).
* @param sinks_offset Offset of the #sink array from the global #sink.
* array.
*/
void space_sinks_sort(struct sink *sinks, int *restrict ind,
int *restrict counts, int num_bins,
ptrdiff_t sinks_offset) {
/* Create the offsets array. */
size_t *offsets = NULL;
if (swift_memalign("sinks_offsets", (void **)&offsets, SWIFT_STRUCT_ALIGNMENT,
sizeof(size_t) * (num_bins + 1)) != 0)
error("Failed to allocate temporary cell offsets array.");
offsets[0] = 0;
for (int k = 1; k <= num_bins; k++) {
offsets[k] = offsets[k - 1] + counts[k - 1];
counts[k - 1] = 0;
}
/* Loop over local cells. */
for (int cid = 0; cid < num_bins; cid++) {
for (size_t k = offsets[cid] + counts[cid]; k < offsets[cid + 1]; k++) {
counts[cid]++;
int target_cid = ind[k];
if (target_cid == cid) {
continue;
}
struct sink temp_sink = sinks[k];
while (target_cid != cid) {
size_t j = offsets[target_cid] + counts[target_cid]++;
while (ind[j] == target_cid) {
j = offsets[target_cid] + counts[target_cid]++;
}
memswap(&sinks[j], &temp_sink, sizeof(struct sink));
memswap(&ind[j], &target_cid, sizeof(int));
if (sinks[j].gpart)
sinks[j].gpart->id_or_neg_offset = -(j + sinks_offset);
}
sinks[k] = temp_sink;
ind[k] = target_cid;
if (sinks[k].gpart)
sinks[k].gpart->id_or_neg_offset = -(k + sinks_offset);
}
}
#ifdef SWIFT_DEBUG_CHECKS
for (int k = 0; k < num_bins; k++)
if (offsets[k + 1] != offsets[k] + counts[k])
error("Bad offsets after shuffle.");
#endif /* SWIFT_DEBUG_CHECKS */
swift_free("sinks_offsets", offsets);
}
/**
* @brief Sort the g-particles according to the given indices.
*
* @param gparts The array of #gpart to sort.
* @param parts Global #part array for re-linking.
* @param sinks Global #sink array for re-linking.
* @param sparts Global #spart array for re-linking.
* @param bparts Global #bpart array for re-linking.
* @param ind The indices with respect to which the gparts are sorted.
* @param counts Number of particles per index.
* @param num_bins Total number of bins (length of counts).
*/
void space_gparts_sort(struct gpart *gparts, struct part *parts,
struct sink *sinks, struct spart *sparts,
struct bpart *bparts, int *restrict ind,
int *restrict counts, int num_bins) {
/* Create the offsets array. */
size_t *offsets = NULL;
if (swift_memalign("gparts_offsets", (void **)&offsets,
SWIFT_STRUCT_ALIGNMENT,
sizeof(size_t) * (num_bins + 1)) != 0)
error("Failed to allocate temporary cell offsets array.");
offsets[0] = 0;
for (int k = 1; k <= num_bins; k++) {
offsets[k] = offsets[k - 1] + counts[k - 1];
counts[k - 1] = 0;
}
/* Loop over local cells. */
for (int cid = 0; cid < num_bins; cid++) {
for (size_t k = offsets[cid] + counts[cid]; k < offsets[cid + 1]; k++) {
counts[cid]++;
int target_cid = ind[k];
if (target_cid == cid) {
continue;
}
struct gpart temp_gpart = gparts[k];
while (target_cid != cid) {
size_t j = offsets[target_cid] + counts[target_cid]++;
while (ind[j] == target_cid) {
j = offsets[target_cid] + counts[target_cid]++;
}
memswap_unaligned(&gparts[j], &temp_gpart, sizeof(struct gpart));
memswap(&ind[j], &target_cid, sizeof(int));
if (gparts[j].type == swift_type_gas) {
parts[-gparts[j].id_or_neg_offset].gpart = &gparts[j];
} else if (gparts[j].type == swift_type_stars) {
sparts[-gparts[j].id_or_neg_offset].gpart = &gparts[j];
} else if (gparts[j].type == swift_type_black_hole) {
bparts[-gparts[j].id_or_neg_offset].gpart = &gparts[j];
} else if (gparts[j].type == swift_type_sink) {
sinks[-gparts[j].id_or_neg_offset].gpart = &gparts[j];
}
}
gparts[k] = temp_gpart;
ind[k] = target_cid;
if (gparts[k].type == swift_type_gas) {
parts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
} else if (gparts[k].type == swift_type_stars) {
sparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
} else if (gparts[k].type == swift_type_black_hole) {
bparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
} else if (gparts[k].type == swift_type_sink) {
sinks[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
}
}
}
#ifdef SWIFT_DEBUG_CHECKS
for (int k = 0; k < num_bins; k++)
if (offsets[k + 1] != offsets[k] + counts[k])
error("Bad offsets after shuffle.");
#endif /* SWIFT_DEBUG_CHECKS */
swift_free("gparts_offsets", offsets);
}