/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
* Matthieu Schaller (schaller@strw.leidenuniv.nl)
* Copyright (c) 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
/* Some standard headers. */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* This object's header. */
#include "tools.h"
/* Local includes. */
#include "active.h"
#include "adaptive_softening.h"
#include "cell.h"
#include "chemistry.h"
#include "cosmology.h"
#include "error.h"
#include "feedback.h"
#include "gravity.h"
#include "hydro.h"
#include "mhd.h"
#include "part.h"
#include "periodic.h"
#include "pressure_floor_iact.h"
#include "runner.h"
#include "sink_iact.h"
#include "sink_properties.h"
#include "star_formation_iact.h"
#include "stars.h"
/**
* Factorize a given integer, attempts to keep larger pair of factors.
*/
void factor(int value, int *f1, int *f2) {
int j;
int i;
j = (int)sqrt(value);
for (i = j; i > 0; i--) {
if ((value % i) == 0) {
*f1 = i;
*f2 = value / i;
break;
}
}
}
/**
* @brief Compute the average number of pairs per particle using
* a brute-force O(N^2) computation.
*
* @param dim The space dimensions.
* @param parts The #part array.
* @param N The number of parts.
* @param periodic Periodic boundary conditions flag.
*/
void pairs_n2(double *dim, struct part *restrict parts, int N, int periodic) {
int i, j, k, count = 0;
// int mj, mk;
// double maxratio = 1.0;
double r2, rho = 0.0;
double rho_max = 0.0, rho_min = 100;
float a = 1.f, H = 0.f;
float dx[3];
/* Loop over all particle pairs. */
for (j = 0; j < N; j++) {
if (j % 1000 == 0) {
printf("pairs_n2: j=%i.\n", j);
fflush(stdout);
}
for (k = j + 1; k < N; k++) {
for (i = 0; i < 3; i++) {
dx[i] = parts[j].x[i] - parts[k].x[i];
if (periodic) {
if (dx[i] < -dim[i] / 2)
dx[i] += dim[i];
else if (dx[i] > dim[i] / 2)
dx[i] -= dim[i];
}
}
r2 = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2];
if (r2 < parts[j].h * parts[j].h || r2 < parts[k].h * parts[k].h) {
runner_iact_density(r2, dx, parts[j].h, parts[k].h, &parts[j],
&parts[k], a, H);
/* if ( parts[j].h / parts[k].h > maxratio )
{
maxratio = parts[j].h / parts[k].h;
mj = j; mk = k;
}
else if ( parts[k].h / parts[j].h > maxratio )
{
maxratio = parts[k].h / parts[j].h;
mj = j; mk = k;
} */
}
}
}
/* Aggregate the results. */
for (k = 0; k < N; k++) {
// count += parts[k].icount;
rho += parts[k].density.wcount;
rho_min = fmin(parts[k].density.wcount, rho_min);
rho_min = fmax(parts[k].density.wcount, rho_max);
}
/* Dump the result. */
printf("pairs_n2: avg. density per part is %.3f (nr. pairs %.3f).\n",
rho / N + 32.0 / 3, ((double)count) / N);
printf("pairs_n2: densities are in [ %e , %e ].\n", rho_min / N + 32.0 / 3,
rho_max / N + 32.0 / 3);
/* printf( "pairs_n2: maximum ratio between parts %i [%e,%e,%e] and %i
[%e,%e,%e] is %.3f/%.3f\n" ,
mj , parts[mj].x[0] , parts[mj].x[1] , parts[mj].x[2] ,
mk , parts[mk].x[0] , parts[mk].x[1] , parts[mk].x[2] ,
parts[mj].h , parts[mk].h ); fflush(stdout); */
fflush(stdout);
}
void pairs_single_density(double *dim, long long int pid,
struct part *restrict parts, int N, int periodic) {
const float a = 1.f;
const float H = 0.f;
/* Find "our" part. */
int k;
for (k = 0; k < N && parts[k].id != pid; k++) {
/* Nothing to do here */
}
/* Clear accumulators. */
if (k == N) error("Part not found.");
struct part p = parts[k];
printf("pairs_single: part[%i].id == %lli.\n", k, pid);
hydro_init_part(&p, NULL);
adaptive_softening_init_part(&p);
mhd_init_part(&p);
/* Loop over all particle pairs. */
for (k = 0; k < N; k++) {
if (parts[k].id == p.id) continue;
double dx[3];
float fdx[3];
for (int i = 0; i < 3; i++) {
dx[i] = p.x[i] - parts[k].x[i];
if (periodic) {
if (dx[i] < -dim[i] / 2)
dx[i] += dim[i];
else if (dx[i] > dim[i] / 2)
dx[i] -= dim[i];
}
fdx[i] = dx[i];
}
const float r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2];
if (r2 < p.h * p.h) {
runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
/* printf( "pairs_simple: interacting particles %lli [%i,%i,%i] and %lli
[%i,%i,%i], r=%e.\n" ,
pid , (int)(p.x[0]*ih) , (int)(p.x[1]*ih) , (int)(p.x[2]*ih) ,
parts[k].id , (int)(parts[k].x[0]*ih) , (int)(parts[k].x[1]*ih) ,
(int)(parts[k].x[2]*ih) ,
sqrtf(r2) ); */
}
}
/* Dump the result. */
printf("pairs_single: wcount of part %lli (h=%e) is %f.\n", p.id, p.h,
p.density.wcount + 32.0 / 3);
fflush(stdout);
}
void pairs_all_density(struct runner *r, struct cell *ci, struct cell *cj) {
float r2, hi, hj, hig2, hjg2, dx[3];
struct part *pi, *pj;
const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pi, e)) continue;
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = ci->hydro.parts[i].x[k] - cj->hydro.parts[j].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hig2 && !part_is_inhibited(pj, e)) {
/* Interact */
runner_iact_nonsym_density(r2, dx, hi, pj->h, pi, pj, a, H);
runner_iact_nonsym_chemistry(r2, dx, hi, pj->h, pi, pj, a, H);
runner_iact_nonsym_pressure_floor(r2, dx, hi, pj->h, pi, pj, a, H);
runner_iact_nonsym_star_formation(r2, dx, hi, pj->h, pi, pj, a, H);
runner_iact_nonsym_sink(r2, dx, hi, pj->h, pi, pj, a, H);
}
}
}
/* Reverse double-for loop and checks every interaction */
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pj, e)) continue;
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = cj->hydro.parts[j].x[k] - ci->hydro.parts[i].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hjg2 && !part_is_inhibited(pi, e)) {
/* Interact */
runner_iact_nonsym_density(r2, dx, hj, pi->h, pj, pi, a, H);
runner_iact_nonsym_chemistry(r2, dx, hj, pi->h, pj, pi, a, H);
runner_iact_nonsym_pressure_floor(r2, dx, hj, pi->h, pj, pi, a, H);
runner_iact_nonsym_star_formation(r2, dx, hj, pi->h, pj, pi, a, H);
runner_iact_nonsym_sink(r2, dx, hj, pi->h, pj, pi, a, H);
}
}
}
}
#ifdef EXTRA_HYDRO_LOOP
void pairs_all_gradient(struct runner *r, struct cell *ci, struct cell *cj) {
float r2, hi, hj, hig2, hjg2, dx[3];
struct part *pi, *pj;
const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pi, e)) continue;
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = ci->hydro.parts[i].x[k] - cj->hydro.parts[j].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hig2 && !part_is_inhibited(pj, e)) {
/* Interact */
runner_iact_nonsym_gradient(r2, dx, hi, hj, pi, pj, a, H);
}
}
}
/* Reverse double-for loop and checks every interaction */
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pj, e)) continue;
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = cj->hydro.parts[j].x[k] - ci->hydro.parts[i].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hjg2 && !part_is_inhibited(pi, e)) {
/* Interact */
runner_iact_nonsym_gradient(r2, dx, hj, pi->h, pj, pi, a, H);
}
}
}
}
#endif /* EXTRA_HDYRO_LOOP */
void pairs_all_force(struct runner *r, struct cell *ci, struct cell *cj) {
float r2, hi, hj, hig2, hjg2, dx[3];
struct part *pi, *pj;
const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pi, e)) continue;
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = ci->hydro.parts[i].x[k] - cj->hydro.parts[j].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hig2 || r2 < hjg2) {
/* Interact */
runner_iact_nonsym_force(r2, dx, hi, hj, pi, pj, a, H);
}
}
}
/* Reverse double-for loop and checks every interaction */
for (int j = 0; j < cj->hydro.count; ++j) {
pj = &cj->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
/* Skip inactive particles. */
if (!part_is_active(pj, e)) continue;
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = cj->hydro.parts[j].x[k] - ci->hydro.parts[i].x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hjg2 || r2 < hig2) {
/* Interact */
runner_iact_nonsym_force(r2, dx, hj, pi->h, pj, pi, a, H);
}
}
}
}
void pairs_all_stars_density(struct runner *r, struct cell *ci,
struct cell *cj) {
float r2, dx[3];
const double dim[3] = {r->e->s->dim[0], r->e->s->dim[1], r->e->s->dim[2]};
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->stars.count; ++i) {
struct spart *spi = &ci->stars.parts[i];
float hi = spi->h;
float hig2 = hi * hi * kernel_gamma2;
/* Skip inactive particles. */
if (!spart_is_active(spi, e)) continue;
if (!feedback_is_active(spi, e)) continue;
for (int j = 0; j < cj->hydro.count; ++j) {
struct part *pj = &cj->hydro.parts[j];
/* Early abort? */
if (part_is_inhibited(pj, e)) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = spi->x[k] - pj->x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hig2) {
/* Interact */
runner_iact_nonsym_stars_density(r2, dx, hi, pj->h, spi, pj, a, H);
}
}
}
/* Reverse double-for loop and checks every interaction */
for (int j = 0; j < cj->stars.count; ++j) {
struct spart *spj = &cj->stars.parts[j];
float hj = spj->h;
float hjg2 = hj * hj * kernel_gamma2;
/* Skip inactive particles. */
if (!spart_is_active(spj, e)) continue;
if (!feedback_is_active(spj, e)) continue;
for (int i = 0; i < ci->hydro.count; ++i) {
struct part *pi = &ci->hydro.parts[i];
/* Early abort? */
if (part_is_inhibited(pi, e)) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dx[k] = spj->x[k] - pi->x[k];
dx[k] = nearest(dx[k], dim[k]);
r2 += dx[k] * dx[k];
}
/* Hit or miss? */
if (r2 < hjg2) {
/* Interact */
runner_iact_nonsym_stars_density(r2, dx, hj, pi->h, spj, pi, a, H);
}
}
}
}
void self_all_density(struct runner *r, struct cell *ci) {
float r2, hi, hj, hig2, hjg2, dxi[3]; //, dxj[3];
struct part *pi, *pj;
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
for (int j = i + 1; j < ci->hydro.count; ++j) {
pj = &ci->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
if (pi == pj) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dxi[k] = ci->hydro.parts[i].x[k] - ci->hydro.parts[j].x[k];
r2 += dxi[k] * dxi[k];
}
/* Hit or miss? */
if (r2 < hig2 && part_is_active(pi, e) && !part_is_inhibited(pj, e)) {
/* Interact */
runner_iact_nonsym_density(r2, dxi, hi, hj, pi, pj, a, H);
runner_iact_nonsym_chemistry(r2, dxi, hi, hj, pi, pj, a, H);
runner_iact_nonsym_pressure_floor(r2, dxi, hi, hj, pi, pj, a, H);
runner_iact_nonsym_star_formation(r2, dxi, hi, hj, pi, pj, a, H);
runner_iact_nonsym_sink(r2, dxi, hi, hj, pi, pj, a, H);
}
/* Hit or miss? */
if (r2 < hjg2 && part_is_active(pj, e) && !part_is_inhibited(pi, e)) {
dxi[0] = -dxi[0];
dxi[1] = -dxi[1];
dxi[2] = -dxi[2];
/* Interact */
runner_iact_nonsym_density(r2, dxi, hj, hi, pj, pi, a, H);
runner_iact_nonsym_chemistry(r2, dxi, hj, hi, pj, pi, a, H);
runner_iact_nonsym_pressure_floor(r2, dxi, hj, hi, pj, pi, a, H);
runner_iact_nonsym_star_formation(r2, dxi, hj, hi, pj, pi, a, H);
runner_iact_nonsym_sink(r2, dxi, hj, hi, pj, pi, a, H);
}
}
}
}
#ifdef EXTRA_HYDRO_LOOP
void self_all_gradient(struct runner *r, struct cell *ci) {
float r2, hi, hj, hig2, hjg2, dxi[3]; //, dxj[3];
struct part *pi, *pj;
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
for (int j = i + 1; j < ci->hydro.count; ++j) {
pj = &ci->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
if (pi == pj) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dxi[k] = ci->hydro.parts[i].x[k] - ci->hydro.parts[j].x[k];
r2 += dxi[k] * dxi[k];
}
/* Hit or miss? */
if (r2 < hig2 && part_is_active(pi, e) && !part_is_inhibited(pj, e)) {
/* Interact */
runner_iact_nonsym_gradient(r2, dxi, hi, hj, pi, pj, a, H);
}
/* Hit or miss? */
if (r2 < hjg2 && part_is_active(pj, e) && !part_is_inhibited(pi, e)) {
dxi[0] = -dxi[0];
dxi[1] = -dxi[1];
dxi[2] = -dxi[2];
/* Interact */
runner_iact_nonsym_gradient(r2, dxi, hj, hi, pj, pi, a, H);
}
}
}
}
#endif /* EXTRA_HYDRO_LOOP */
void self_all_force(struct runner *r, struct cell *ci) {
float r2, hi, hj, hig2, hjg2, dxi[3]; //, dxj[3];
struct part *pi, *pj;
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->hydro.count; ++i) {
pi = &ci->hydro.parts[i];
hi = pi->h;
hig2 = hi * hi * kernel_gamma2;
for (int j = i + 1; j < ci->hydro.count; ++j) {
pj = &ci->hydro.parts[j];
hj = pj->h;
hjg2 = hj * hj * kernel_gamma2;
if (pi == pj) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dxi[k] = ci->hydro.parts[i].x[k] - ci->hydro.parts[j].x[k];
r2 += dxi[k] * dxi[k];
}
/* Hit or miss? */
if (r2 < hig2 || r2 < hjg2) {
/* Interact */
runner_iact_force(r2, dxi, hi, hj, pi, pj, a, H);
}
}
}
}
void self_all_stars_density(struct runner *r, struct cell *ci) {
float r2, hi, hj, hig2, dxi[3];
struct spart *spi;
struct part *pj;
const struct engine *e = r->e;
const struct cosmology *cosmo = e->cosmology;
const float a = cosmo->a;
const float H = cosmo->H;
/* Implements a double-for loop and checks every interaction */
for (int i = 0; i < ci->stars.count; ++i) {
spi = &ci->stars.parts[i];
hi = spi->h;
hig2 = hi * hi * kernel_gamma2;
if (!spart_is_active(spi, e)) continue;
if (!feedback_is_active(spi, e)) continue;
for (int j = 0; j < ci->hydro.count; ++j) {
pj = &ci->hydro.parts[j];
hj = pj->h;
/* Early abort? */
if (part_is_inhibited(pj, e)) continue;
/* Pairwise distance */
r2 = 0.0f;
for (int k = 0; k < 3; k++) {
dxi[k] = spi->x[k] - pj->x[k];
r2 += dxi[k] * dxi[k];
}
/* Hit or miss? */
if (r2 < hig2) {
/* Interact */
runner_iact_nonsym_stars_density(r2, dxi, hi, hj, spi, pj, a, H);
}
}
}
}
/**
* @brief Compute the force on a single particle brute-force.
*/
void engine_single_density(const double dim[3], const long long int pid,
struct part *restrict parts, const int N,
const int periodic, const struct cosmology *cosmo,
const struct gravity_props *grav_props) {
const float a = 1.f;
const float H = 0.f;
/* Find "our" part. */
int k;
for (k = 0; k < N && parts[k].id != pid; k++) {
/* Nothing to do here */
}
if (k == N) error("Part not found.");
struct part p = parts[k];
/* Clear accumulators. */
hydro_init_part(&p, NULL);
adaptive_softening_init_part(&p);
mhd_init_part(&p);
/* Loop over all particle pairs (density). */
for (k = 0; k < N; k++) {
if (parts[k].id == p.id) continue;
double dx[3];
float fdx[3];
for (int i = 0; i < 3; i++) {
dx[i] = p.x[i] - parts[k].x[i];
if (periodic) {
if (dx[i] < -dim[i] / 2)
dx[i] += dim[i];
else if (dx[i] > dim[i] / 2)
dx[i] -= dim[i];
}
fdx[i] = dx[i];
}
const float r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2];
if (r2 < p.h * p.h * kernel_gamma2) {
runner_iact_nonsym_density(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
}
}
/* Dump the result. */
hydro_end_density(&p, cosmo);
adaptive_softening_end_density(&p, grav_props);
mhd_end_density(&p, cosmo);
message("part %lli (h=%e) has wcount=%e, rho=%e.", p.id, p.h,
p.density.wcount, hydro_get_comoving_density(&p));
fflush(stdout);
}
void engine_single_force(double *dim, long long int pid,
struct part *restrict parts, int N, int periodic) {
int i, k;
double r2, dx[3];
float fdx[3];
struct part p;
float a = 1.f, H = 0.f;
/* Find "our" part. */
for (k = 0; k < N && parts[k].id != pid; k++) {
/* Nothing to do here */
}
if (k == N) error("Part not found.");
p = parts[k];
/* Clear accumulators. */
hydro_reset_acceleration(&p);
mhd_reset_acceleration(&p);
/* Loop over all particle pairs (force). */
for (k = 0; k < N; k++) {
// for ( k = N-1 ; k >= 0 ; k-- ) {
if (parts[k].id == p.id) continue;
for (i = 0; i < 3; i++) {
dx[i] = p.x[i] - parts[k].x[i];
if (periodic) {
if (dx[i] < -dim[i] / 2)
dx[i] += dim[i];
else if (dx[i] > dim[i] / 2)
dx[i] -= dim[i];
}
fdx[i] = dx[i];
}
r2 = fdx[0] * fdx[0] + fdx[1] * fdx[1] + fdx[2] * fdx[2];
if (r2 < p.h * p.h * kernel_gamma2 ||
r2 < parts[k].h * parts[k].h * kernel_gamma2) {
hydro_reset_acceleration(&p);
mhd_reset_acceleration(&p);
runner_iact_nonsym_force(r2, fdx, p.h, parts[k].h, &p, &parts[k], a, H);
}
}
/* Dump the result. */
message("part %lli (h=%e) has a=[%.3e,%.3e,%.3e]", p.id, p.h, p.a_hydro[0],
p.a_hydro[1], p.a_hydro[2]);
fflush(stdout);
}
/**
* Returns a random number (uniformly distributed) in [a,b)
*
* This function is *not* thread-safe.
*/
double random_uniform(const double a, const double b) {
return (rand() / (((double)RAND_MAX) + 1.0)) * (b - a) + a;
}
/**
* @brief Randomly shuffle an array of particles.
*/
void shuffle_particles(struct part *parts, const int count) {
if (count > 1) {
for (int i = 0; i < count - 1; i++) {
int j = i + random_uniform(0., (double)(count - 1 - i));
struct part particle = parts[j];
parts[j] = parts[i];
parts[i] = particle;
}
}
}
/**
* @brief Randomly shuffle an array of sparticles.
*/
void shuffle_sparticles(struct spart *sparts, const int scount) {
if (scount > 1) {
for (int i = 0; i < scount - 1; i++) {
int j = i + random_uniform(0., (double)(scount - 1 - i));
struct spart sparticle = sparts[j];
sparts[j] = sparts[i];
sparts[i] = sparticle;
}
}
}
/**
* @brief Compares two values based on their relative difference: |a - b|/|a +
* b|
*
* @param a Value a
* @param b Value b
* @param threshold The limit on the relative difference between the two values
* @param absDiff (return) Absolute difference: |a - b|
* @param absSum (return) Absolute sum: |a + b|
* @param relDiff (return) Relative difference: |a - b|/|a + b|
*
* @return 1 if difference found, 0 otherwise
*/
int compare_values(double a, double b, double threshold, double *absDiff,
double *absSum, double *relDiff) {
int result = 0;
*absDiff = 0.0, *absSum = 0.0, *relDiff = 0.0;
*absDiff = fabs(a - b);
*absSum = fabs(a + b);
if (*absSum > 0.f) {
*relDiff = *absDiff / *absSum;
}
if (*relDiff > threshold) {
result = 1;
}
return result;
}
/**
* @brief Compares two particles' properties using the relative difference and a
* threshold.
*
* @param a Particle A
* @param b Particle B
* @param threshold The limit on the relative difference between the two values
*
* @return 1 if difference found, 0 otherwise
*/
int compare_particles(struct part *a, struct part *b, double threshold) {
#ifdef GADGET2_SPH
int result = 0;
double absDiff = 0.0, absSum = 0.0, relDiff = 0.0;
for (int k = 0; k < 3; k++) {
if (compare_values(a->x[k], b->x[k], threshold, &absDiff, &absSum,
&relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for x[%d] of "
"particle %lld.",
relDiff, threshold, k, a->id);
message("a = %e, b = %e", a->x[k], b->x[k]);
result = 1;
}
}
for (int k = 0; k < 3; k++) {
if (compare_values(a->v[k], b->v[k], threshold, &absDiff, &absSum,
&relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for v[%d] of "
"particle %lld.",
relDiff, threshold, k, a->id);
message("a = %e, b = %e", a->v[k], b->v[k]);
result = 1;
}
}
for (int k = 0; k < 3; k++) {
if (compare_values(a->a_hydro[k], b->a_hydro[k], threshold, &absDiff,
&absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for a_hydro[%d] "
"of particle %lld.",
relDiff, threshold, k, a->id);
message("a = %e, b = %e", a->a_hydro[k], b->a_hydro[k]);
result = 1;
}
}
if (compare_values(a->rho, b->rho, threshold, &absDiff, &absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for rho of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->rho, b->rho);
result = 1;
}
if (compare_values(a->density.rho_dh, b->density.rho_dh, threshold, &absDiff,
&absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for rho_dh of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->density.rho_dh, b->density.rho_dh);
result = 1;
}
if (compare_values(a->density.wcount, b->density.wcount, threshold, &absDiff,
&absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for wcount of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->density.wcount, b->density.wcount);
result = 1;
}
if (compare_values(a->density.wcount_dh, b->density.wcount_dh, threshold,
&absDiff, &absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for wcount_dh of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->density.wcount_dh, b->density.wcount_dh);
result = 1;
}
if (compare_values(a->force.h_dt, b->force.h_dt, threshold, &absDiff, &absSum,
&relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for h_dt of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->force.h_dt, b->force.h_dt);
result = 1;
}
if (compare_values(a->force.v_sig, b->force.v_sig, threshold, &absDiff,
&absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for v_sig of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->force.v_sig, b->force.v_sig);
result = 1;
}
if (compare_values(a->entropy_dt, b->entropy_dt, threshold, &absDiff, &absSum,
&relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for entropy_dt of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->entropy_dt, b->entropy_dt);
result = 1;
}
if (compare_values(a->density.div_v, b->density.div_v, threshold, &absDiff,
&absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for div_v of "
"particle %lld.",
relDiff, threshold, a->id);
message("a = %e, b = %e", a->density.div_v, b->density.div_v);
result = 1;
}
for (int k = 0; k < 3; k++) {
if (compare_values(a->density.rot_v[k], b->density.rot_v[k], threshold,
&absDiff, &absSum, &relDiff)) {
message(
"Relative difference (%e) larger than tolerance (%e) for rot_v[%d] "
"of particle %lld.",
relDiff, threshold, k, a->id);
message("a = %e, b = %e", a->density.rot_v[k], b->density.rot_v[k]);
result = 1;
}
}
return result;
#else
error("Function not supported for this flavour of SPH");
return 0;
#endif
}
/**
* @brief return the resident memory use of the process and its children.
*
* @result memory use in Kb.
*/
long get_maxrss(void) {
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
return usage.ru_maxrss;
}
/**
* @brief trim leading white space from a string.
*
* Returns pointer to first character.
*
* @param s the string.
* @result the result.
*/
char *trim_leading(char *s) {
if (s == NULL || strlen(s) < 2) return s;
while (isspace(*s)) s++;
return s;
}
/**
* @brief trim trailing white space from a string.
*
* Modifies the string by adding a NULL to the end.
*
* @param s the string.
* @result the result.
*/
char *trim_trailing(char *s) {
if (s == NULL || strlen(s) < 2) return s;
char *end = s + strlen(s) - 1;
while (isspace(*end)) end--;
*(end + 1) = '\0';
return s;
}
/**
* @brief trim leading and trailing white space from a string.
*
* Can modify the string by adding a NULL to the end.
*
* @param s the string.
* @result the result.
*/
char *trim_both(char *s) {
if (s == NULL || strlen(s) < 2) return s;
return trim_trailing(trim_leading(s));
}
/**
* @brief safe check directory existence and creation.
*
* Doesn't try to re-create an existing directory and makes sure that it can
* have files created in it. If the directory doesn't exist and we want to
* create it then we try to do that with an appropriate mask that should
* honour the users umask. If the directory is something odd like a broken
* link then that is dereferenced so should also result in an error, since
* it doesn't exist and cannot be created. Finally we check that an existing
* file with this name is indeed a directory.
*
* @param dir the directory we need to exist.
* @param create create if not already exists, otherwise non-existence is an
* error.
*/
void safe_checkdir(const char *dir, int create) {
if (access(dir, W_OK | X_OK) != 0) {
/* A file with this name and the minimally correct permissions does not
* exist. */
if (create) {
if (mkdir(dir, 0777) != 0)
error("Failed to create directory %s (%s)", dir, strerror(errno));
} else {
error("directory %s does not exist or cannot be used (%s)", dir,
strerror(errno));
}
} else {
/* Exists and has the minimally correct permissions, is this a
* directory? */
struct stat sb;
if (stat(dir, &sb) != 0) {
/* Weird error, can stat all existing files. */
error("Failed to stat directory %s (%s)", dir, strerror(errno));
} else if ((sb.st_mode & S_IFMT) != S_IFDIR) {
error("%s is not a directory, cannot use or create.", dir);
}
}
/* Success. */
return;
}