/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2021 John Helly (j.c.helly@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 .
*
******************************************************************************/
#include "lightcone/lightcone_replications.h"
#include "align.h"
#include "cell.h"
#include "error.h"
#include "memuse.h"
#include
#include
#include
/**
* @brief Comparison function for sorting replications
*
* a The first replication
* b The second replication
*
*/
static int compare_replication_rmin(const void *a, const void *b) {
const struct replication *rep_a = (struct replication *)a;
const struct replication *rep_b = (struct replication *)b;
if (rep_a->rmin2 < rep_b->rmin2)
return -1;
else if (rep_a->rmin2 > rep_b->rmin2)
return 1;
else
return 0;
}
/**
* @brief Make a list of periodic box replications which overlap
* the specified distance range from an observer.
*
* @param boxsize Size of the cubic simulation box.
* @param observer_position Location of the observer.
* @param lightcone_rmin Minimum distance from the observer.
* @param lightcone_rmax Maximum distance from the observer.
* of particles.
* @param replication_list Pointer to the struct to initialise.
*/
void replication_list_init(struct replication_list *replication_list,
double boxsize, double cell_width,
double observer_position[3], double lightcone_rmin,
double lightcone_rmax) {
/* Find range of replications to examine in each dimension */
int rep_min[3];
int rep_max[3];
for (int i = 0; i < 3; i += 1) {
rep_min[i] = (int)floor(
(observer_position[i] - lightcone_rmax - 0.5 * cell_width) / boxsize);
rep_max[i] = (int)floor(
(observer_position[i] + lightcone_rmax + 0.5 * cell_width) / boxsize);
}
/* On first pass just count replications */
for (int ipass = 0; ipass < 2; ipass += 1) {
replication_list->nrep = 0;
/* Loop over periodic replications */
for (int i = rep_min[0]; i <= rep_max[0]; i += 1) {
for (int j = rep_min[1]; j <= rep_max[1]; j += 1) {
for (int k = rep_min[2]; k <= rep_max[2]; k += 1) {
/* Find centre of this replication relative to observer */
double cx = boxsize * i + 0.5 * boxsize - observer_position[0];
double cy = boxsize * j + 0.5 * boxsize - observer_position[1];
double cz = boxsize * k + 0.5 * boxsize - observer_position[2];
/* Find distance to closest possible particle in this replication */
double dx, dy, dz;
dx = fabs(cx) - 0.5 * boxsize - 0.5 * cell_width;
if (dx < 0) dx = 0;
dy = fabs(cy) - 0.5 * boxsize - 0.5 * cell_width;
if (dy < 0) dy = 0;
dz = fabs(cz) - 0.5 * boxsize - 0.5 * cell_width;
if (dz < 0) dz = 0;
double rep_rmin = sqrt(dx * dx + dy * dy + dz * dz);
/* Find distance to most distant possible particle in this replication
*/
dx = fabs(cx) + 0.5 * boxsize + 0.5 * cell_width;
dy = fabs(cy) + 0.5 * boxsize + 0.5 * cell_width;
dz = fabs(cz) + 0.5 * boxsize + 0.5 * cell_width;
double rep_rmax = sqrt(dx * dx + dy * dy + dz * dz);
/* Flag if any point in this replication could be in the lightcone */
int in_lightcone = 1;
/* Check distance limits */
if (rep_rmax < lightcone_rmin || rep_rmin > lightcone_rmax)
in_lightcone = 0;
if (in_lightcone) {
/* Store replications on second pass */
if (ipass == 1) {
/* Get a pointer to the next replication */
const int nrep = replication_list->nrep;
struct replication *rep = replication_list->replication + nrep;
/* Store info about this replication */
rep->rmin2 = pow(rep_rmin, 2.0);
rep->rmax2 = pow(rep_rmax, 2.0);
rep->coord[0] = i * boxsize;
rep->coord[1] = j * boxsize;
rep->coord[2] = k * boxsize;
}
replication_list->nrep += 1;
}
} /* Next replication in z */
} /* Next replication in y */
} /* Next replication in x */
/* Allocate storage after first pass */
if (ipass == 0) {
const int nrep = replication_list->nrep;
if (swift_memalign(
"lightcone_replications", (void **)&replication_list->replication,
SWIFT_STRUCT_ALIGNMENT, sizeof(struct replication) * nrep) != 0) {
error("Failed to allocate lightcone replication list");
}
}
} /* Next pass */
/* Now sort replications by minimum distance */
qsort(replication_list->replication, (size_t)replication_list->nrep,
sizeof(struct replication), compare_replication_rmin);
/* Record the distance limits we used - may need these to refine the list
* later */
replication_list->lightcone_rmin = lightcone_rmin;
replication_list->lightcone_rmax = lightcone_rmax;
}
/**
* @brief Make an empty replication list
*
* @param replication_list Pointer to the struct to initialise.
*/
void replication_list_init_empty(struct replication_list *replication_list) {
const int nrep = 0;
if (swift_memalign(
"lightcone_replications", (void **)&replication_list->replication,
SWIFT_STRUCT_ALIGNMENT, sizeof(struct replication) * nrep) != 0) {
error("Failed to allocate lightcone replication list");
}
replication_list->lightcone_rmin = 0.0;
replication_list->lightcone_rmax = 0.0;
replication_list->nrep = 0;
}
/**
* @brief Deallocate a replication list
*
* @param replication_list Pointer to the struct to deallocate.
*/
void replication_list_clean(struct replication_list *replication_list) {
swift_free("lightcone_replications", replication_list->replication);
replication_list->replication = NULL;
replication_list->nrep = 0;
}
/**
* @brief Write a replication list to a file as text
*
* @param replication_list The replication list
* @param fd The file to write to
*/
void replication_list_write(struct replication_list *replication_list,
FILE *fd) {
for (int i = 0; i < replication_list->nrep; i += 1) {
fprintf(fd, "%e, %e, %e, %e, %e\n",
replication_list->replication[i].coord[0],
replication_list->replication[i].coord[1],
replication_list->replication[i].coord[2],
sqrt(replication_list->replication[i].rmin2),
sqrt(replication_list->replication[i].rmax2));
}
}
/**
* Determine subset of replications which overlap a #cell
*
* @param rep_in The input replication list
* @param cell The input cell
* @param rep_out The output replication list
*
* Initializes rep_out, which must then be freed with
* replication_list_clean().
*
*/
void replication_list_subset_for_cell(const struct replication_list *rep_in,
const struct cell *cell,
const double observer_position[3],
struct replication_list *rep_out) {
/* Find centre coordinates of this cell */
const double cell_centre[] = {cell->loc[0] + 0.5 * cell->width[0],
cell->loc[1] + 0.5 * cell->width[1],
cell->loc[2] + 0.5 * cell->width[2]};
/* Find 'effective' width of this cell - particles can wander out of the cell
* by up to half a cell width */
const double cell_eff_width[] = {2.0 * cell->width[0], 2.0 * cell->width[1],
2.0 * cell->width[2]};
/* Allocate array of replications for the new list */
const int nrep_max = rep_in->nrep;
if (swift_memalign("lightcone_replications", (void **)&rep_out->replication,
SWIFT_STRUCT_ALIGNMENT,
sizeof(struct replication) * nrep_max) != 0) {
error("Failed to allocate pruned lightcone replication list");
}
/* Get distance limits (squared) used to make the input list */
const double lightcone_rmin2 = pow(rep_in->lightcone_rmin, 2.0);
const double lightcone_rmax2 = pow(rep_in->lightcone_rmax, 2.0);
/* Loop over all replications */
rep_out->nrep = 0;
for (int i = 0; i < nrep_max; i += 1) {
/* Get a pointer to this input replication */
const struct replication *rep = rep_in->replication + i;
/* Find coordinates of centre of this replication of the cell relative to
* the observer */
double cell_rep_centre[3];
for (int j = 0; j < 3; j += 1) {
cell_rep_centre[j] =
rep->coord[j] + cell_centre[j] - observer_position[j];
}
/* Compute minimum possible distance squared from observer to this
* replication of this cell */
double cell_rmin2 = 0.0;
for (int j = 0; j < 3; j += 1) {
double dx = fabs(cell_rep_centre[j]) - 0.5 * cell_eff_width[j];
if (dx < 0.0) dx = 0.0;
cell_rmin2 += dx * dx;
}
/* Compute maximum possible distance squared from observer to this
* replication of this cell */
double cell_rmax2 = 0.0;
for (int j = 0; j < 3; j += 1) {
double dx = fabs(cell_rep_centre[j]) + 0.5 * cell_eff_width[j];
cell_rmax2 += dx * dx;
}
/* Decide whether this cell could contribute to this replication */
if (cell_rmax2 >= lightcone_rmin2 && cell_rmin2 <= lightcone_rmax2) {
memcpy(rep_out->replication + rep_out->nrep, rep,
sizeof(struct replication));
rep_out->nrep += 1;
}
/* Next input replication */
}
/* Not used currently */
rep_out->lightcone_rmin = rep_in->lightcone_rmin;
rep_out->lightcone_rmax = rep_in->lightcone_rmax;
}