Initial import

This commit is contained in:
Guilhem Lavaux 2023-05-29 10:41:03 +02:00
commit 56a50eead3
820 changed files with 192077 additions and 0 deletions

14
extra/dm_sheet/README.md Normal file
View file

@ -0,0 +1,14 @@
# README #
### Documentation ###
Please see this page on the Aquila Consortium wiki: https://athos.iap.fr/wiki/index.php/ARES_Extras/dm_sheet
### Contributors ###
The main authors of this module are:
* Florent Leclercq
* Guilhem Lavaux
To add more features, please contact these people, or submit pull requests.

View file

@ -0,0 +1,6 @@
SET(EXTRA_DM_SHEET ${CMAKE_SOURCE_DIR}/extra/dm_sheet)
SET(EXTRA_LIBLSS ${EXTRA_LIBLSS}
${EXTRA_DM_SHEET}/libLSS/physics/dm_sheet/dm_sheet.cpp
${EXTRA_DM_SHEET}/libLSS/physics/velocity/velocity_sic.cpp
)

View file

@ -0,0 +1,519 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/dm_sheet/dm_sheet.cpp
Copyright (C) 2016-2018 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2018 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2019-2020 James Prideaux-Ghee <j.prideaux-ghee19@imperial.ac.uk>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <cmath>
#include <algorithm>
#include <boost/multi_array.hpp>
#include <Eigen/Dense>
#include "libLSS/tools/console.hpp"
#include "libLSS/tools/log_traits.hpp"
#include "libLSS/tools/string_tools.hpp"
#include "libLSS/tools/fused_array.hpp"
#include "libLSS/physics/dm_sheet/dm_sheet.hpp"
#include "libLSS/physics/dm_sheet/tools.hpp"
#include "libLSS/physics/dm_sheet/tetrahedron_tools.hpp"
using namespace LibLSS;
using namespace LibLSS::DM_Sheet;
///-------------------------------------------------------------------------------------
/** @fn project_tetrahedron
* Project a tetrahedron to the Eulerian grid
* @param TetrahedronCoords input tetrahedron vertices coordinates
* @param N0 mesh size x
* @param N1 mesh size y
* @param N2 mesh size z
* @param L0 box size x
* @param L1 box size y
* @param L2 box size z
* @param f functor to use for projection
*/
template <typename Functor>
void project_tetrahedron(
const double *TetrahedronCoords, const size_t N0, const size_t N1,
const size_t N2, const double L0, const double L1, const double L2,
Functor f) {
const double d0 = L0 / N0;
const double d1 = L1 / N1;
const double d2 = L2 / N2;
double xA, yA, zA, xB, yB, zB, xC, yC, zC, xD, yD, zD;
xA = TetrahedronCoords[0];
yA = TetrahedronCoords[1];
zA = TetrahedronCoords[2];
xB = TetrahedronCoords[3];
yB = TetrahedronCoords[4];
zB = TetrahedronCoords[5];
xC = TetrahedronCoords[6];
yC = TetrahedronCoords[7];
zC = TetrahedronCoords[8];
xD = TetrahedronCoords[9];
yD = TetrahedronCoords[10];
zD = TetrahedronCoords[11];
double xmin = std::min({xA, xB, xC, xD}), xmax = std::max({xA, xB, xC, xD});
double ymin = std::min({yA, yB, yC, yD}), ymax = std::max({yA, yB, yC, yD});
double zmin = std::min({zA, zB, zC, zD}), zmax = std::max({zA, zB, zC, zD});
ssize_t imin = ssize_t(floor(xmin / d0)), imax = ssize_t(floor(xmax / d0));
ssize_t jmin = ssize_t(floor(ymin / d1)), jmax = ssize_t(floor(ymax / d1));
ssize_t kmin = ssize_t(floor(zmin / d2)), kmax = ssize_t(floor(zmax / d2));
Eigen::Matrix4d M;
M << xA, yA, zA, 1., xB, yB, zB, 1., xC, yC, zC, 1., xD, yD, zD, 1.;
double D0 = M.determinant();
// Check if this grid point is in the tetrahedron and project
/// \note in this loop it is possible to have i>N0, j>N1, k>N2 !!
for (ssize_t i = imin; i <= imax; i++)
for (ssize_t j = jmin; j <= jmax; j++)
for (ssize_t k = kmin; k <= kmax; k++) {
// check the current grid point
double x = i * d0;
double y = j * d1;
double z = k * d2;
if (isInTetrahedron(TetrahedronCoords, D0, x, y, z)) {
// important: check periodic boundary conditions here
size_t igrid = p_mod(i, ssize_t(N0));
size_t jgrid = p_mod(j, ssize_t(N1));
size_t kgrid = p_mod(k, ssize_t(N2));
// interpolate with Shepard's method (1/distance^2 weights)
double wA = 1 / ((x - xA) * (x - xA) + (y - yA) * (y - yA) +
(z - zA) * (z - zA));
double wB = 1 / ((x - xB) * (x - xB) + (y - yB) * (y - yB) +
(z - zB) * (z - zB));
double wC = 1 / ((x - xC) * (x - xC) + (y - yC) * (y - yC) +
(z - zC) * (z - zC));
double wD = 1 / ((x - xD) * (x - xD) + (y - yD) * (y - yD) +
(z - zD) * (z - zD));
double w = wA + wB + wC + wD;
f(igrid, jgrid, kgrid, wA, wB, wC, wD, w);
}
}
} //project_tetrahedron
///-------------------------------------------------------------------------------------
static massparticleID_t get_NpM(const particleID_t NpF) {
// There is exactly 24 times more mass tracers than flow tracers
return massparticleID_t(24) * NpF;
} //get_NpM
///-------------------------------------------------------------------------------------
/** @fn get_masstracers
* Return a Snapshot *containing the mass tracers
* @warning Take care to use the same type for flow tracers and mass tracers IDs in this function!
*/
void get_masstracers(
const arrayID_view_t &flowtracers_Ids,
const arrayPosition_view_t &flowtracers_positions, const double L0,
const double L1, const double L2, const size_t Np0, const size_t Np1,
const size_t Np2, arrayPosition_t &masstracers_positions) {
const particleID_t NpF = flowtracers_positions.shape()[0];
const massparticleID_t NpM = get_NpM(NpF);
// Types should match here!
// Loop on flow tracers
#pragma omp parallel for schedule(static)
for (particleID_t mpF = 0; mpF < NpF; mpF++) {
particleID_t Id = flowtracers_Ids[mpF];
// Loop on the 6 tetrahedra for this particle
for (int itet = 0; itet < 6; itet++) {
particleID_t mpM, mpA, mpB, mpC, mpD;
// Get the indices of the 4 vertices
particleID_t TetrahedronIndices[4];
get_tetrahedron_indices(Id, itet, Np0, Np1, Np2, TetrahedronIndices);
mpA = TetrahedronIndices[0];
mpB = TetrahedronIndices[1];
mpC = TetrahedronIndices[2];
mpD = TetrahedronIndices[3];
// Get the coordinates
double TetrahedronCoords[12];
get_tetrahedron_coords(
flowtracers_positions, mpA, mpB, mpC, mpD, L0, L1, L2,
TetrahedronCoords);
// Loop on the 4 sides for this tetrahedron
for (unsigned int iside = 0; iside < 4; iside++) {
// Get the positions of the mass tracers
mpM = 24 * mpF + 4 * itet + iside;
double MassTracerCoords[3];
get_masstracer_coords(TetrahedronCoords, iside, MassTracerCoords);
// check periodic boundary conditions here
masstracers_positions[mpM][0] = p_mod(MassTracerCoords[0], L0);
masstracers_positions[mpM][1] = p_mod(MassTracerCoords[1], L1);
masstracers_positions[mpM][2] = p_mod(MassTracerCoords[2], L2);
} //end loop on sides
} //end loop on tetrahedra
} //end loop on flow tracers
} //get_masstracers
///-------------------------------------------------------------------------------------
/** @fn lagrangian_transport
* Do the Lagrangian transport of various quantities
*/
template <
typename ParticlePropertyArray, typename ApplyPropertyFunctor,
typename WeightFunctor>
void lagrangian_transport(
const arrayID_view_t &flowtracers_Ids,
const arrayPosition_view_t &flowtracers_positions,
const ParticlePropertyArray &properties, WeightFunctor weighter,
const double L0, const double L1, const double L2, const size_t Np0,
const size_t Np1, const size_t Np2, const size_t N0, const size_t N1,
const size_t N2, ApplyPropertyFunctor applier) {
const double m = 1.0;
const double d = L0 / Np0;
const size_t N = N0 * N1 * N2;
const particleID_t NpF = flowtracers_Ids.shape()[0];
Console::instance().print<LOG_VERBOSE>("Npf = " + to_string(NpF));
// loop on particles
for (particleID_t mpF = 0; mpF < NpF; mpF++) {
particleID_t Id = flowtracers_Ids[mpF];
// loop on the 6 tetrahedra for this particle
for (unsigned int itet = 0; itet < 6; itet++) {
particleID_t mpA, mpB, mpC, mpD;
// get the indices of the 4 vertices
particleID_t TetrahedronIndices[4];
get_tetrahedron_indices(Id, itet, Np0, Np1, Np2, TetrahedronIndices);
mpA = TetrahedronIndices[0];
mpB = TetrahedronIndices[1];
mpC = TetrahedronIndices[2];
mpD = TetrahedronIndices[3];
// get the coordinates
double TetrahedronCoords[12];
get_tetrahedron_coords(
flowtracers_positions, mpA, mpB, mpC, mpD, L0, L1, L2,
TetrahedronCoords);
// get the volume and mass
double Vtet = get_tetrahedron_volume(TetrahedronCoords);
double rhotet =
m / (6 * std::abs(Vtet)); //equation (6) in Abel, Hahn & Kaehler 2012
// get weights for each vertex
auto pA = weighter(properties[mpA], rhotet),
pB = weighter(properties[mpB], rhotet),
pC = weighter(properties[mpC], rhotet),
pD = weighter(properties[mpD], rhotet);
// project tetrahedron
project_tetrahedron(
TetrahedronCoords, N0, N1, N2, L0, L1, L2,
[&pA, &pB, &pC, &pD, &applier](
size_t i, size_t j, size_t k, double wA, double wB, double wC,
double wD, double w) {
applier(i, j, k, pA, wA, pB, wB, pC, wC, pD, wD, w);
});
} //end loop on tetrahedra
} //end loop on particles
} //lagrangian_transport
namespace LibLSS {
namespace DM_Sheet {
void get_nbstreams_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid) {
auto mass_array =
b_fused_idx<double, 2>([](int, int) -> double { return 1; });
typedef decltype(mass_array[0]) Mass_t;
auto weighter = [](const Mass_t &, double rhotet) -> double {
return 1.;
};
auto applier = [&nbstreams_grid](
size_t i, size_t j, size_t k, double, double wA,
double, double wB, double, double wC, double,
double wD,
double w) { nbstreams_grid[i][j][k] += 1.; };
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, mass_array, weighter, L0, L1,
L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_nbstreams_tetrahedra
void get_density_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &density_grid) {
auto mass_array =
b_fused_idx<double, 2>([](int, int) -> double { return 1; });
typedef decltype(mass_array[0]) Mass_t;
auto weighter = [](const Mass_t &, double rhotet) -> double {
return rhotet;
};
auto applier = [&density_grid](
size_t i, size_t j, size_t k, double rho, double wA,
double, double wB, double, double wC, double,
double wD, double w) { density_grid[i][j][k] += rho; };
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, mass_array, weighter, L0, L1,
L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_density_tetrahedra
void get_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 4> &momenta_grid) {
typedef decltype(flowtracers_velocities[0]) Flow_t;
typedef std::tuple<Flow_t, double> TupleV;
typedef TupleV const &TupleV_c;
auto weighter = [](Flow_t v, double rhotet) -> TupleV {
return TupleV(v, rhotet);
};
auto applier = [&momenta_grid](
size_t i, size_t j, size_t k, TupleV_c tA, double wA,
TupleV_c tB, double wB, TupleV_c tC, double wC,
TupleV_c tD, double wD, double w) {
auto vg = momenta_grid[i][j][k];
auto const &vA = std::get<0>(tA);
auto const &vB = std::get<0>(tB);
auto const &vC = std::get<0>(tC);
auto const &vD = std::get<0>(tD);
double rhotet_w = std::get<1>(tA) / w;
for (unsigned int l = 0; l < 3; l++)
vg[l] +=
rhotet_w * (vA[l] * wA + vB[l] * wB + vC[l] * wC + vD[l] * wD);
};
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, flowtracers_velocities,
weighter, L0, L1, L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_momenta_tetrahedra
void get_mass_and_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid) {
typedef decltype(flowtracers_velocities[0]) Flow_t;
typedef std::tuple<Flow_t, double> TupleV;
typedef TupleV const &TupleV_c;
auto weighter = [](Flow_t v, double rhotet) -> TupleV {
return TupleV(v, rhotet);
};
auto applier = [&density_grid, &momenta_grid](
size_t i, size_t j, size_t k, TupleV_c tA, double wA,
TupleV_c tB, double wB, TupleV_c tC, double wC,
TupleV_c tD, double wD, double w) {
auto vg = momenta_grid[i][j][k];
auto const &vA = std::get<0>(tA);
auto const &vB = std::get<0>(tB);
auto const &vC = std::get<0>(tC);
auto const &vD = std::get<0>(tD);
double rhotet = std::get<1>(tA);
double rhotet_w = rhotet / w;
for (unsigned int l = 0; l < 3; l++)
vg[l] +=
rhotet_w * (vA[l] * wA + vB[l] * wB + vC[l] * wC + vD[l] * wD);
density_grid[i][j][k] += rhotet;
};
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, flowtracers_velocities,
weighter, L0, L1, L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_mass_and_momenta_tetrahedra
void get_velocity_dispersion_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid,
boost::multi_array_ref<double, 4> &dispersion_grid) {
typedef decltype(flowtracers_velocities[0]) Flow_t;
typedef std::tuple<Flow_t, double> TupleV;
typedef TupleV const &TupleV_c;
auto weighter = [](Flow_t v, double rhotet) -> TupleV {
return TupleV(v, rhotet);
};
auto applier = [&momenta_grid, &dispersion_grid](
size_t i, size_t j, size_t k, TupleV_c tA, double wA,
TupleV_c tB, double wB, TupleV_c tC, double wC,
TupleV_c tD, double wD, double w) {
auto vg = momenta_grid[i][j][k];
auto vp = dispersion_grid[i][j][k];
auto const &vA = std::get<0>(tA);
auto const &vB = std::get<0>(tB);
auto const &vC = std::get<0>(tC);
auto const &vD = std::get<0>(tD);
double rhotet = std::get<1>(tA);
double rhotet_w = rhotet / w;
for (unsigned int l = 0; l < 3; l++) {
vg[l] +=
rhotet_w * (vA[l] * wA + vB[l] * wB + vC[l] * wC + vD[l] * wD);
}
vp[0] += rhotet_w * (vA[0] * vA[0] * wA + vB[0] * vB[0] * wB +
vC[0] * vC[0] * wC + vD[0] * vD[0] * wD);
vp[1] += rhotet_w * (vA[1] * vA[1] * wA + vB[1] * vB[1] * wB +
vC[1] * vC[1] * wC + vD[1] * vD[1] * wD);
vp[2] += rhotet_w * (vA[2] * vA[2] * wA + vB[2] * vB[2] * wB +
vC[2] * vC[2] * wC + vD[2] * vD[2] * wD);
vp[3] += rhotet_w * (vA[0] * vA[1] * wA + vB[0] * vB[1] * wB +
vC[0] * vC[1] * wC + vD[0] * vD[1] * wD);
vp[4] += rhotet_w * (vA[0] * vA[2] * wA + vB[0] * vB[2] * wB +
vC[0] * vC[2] * wC + vD[0] * vD[2] * wD);
vp[5] += rhotet_w * (vA[1] * vA[2] * wA + vB[1] * vB[2] * wB +
vC[1] * vC[2] * wC + vD[1] * vD[2] * wD);
};
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, flowtracers_velocities,
weighter, L0, L1, L2, Np0, Np1, Np2, N0, N1, N2, applier);
} // get_velocity_dispersion_tetrahedra
void get_nbstreams_mass_and_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid) {
typedef decltype(flowtracers_velocities[0]) Flow_t;
typedef std::tuple<Flow_t, double> TupleV;
typedef TupleV const &TupleV_c;
auto weighter = [](Flow_t v, double rhotet) -> TupleV {
return TupleV(v, rhotet);
};
auto applier = [&nbstreams_grid, &density_grid, &momenta_grid](
size_t i, size_t j, size_t k, TupleV_c tA, double wA,
TupleV_c tB, double wB, TupleV_c tC, double wC,
TupleV_c tD, double wD, double w) {
auto vg = momenta_grid[i][j][k];
auto const &vA = std::get<0>(tA);
auto const &vB = std::get<0>(tB);
auto const &vC = std::get<0>(tC);
auto const &vD = std::get<0>(tD);
double rhotet = std::get<1>(tA);
double rhotet_w = rhotet / w;
for (unsigned int l = 0; l < 3; l++)
vg[l] +=
rhotet_w * (vA[l] * wA + vB[l] * wB + vC[l] * wC + vD[l] * wD);
density_grid[i][j][k] += rhotet;
nbstreams_grid[i][j][k] += 1.;
};
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, flowtracers_velocities,
weighter, L0, L1, L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_nbstreams_mass_and_momenta_tetrahedra
//get_nbstreams_mass_momenta_and_velocity_dispersion_tetrahedra
void get_nbstreams_mass_momenta_and_velocity_dispersion_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid,
boost::multi_array_ref<double, 4> &dispersion_grid) {
typedef decltype(flowtracers_velocities[0]) Flow_t;
typedef std::tuple<Flow_t, double> TupleV;
typedef TupleV const &TupleV_c;
auto weighter = [](Flow_t v, double rhotet) -> TupleV {
return TupleV(v, rhotet);
};
auto applier = [&nbstreams_grid, &density_grid, &momenta_grid,
&dispersion_grid](
size_t i, size_t j, size_t k, TupleV_c tA, double wA,
TupleV_c tB, double wB, TupleV_c tC, double wC,
TupleV_c tD, double wD, double w) {
auto vg = momenta_grid[i][j][k];
auto vp = dispersion_grid[i][j][k];
auto const &vA = std::get<0>(tA);
auto const &vB = std::get<0>(tB);
auto const &vC = std::get<0>(tC);
auto const &vD = std::get<0>(tD);
double rhotet = std::get<1>(tA);
double rhotet_w = rhotet / w;
for (unsigned int l = 0; l < 3; l++) {
vg[l] +=
rhotet_w * (vA[l] * wA + vB[l] * wB + vC[l] * wC + vD[l] * wD);
}
vp[0] += rhotet_w * (vA[0] * vA[0] * wA + vB[0] * vB[0] * wB +
vC[0] * vC[0] * wC + vD[0] * vD[0] * wD);
vp[1] += rhotet_w * (vA[1] * vA[1] * wA + vB[1] * vB[1] * wB +
vC[1] * vC[1] * wC + vD[1] * vD[1] * wD);
vp[2] += rhotet_w * (vA[2] * vA[2] * wA + vB[2] * vB[2] * wB +
vC[2] * vC[2] * wC + vD[2] * vD[2] * wD);
vp[3] += rhotet_w * (vA[0] * vA[1] * wA + vB[0] * vB[1] * wB +
vC[0] * vC[1] * wC + vD[0] * vD[1] * wD);
vp[4] += rhotet_w * (vA[0] * vA[2] * wA + vB[0] * vB[2] * wB +
vC[0] * vC[2] * wC + vD[0] * vD[2] * wD);
vp[5] += rhotet_w * (vA[1] * vA[2] * wA + vB[1] * vB[2] * wB +
vC[1] * vC[2] * wC + vD[1] * vD[2] * wD);
density_grid[i][j][k] += rhotet;
nbstreams_grid[i][j][k] += 1.;
};
lagrangian_transport(
flowtracers_Ids, flowtracers_positions, flowtracers_velocities,
weighter, L0, L1, L2, Np0, Np1, Np2, N0, N1, N2, applier);
} //get_nbstreams_mass_momenta_and_velocity_dispersion_tetrahedra
} // namespace DM_Sheet
} // namespace LibLSS
// ARES TAG: authors_num = 3
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2016-2018
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2018
// ARES TAG: email(1) = guilhem.lavaux@iap.fr
// ARES TAG: name(2) = James Prideaux-Ghee
// ARES TAG: year(2) = 2019-2020
// ARES TAG: email(2) = j.prideaux-ghee19@imperial.ac.uk

View file

@ -0,0 +1,178 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/dm_sheet/dm_sheet.hpp
Copyright (C) 2016-2018 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2018 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2019-2020 James Prideaux-Ghee <j.prideaux-ghee19@imperial.ac.uk>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_DMSHEET_HPP
# define __LIBLSS_DMSHEET_HPP
# include <boost/multi_array.hpp>
# include "libLSS/physics/dm_sheet/tetrahedron_tools.hpp"
namespace LibLSS {
namespace DM_Sheet {
typedef boost::multi_array_ref<particleID_t, 1> arrayID_t;
typedef boost::multi_array_ref<double, 2> arrayPosition_t;
typedef boost::multi_array_ref<double, 2> arrayVelocity_t;
typedef arrayID_t::const_array_view<1>::type arrayID_view_t;
typedef arrayPosition_t::const_array_view<2>::type arrayPosition_view_t;
typedef arrayVelocity_t::const_array_view<2>::type arrayVelocity_view_t;
/**
* This function computes projects tetrahedra on the provided density grid
* with the indicated flow tracers.
*
* @param flowtracers_Ids lagrangian ids of the flowtracers
* @param flowtracers_positions Eulerian position of the flowtracers
* @param L0 first dimension of the box
* @param L1 second dimension of the box
* @param L2 third dimension of hte box
* @param Np0 first dimension of the Lagrangian grid
* @param Np1 second dimension of the Lagrangian grid
* @param Np2 third dimension of the Lagrangian grid
* @param N0 first dimension of the expected Eulerian grid
* @param N1 second dimension of the expected Eulerian grid
* @param N2 third dimension of the expected Eulerian grid
* @param density_grid unnormalized mass density
*/
void get_nbstreams_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid);
/**
* This function computes the density field from tetrahedra on the provided density grid
* with the indicated flow tracers.
*
* @param flowtracers_Ids lagrangian ids of the flowtracers
* @param flowtracers_positions Eulerian position of the flowtracers
* @param L0 first dimension of the box
* @param L1 second dimension of the box
* @param L2 third dimension of hte box
* @param Np0 first dimension of the Lagrangian grid
* @param Np1 second dimension of the Lagrangian grid
* @param Np2 third dimension of the Lagrangian grid
* @param N0 first dimension of the expected Eulerian grid
* @param N1 second dimension of the expected Eulerian grid
* @param N2 third dimension of the expected Eulerian grid
* @param density_grid unnormalized mass density
*/
void get_density_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &density_grid);
/**
* This function computes the \emph{momenta} from tetrahedra
* on the provided momenta grid with the indicated flow tracers.
*
* @param flowtracers_Ids lagrangian ids of the flowtracers
* @param flowtracers_positions Eulerian position of the flowtracers
* @param L0 first dimension of the box
* @param L1 second dimension of the box
* @param L2 third dimension of hte box
* @param Np0 first dimension of the Lagrangian grid
* @param Np1 second dimension of the Lagrangian grid
* @param Np2 third dimension of the Lagrangian grid
* @param N0 first dimension of the expected Eulerian grid
* @param N1 second dimension of the expected Eulerian grid
* @param N2 third dimension of the expected Eulerian grid
* @param momenta_grid output momenta grid
*/
void get_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 4> &momenta_grid);
/**
* This function computes density and \emph{momenta} fields from tetrahedra
* on the provided grids with the indicated flow tracers.
*
* @param flowtracers_Ids lagrangian ids of the flowtracers
* @param flowtracers_positions Eulerian position of the flowtracers
* @param L0 first dimension of the box
* @param L1 second dimension of the box
* @param L2 third dimension of hte box
* @param Np0 first dimension of the Lagrangian grid
* @param Np1 second dimension of the Lagrangian grid
* @param Np2 third dimension of the Lagrangian grid
* @param N0 first dimension of the expected Eulerian grid
* @param N1 second dimension of the expected Eulerian grid
* @param N2 third dimension of the expected Eulerian grid
* @param density_grid output mass density
* @param momenta_grid output momenta grid
*/
void get_mass_and_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid);
void get_nbstreams_mass_and_momenta_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid);
void get_velocity_dispersion_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &
nbstreams_grid, // Introduce a 3d array with the no. dm streams per point.
boost::multi_array_ref<double, 3> &
density_grid, // Introduce a 3d array with the density at each point
boost::multi_array_ref<double, 4> &
momenta_grid, // Introduce a 4d array, with the velocity components at each point
boost::multi_array_ref<double, 4> &
dispersion_grid); // Introduce a 5d array with the velocity dispersion tensor
void get_nbstreams_mass_momenta_and_velocity_dispersion_tetrahedra(
arrayID_view_t flowtracers_Ids,
arrayPosition_view_t flowtracers_positions,
arrayVelocity_view_t flowtracers_velocities, const double L0,
const double L1, const double L2, const int Np0, const int Np1,
const int Np2, const int N0, const int N1, const int N2,
boost::multi_array_ref<double, 3> &nbstreams_grid,
boost::multi_array_ref<double, 3> &density_grid,
boost::multi_array_ref<double, 4> &momenta_grid,
boost::multi_array_ref<double, 4> &dispersion_grid);
} // namespace DM_Sheet
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 3
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2016-2018
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2018
// ARES TAG: email(1) = guilhem.lavaux@iap.fr
// ARES TAG: name(2) = James Prideaux-Ghee
// ARES TAG: year(2) = 2019-2020
// ARES TAG: email(2) = j.prideaux-ghee19@imperial.ac.uk
#pragma once

View file

@ -0,0 +1,380 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/dm_sheet/tetrahedron_tools.hpp
Copyright (C) 2016-2018 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2018 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_DMSHEET_TETRAHEDRON_TOOLS_HPP
# define __LIBLSS_DMSHEET_TETRAHEDRON_TOOLS_HPP
# include <array>
# include <Eigen/Dense>
# include "libLSS/physics/dm_sheet/tools.hpp"
namespace LibLSS {
namespace DM_Sheet {
typedef size_t particleID_t;
typedef size_t massparticleID_t;
#if defined(__GNUC__) && !(defined(__clang__) || defined(__INTEL_COMPILER))
static constexpr double INV_SQRT_5 = 1.0 / std::sqrt(5.0);
static constexpr double ONE_MINUS_INV_SQRT_5 = 1 - 1.0 / std::sqrt(5.0);
#else
static const double INV_SQRT_5 = 1.0 / std::sqrt(5.0);
static const double ONE_MINUS_INV_SQRT_5 = 1 - 1.0 / std::sqrt(5.0);
#endif
///-------------------------------------------------------------------------
/** @fn get_Lagrangian_indices
* Get indices on the Lagrangian grid from particle Id
* @param Id particle id
* @param Np0 particle mesh size x
* @param Np1 particle mesh size y
* @param Np2 particle mesh size z
* @param indices output indices
* \warning Assumes row major!
*/
static inline void get_Lagrangian_indices(
const particleID_t Id, const size_t Np0, const size_t Np1,
const size_t Np2, std::array<size_t, 3> &indices) {
// assumes Id = k+Np2*(j+Np1*i)
size_t i = (Id / (Np1 * Np2)) % Np0;
size_t j = ((Id - Np1 * Np2 * i) / Np2) % Np1;
size_t k = ((Id - Np2 * j - Np2 * Np1 * i)) % Np2;
indices[0] = i;
indices[1] = j;
indices[2] = k;
} //get_Lagrangian_indices
///-------------------------------------------------------------------------
/** @fn get_index
* Get mapping from 3D to 1D array
* @param i index x
* @param j index y
* @param k index z
* @param N0 array size x
* @param N1 array size y
* @param N2 array size z
* @return index
* \warning Assumes row major!
*/
static inline size_t get_index(
const int i, const int j, const int k, const int, const int N1,
const int N2) {
return size_t(k + N2 * (j + N1 * i));
} //get_index
///-------------------------------------------------------------------------
/** @fn get_Lagrangian_Id
* Get particle Id from indices on the Lagrangian grid
* @param mp0 index x
* @param mp1 index y
* @param mp2 index z
* @param Np0 particle mesh size x
* @param Np1 particle mesh size y
* @param Np2 particle mesh size z
* @return particle id
* \warning Assumes row major!
*/
static inline particleID_t get_Lagrangian_Id(
const size_t mp0, const size_t mp1, const size_t mp2, const size_t Np0,
const size_t Np1, const size_t Np2) {
return particleID_t(get_index(mp0, mp1, mp2, Np0, Np1, Np2));
} //get_Lagrangian_Id
///-------------------------------------------------------------------------
/** @fn get_tetrahedron_indices
* Get the particle indices of a tetrahedron
* @param Id particle id
* @param itet the id of the tetrahedron (0 to 5)
* @param Np0 particle mesh size x
* @param Np1 particle mesh size y
* @param Np2 particle mesh size z
* @param TetrahedronIndices output tetrahedron particle indices
*/
static inline void get_tetrahedron_indices(
const particleID_t Id, const size_t itet, const size_t Np0,
const size_t Np1, const size_t Np2, particleID_t *TetrahedronIndices) {
std::array<size_t, 3> indices;
get_Lagrangian_indices(Id, Np0, Np1, Np2, indices);
size_t i = indices[0];
size_t j = indices[1];
size_t k = indices[2];
size_t ii = (i + 1) % Np0;
size_t jj = (j + 1) % Np1;
size_t kk = (k + 1) % Np2;
particleID_t mpA, mpB, mpC, mpD;
switch (itet) {
case 0:
// Tetrahedron 1: (0,1,3,4)
mpA = get_Lagrangian_Id(i, j, k, Np0, Np1, Np2); //0
mpB = get_Lagrangian_Id(ii, j, k, Np0, Np1, Np2); //1
mpC = get_Lagrangian_Id(i, jj, k, Np0, Np1, Np2); //3
mpD = get_Lagrangian_Id(i, j, kk, Np0, Np1, Np2); //4
break;
case 1:
// Tetrahedron 2: (1,3,4,7)
mpA = get_Lagrangian_Id(ii, j, k, Np0, Np1, Np2); //1
mpB = get_Lagrangian_Id(i, jj, k, Np0, Np1, Np2); //3
mpC = get_Lagrangian_Id(i, j, kk, Np0, Np1, Np2); //4
mpD = get_Lagrangian_Id(i, jj, kk, Np0, Np1, Np2); //7
break;
case 2:
// Tetrahedron 3: (1,4,5,7)
mpA = get_Lagrangian_Id(ii, j, k, Np0, Np1, Np2); //1
mpB = get_Lagrangian_Id(i, j, kk, Np0, Np1, Np2); //4
mpC = get_Lagrangian_Id(ii, j, kk, Np0, Np1, Np2); //5
mpD = get_Lagrangian_Id(i, jj, kk, Np0, Np1, Np2); //7
break;
case 3:
// Tetrahedron 4: (1,2,5,7)
mpA = get_Lagrangian_Id(ii, j, k, Np0, Np1, Np2); //1
mpB = get_Lagrangian_Id(ii, jj, k, Np0, Np1, Np2); //2
mpC = get_Lagrangian_Id(ii, j, kk, Np0, Np1, Np2); //5
mpD = get_Lagrangian_Id(i, jj, kk, Np0, Np1, Np2); //7
break;
case 4:
// Tetrahedron 5: (1,2,3,7)
mpA = get_Lagrangian_Id(ii, j, k, Np0, Np1, Np2); //1
mpB = get_Lagrangian_Id(ii, jj, k, Np0, Np1, Np2); //2
mpC = get_Lagrangian_Id(i, jj, k, Np0, Np1, Np2); //3
mpD = get_Lagrangian_Id(i, jj, kk, Np0, Np1, Np2); //7
break;
case 5:
// Tetrahedron 6: (2,5,6,7)
mpA = get_Lagrangian_Id(ii, jj, k, Np0, Np1, Np2); //2
mpB = get_Lagrangian_Id(ii, j, kk, Np0, Np1, Np2); //5
mpC = get_Lagrangian_Id(ii, jj, kk, Np0, Np1, Np2); //6
mpD = get_Lagrangian_Id(i, jj, kk, Np0, Np1, Np2); //7
break;
}
TetrahedronIndices[0] = mpA;
TetrahedronIndices[1] = mpB;
TetrahedronIndices[2] = mpC;
TetrahedronIndices[3] = mpD;
} //get_tetrahedron_indices
///-------------------------------------------------------------------------
/** @fn get_tetrahedron_coords
* Get physical coordinates of the tetrahedron vertices
* @param positions particles' positions
* @param mpA particle Id first vertex
* @param mpB particle Id second vertex
* @param mpC particle Id third vertex
* @param mpD particle Id fourth vertex
* @param TetrahedronCoords output tetrahedron vertices coordinates
*/
template <typename ArrayPosition>
static inline void get_tetrahedron_coords(
const ArrayPosition &positions, const size_t mpA, const size_t mpB,
const size_t mpC, const size_t mpD, const double L0, const double L1,
const double L2, double *TetrahedronCoords) {
double xA = positions[mpA][0], yA = positions[mpA][1],
zA = positions[mpA][2];
double xB = positions[mpB][0], yB = positions[mpB][1],
zB = positions[mpB][2];
double xC = positions[mpC][0], yC = positions[mpC][1],
zC = positions[mpC][2];
double xD = positions[mpD][0], yD = positions[mpD][1],
zD = positions[mpD][2];
// Correction for periodic boundary conditions
double xmax = std::max({xA, xB, xC, xD});
periodic_boundary_correct(xmax, xA, L0);
periodic_boundary_correct(xmax, xB, L0);
periodic_boundary_correct(xmax, xC, L0);
periodic_boundary_correct(xmax, xD, L0);
double ymax = std::max({yA, yB, yC, yD});
periodic_boundary_correct(ymax, yA, L1);
periodic_boundary_correct(ymax, yB, L1);
periodic_boundary_correct(ymax, yC, L1);
periodic_boundary_correct(ymax, yD, L1);
double zmax = std::max({zA, zB, zC, zD});
periodic_boundary_correct(zmax, zA, L2);
periodic_boundary_correct(zmax, zB, L2);
periodic_boundary_correct(zmax, zC, L2);
periodic_boundary_correct(zmax, zD, L2);
TetrahedronCoords[0] = xA;
TetrahedronCoords[1] = yA;
TetrahedronCoords[2] = zA;
TetrahedronCoords[3] = xB;
TetrahedronCoords[4] = yB;
TetrahedronCoords[5] = zB;
TetrahedronCoords[6] = xC;
TetrahedronCoords[7] = yC;
TetrahedronCoords[8] = zC;
TetrahedronCoords[9] = xD;
TetrahedronCoords[10] = yD;
TetrahedronCoords[11] = zD;
} //get_tetrahedron_coords
///-------------------------------------------------------------------------
/** @fn get_tetrahedron_volume
* Get volume of a tetrahedron
* @param TetrahedronCoords input tetrahedron vertices positions
* @return volume in UnitLength**3 (typically (Mpc/h)**3)
*/
static inline double
get_tetrahedron_volume(const double *TetrahedronCoords) {
double xA, yA, zA, xB, yB, zB, xC, yC, zC, xD, yD, zD;
xA = TetrahedronCoords[0];
yA = TetrahedronCoords[1];
zA = TetrahedronCoords[2];
xB = TetrahedronCoords[3];
yB = TetrahedronCoords[4];
zB = TetrahedronCoords[5];
xC = TetrahedronCoords[6];
yC = TetrahedronCoords[7];
zC = TetrahedronCoords[8];
xD = TetrahedronCoords[9];
yD = TetrahedronCoords[10];
zD = TetrahedronCoords[11];
// triple scalar product of the vectors
// a factor of 6 because the cube is tessellated into 6 tetrahedra
// (section 2.2 in Abel, Hahn & Kaehler 2012)
Eigen::Matrix3d M;
M << xB - xA, xC - xA, xD - xA,
yB - yA, yC - yA, yD - yA,
zB - zA, zC - zA, zD - zA;
return (double)M.determinant() / 6.;
} //get_tetrahedron_volume
///-------------------------------------------------------------------------------------
/** @fn isInTetrahedron
* Check if a spatial position is inside a tetrahedron
* @param TetrahedronCoords input tetrahedron vertices coordinates
* @param xP position x
* @param yP position y
* @param zP position z
*/
static bool isInTetrahedron(
const double *TetrahedronCoords, const double D0, const double xP,
const double yP, const double zP) {
double xA, yA, zA, xB, yB, zB, xC, yC, zC, xD, yD, zD;
xA = TetrahedronCoords[0];
yA = TetrahedronCoords[1];
zA = TetrahedronCoords[2];
xB = TetrahedronCoords[3];
yB = TetrahedronCoords[4];
zB = TetrahedronCoords[5];
xC = TetrahedronCoords[6];
yC = TetrahedronCoords[7];
zC = TetrahedronCoords[8];
xD = TetrahedronCoords[9];
yD = TetrahedronCoords[10];
zD = TetrahedronCoords[11];
Eigen::Matrix4d M1, M2, M3, M4;
// As a consistency check, D0 should be D1+D2+D3+D4
M1 << xP, yP, zP, 1., xB, yB, zB, 1., xC, yC, zC, 1., xD, yD, zD, 1.;
double D1 = M1.determinant();
if (!sameSign(D1, D0))
return false;
M2 << xA, yA, zA, 1., xP, yP, zP, 1., xC, yC, zC, 1., xD, yD, zD, 1.;
double D2 = M2.determinant();
if (!sameSign(D2, D0))
return false;
M3 << xA, yA, zA, 1., xB, yB, zB, 1., xP, yP, zP, 1., xD, yD, zD, 1.;
double D3 = M3.determinant();
if (!sameSign(D3, D0))
return false;
M4 << xA, yA, zA, 1., xB, yB, zB, 1., xC, yC, zC, 1., xP, yP, zP, 1.;
double D4 = M4.determinant();
if (!sameSign(D4, D0))
return false;
return true;
} //isInTetrahedron
///-------------------------------------------------------------------------
/** @fn aux_get_masstracer_coords
* Subroutine of get_masstracer_coords
*/
static void aux_get_masstracer_coords(
const double xS, const double yS, const double zS, const double xM,
const double yM, const double zM, double *MassTracerCoords) {
// Matches the monopole and quadrupole moments
// of the mass distribution of the homogeneous tetrahedron
// (section 2.2 in Hahn, Abel & Kaehler 2013)
MassTracerCoords[0] = INV_SQRT_5 * xS + ONE_MINUS_INV_SQRT_5 * xM;
MassTracerCoords[1] = INV_SQRT_5 * yS + ONE_MINUS_INV_SQRT_5 * yM;
MassTracerCoords[2] = INV_SQRT_5 * zS + ONE_MINUS_INV_SQRT_5 * zM;
} //aux_get_masstracer_coords
///-------------------------------------------------------------------------
/** @fn get_masstracer_coords
* Get coordinates of the mass tracer for one side of a tetrahedron
* @param TetrahedronCoords input tetrahedron vertices coordinates
* @param iside the id of the tetrahedron side (0 to 4)
* @param MassTracerCoords output coordinates of the mass tracer
*/
static void get_masstracer_coords(
const double *TetrahedronCoords, const int iside,
double *MassTracerCoords) {
double xA, yA, zA, xB, yB, zB, xC, yC, zC, xD, yD, zD, xM, yM, zM;
xA = TetrahedronCoords[0];
yA = TetrahedronCoords[1];
zA = TetrahedronCoords[2];
xB = TetrahedronCoords[3];
yB = TetrahedronCoords[4];
zB = TetrahedronCoords[5];
xC = TetrahedronCoords[6];
yC = TetrahedronCoords[7];
zC = TetrahedronCoords[8];
xD = TetrahedronCoords[9];
yD = TetrahedronCoords[10];
zD = TetrahedronCoords[11];
xM = (xA + xB + xC + xD) / 4;
yM = (yA + yB + yC + yD) / 4;
zM = (zA + zB + zC + zD) / 4;
switch (iside) {
case 0:
aux_get_masstracer_coords(xA, yA, zA, xM, yM, zM, MassTracerCoords);
break;
case 1:
aux_get_masstracer_coords(xB, yB, zB, xM, yM, zM, MassTracerCoords);
break;
case 2:
aux_get_masstracer_coords(xC, yC, zC, xM, yM, zM, MassTracerCoords);
break;
case 3:
aux_get_masstracer_coords(xD, yD, zD, xM, yM, zM, MassTracerCoords);
break;
}
} //get_masstracer_coords
} // namespace DM_Sheet
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 2
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2016-2018
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2018
// ARES TAG: email(1) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,58 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/dm_sheet/tools.hpp
Copyright (C) 2016-2018 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2018 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_DMSHEET_TOOLS_HPP
# define __LIBLSS_DMSHEET_TOOLS_HPP
# include <cmath>
namespace LibLSS {
namespace DM_Sheet {
///-------------------------------------------------------------------------------------
/** @fn p_mod
* Replaces function modulo, treats differently negative values
* @param x
* @param y should be positive, else replaced by -y
* @return value between 0 and y
*/
template <typename T>
inline T p_mod(const T x, const T y) {
if (y == 0)
return 0;
T yy = std::abs(y);
return std::fmod(x + yy, yy);
} //p_mod
static bool sameSign(double x, double y) {
double xy = x*y;
return xy >= 0.;
} //sameSign
static void
periodic_boundary_correct(const double xmax, double &xA, const double L0) {
if ((xmax - xA) > (L0 - xmax) + xA)
xA += L0;
} //periodic_boundary_correct
} // namespace DM_Sheet
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 2
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2016-2018
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2018
// ARES TAG: email(1) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,198 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/velocity/velocity_sic.cpp
Copyright (C) 2019-2020 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2019-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/physics/velocity/velocity_sic.hpp"
#include "libLSS/physics/dm_sheet/dm_sheet.hpp"
using namespace LibLSS;
using namespace LibLSS::VelocityModel;
typedef U_Array<double, 4> U_VFieldType;
typedef U_Array<double, 1> U_ParticleBasedScalar;
typedef U_Array<double, 2> U_ParticleBasedArray;
typedef ParticleBasedForwardModel::PhaseSubArray::index_range range;
/**
* @brief
*
* This computes the velocity field by CiC projection of particles
*
* @param VelocityField
*/
void SICModel::getVelocityField(arrayVelocityField_t VelocityField) {
boost::multi_array_types::index_gen i_gen;
typedef boost::multi_array_types::index_range range;
LibLSS::ConsoleContext<LOG_DEBUG> ctx("SICModel::getVelocityField");
// get particles' positions and velocities from the forward model
auto ids = p_model->getLagrangianIdentifiers();
auto positions = p_model->getParticlePositions();
auto velocities = p_model->getParticleVelocities();
unsigned int srate = p_model->getSupersamplingRate();
// get number of particles, box specifications, FFTW manager and MPI communicator from forward model
size_t numParticles = p_model->getNumberOfParticles();
BoxModel model_box = model->get_box_model();
BoxModel box = outputBox;
MPI_Communication *comm = model->communicator();
size_t startN0 = mgr.startN0;
size_t endN0 = startN0 + mgr.localN0;
size_t N1 = mgr.N1;
size_t N2 = mgr.N2;
typedef std::unique_ptr<U_Array<double, 3>> U_3d;
typedef std::unique_ptr<U_Array<double, 4>> U_4d;
// initialize VelocityField and MassField to zero
fwrap(VelocityField) = 0;
size_t thread_max = smp_get_max_threads();
std::unique_ptr<U_3d[]> threaded_density_array(new U_3d[thread_max]);
std::unique_ptr<U_4d[]> threaded_velocity_array(new U_4d[thread_max]);
ctx.format("Allocating temporary output array, max_threads = %d", thread_max);
for (size_t i = 0; i < thread_max; i++) {
threaded_density_array[i] =
U_3d(new U_3d::element_type(boost::extents[box.N0][box.N1][box.N2]));
threaded_velocity_array[i] =
U_4d(new U_4d::element_type(boost::extents[box.N0][box.N1][box.N2][3]));
}
ctx.print("Go parallel and compute velocity/density");
#pragma omp parallel
{
size_t tid = smp_get_thread_id();
size_t id_min = tid * numParticles / smp_get_num_threads();
size_t id_max = (tid + 1) * numParticles / smp_get_num_threads();
fwrap(*threaded_density_array[tid]) = 0;
fwrap(*threaded_velocity_array[tid]) = 0;
DM_Sheet::get_mass_and_momenta_tetrahedra(
ids[i_gen[range(id_min, id_max)]], positions, velocities, model_box.L0,
model_box.L1, model_box.L2, srate * model_box.N0, srate * model_box.N1,
srate * model_box.N2, box.N0, box.N1, box.N2,
threaded_density_array[tid]->get_array(),
threaded_velocity_array[tid]->get_array());
}
// divide momenta by density and normalize to get the velocity field
ctx.print("Final reduction");
for (size_t i = 0; i < thread_max; i++) {
if (i > 0) {
auto out_w = fwrap(threaded_density_array[0]->get_array());
out_w = out_w + fwrap(threaded_density_array[i]->get_array());
}
for (int k = 0; k < 3; k++) {
auto out_v = fwrap(VelocityField[k]);
out_v =
out_v + fwrap(threaded_velocity_array[i]
->get_array()[i_gen[range()][range()][range()][k]]);
}
}
auto out = fwrap(threaded_density_array[0]->get_array());
for (unsigned int k = 0; k < 3; k++) {
auto v = fwrap(VelocityField[i_gen[k][range()][range()][range()]]);
v = p_model->getVelocityMultiplier() * v / out;
}
} //getVelocityField
void SICModel::computeAdjointModel(arrayVelocityField_view_t AGVelocityField) {
LIBLSS_AUTO_DEBUG_CONTEXT(ctx);
} //computeAdjointModel
void LibLSS::computeSICVelocityField(
DM_Sheet::arrayID_t const &identifiers,
DM_Sheet::arrayPosition_t const &pos, DM_Sheet::arrayVelocity_t const &vels,
double L, int N, int Ng, boost::multi_array_ref<double, 3> &DensityField,
VelocityModel::ParticleBasedModel::arrayVelocityField_t &VelocityField) {
boost::multi_array_types::index_gen i_gen;
typedef boost::multi_array_types::index_range range;
LIBLSS_AUTO_DEBUG_CONTEXT(ctx);
// get particles' positions and velocities from the forward model
auto ids = identifiers[i_gen[range()]];
auto positions = pos[i_gen[range()][range()]];
auto velocities = vels[i_gen[range()][range()]];
long numParticles = ids.shape()[0];
typedef std::unique_ptr<U_Array<double, 3>> U_3d;
typedef std::unique_ptr<U_Array<double, 4>> U_4d;
// initialize VelocityField and MassField to zero
fwrap(VelocityField) = 0;
size_t thread_max = smp_get_max_threads();
std::unique_ptr<U_3d[]> threaded_density_array(new U_3d[thread_max]);
std::unique_ptr<U_4d[]> threaded_velocity_array(new U_4d[thread_max]);
ctx.format("Allocating temporary output array, max_threads = %d", thread_max);
for (size_t i = 0; i < thread_max; i++) {
threaded_density_array[i] =
U_3d(new U_3d::element_type(boost::extents[Ng][Ng][Ng]));
threaded_velocity_array[i] =
U_4d(new U_4d::element_type(boost::extents[Ng][Ng][Ng][3]));
}
ctx.print("Go parallel and compute velocity/density");
#pragma omp parallel
{
size_t tid = smp_get_thread_id();
size_t id_min = tid * numParticles / smp_get_num_threads();
size_t id_max = (tid + 1) * numParticles / smp_get_num_threads();
fwrap(*threaded_density_array[tid]) = 0;
fwrap(*threaded_velocity_array[tid]) = 0;
DM_Sheet::get_mass_and_momenta_tetrahedra(
ids[i_gen[range(id_min, id_max)]], positions, velocities, L, L, L, N, N,
N, Ng, Ng, Ng, threaded_density_array[tid]->get_array(),
threaded_velocity_array[tid]->get_array());
}
// divide momenta by density and normalize to get the velocity field
ctx.print("Final reduction");
auto out_w = fwrap(threaded_density_array[0]->get_array());
for (size_t i = 0; i < thread_max; i++) {
if (i > 0) {
out_w = out_w + fwrap(threaded_density_array[i]->get_array());
}
for (int k = 0; k < 3; k++) {
auto out_v = fwrap(VelocityField[k]);
out_v =
out_v + fwrap(threaded_velocity_array[i]
->get_array()[i_gen[range()][range()][range()][k]]);
}
}
for (unsigned int k = 0; k < 3; k++) {
auto v = fwrap(VelocityField[i_gen[k][range()][range()][range()]]);
v = v / out_w;
}
fwrap(DensityField) = out_w;
}
// ARES TAG: authors_num = 2
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2019-2020
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2019-2020
// ARES TAG: email(1) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,81 @@
/*+
ARES/HADES/BORG Package -- ./extra/dm_sheet/libLSS/physics/velocity/velocity_sic.hpp
Copyright (C) 2019-2020 Florent Leclercq <florent.leclercq@polytechnique.org>
Copyright (C) 2019-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#pragma once
#ifndef __LIBLSS_PHYSICS_VELOCITY_SIC
# define __LIBLSS_PHYSICS_VELOCITY_SIC
# include <boost/multi_array.hpp>
# include "libLSS/physics/velocity/velocity.hpp"
# include "libLSS/physics/dm_sheet/dm_sheet.hpp"
namespace LibLSS {
void computeSICVelocityField(
DM_Sheet::arrayID_t const &identifiers,
DM_Sheet::arrayPosition_t const &pos,
DM_Sheet::arrayVelocity_t const &vels, double L, int N, int Ng,
boost::multi_array_ref<double, 3> &DensityField,
VelocityModel::ParticleBasedModel::arrayVelocityField_t &VelocityField);
namespace VelocityModel {
/**
* @brief Simplex-In-Cell velocity field model from BORGForwardModel
*
*/
class SICModel : public ParticleBasedModel {
protected:
LibLSS::FFTW_Manager<double, 3> mgr;
public:
/**
* @brief Construct a new SICModel object
*
* @param box_out_
* @param model_
*/
SICModel(BoxModel box_out_, particleForwardModel_t model_)
: ParticleBasedModel(box_out_, model_),
mgr(box_out_.N0, box_out_.N1, box_out_.N2, model_->communicator()) {
}
/**
* @brief Get the Mgr object
*
* @return LibLSS::FFTW_Manager<double, 3> const&
*/
LibLSS::FFTW_Manager<double, 3> const &getMgr() const { return mgr; }
void queryLocalExtents(std::array<ssize_t, 6> &e) override {
e[0] = mgr.startN0;
e[1] = mgr.startN0 + mgr.localN0;
e[2] = 0;
e[3] = mgr.N1;
e[4] = 0;
e[5] = mgr.N2;
}
void getVelocityField(arrayVelocityField_t VelocityField) override;
void
computeAdjointModel(arrayVelocityField_view_t AGVelocityField) override;
};
} // namespace VelocityModel
}; // namespace LibLSS
#endif
// ARES TAG: authors_num = 2
// ARES TAG: name(0) = Florent Leclercq
// ARES TAG: year(0) = 2019-2020
// ARES TAG: email(0) = florent.leclercq@polytechnique.org
// ARES TAG: name(1) = Guilhem Lavaux
// ARES TAG: year(1) = 2019-2020
// ARES TAG: email(1) = guilhem.lavaux@iap.fr