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

View file

@ -0,0 +1,14 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/mpi_fftw/copy_utils.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
template<bool upgrading, typename T> struct copy_utils{};
#include "copy_utils_upgrade.hpp"
#include "copy_utils_degrade.hpp"

View file

@ -0,0 +1,148 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/mpi_fftw/copy_utils_degrade.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
// target_mgr < init_mgr here
template<typename T>
struct copy_utils<false, T> {
typedef T element;
typedef FFTW_Manager<T,3> Mgr;
typedef std::complex<T> complex_element;
template<typename OutArray, typename InArray, typename Func >
static
void _copy_sub_2d_plane(const Mgr& init_mgr, const Mgr& target_mgr, OutArray out, const InArray& in_array, const Func& func)
{
long last_plane = target_mgr.N2_HC-1;
typedef typename OutArray::reference OutRef;
typedef typename InArray::const_reference InRef;
for (long i = 0; i < target_mgr.N1/2; i++) {
for (long j = 0; j < last_plane; j++) {
func(out[i][j], in_array[i][j], false, false);
}
func(out[i][last_plane], in_array[i][last_plane], false, true);
// There is missing half sum here. But the data are not necessarily here. (conjugate on the last plane).
// The final sum is delayed.
}
long base, base2;
long out1_half_N1, out2_half_N1;
long in1_half_N1, in2_half_N1;
base = 0;
base2 = init_mgr.N1 - target_mgr.N1;
out1_half_N1 = target_mgr.N1/2;
out2_half_N1 = target_mgr.N1/2;
in1_half_N1 = target_mgr.N1/2;
in2_half_N1 = init_mgr.N1-target_mgr.N1/2;
{
OutRef out1 = out[out1_half_N1];
OutRef out2 = out[out2_half_N1];
InRef in1 = in_array[in1_half_N1];
InRef in2 = in_array[in2_half_N1];
for (long j = 0; j < last_plane; j++) {
func(out1[j], in1[j], true, false);
func(out2[j], in2[j], true, false);
}
func(out1[last_plane], in1[last_plane], true, true);
}
for (long i = target_mgr.N1/2+1; i < target_mgr.N1; i++) {
OutRef out_i = out[base+i];
InRef in_i = in_array[base2+i];
for (long j = 0; j < last_plane; j++) {
func(out_i[j], in_i[j], false, false);
}
func(out_i[last_plane], in_i[last_plane], false, true);
// There is missing half sum here. But the data are not necessarily here. (conjugate on the last plane).
// The final sum is delayed.
}
}
// This function up/downgrades the input array to output array. It assumes
// the current manager object if the high resolution and init_mgr is the low
// resolution descriptor. It transfers then the two Fourier square ([0:N1/2, 0:N2_HC] and [N1/2:N1, 0:N2_HC] to their
// adequate position in the target array.
// The array must have a 1D flat topology.
template<typename OutArray, typename FlatPlane, typename Func >
static
void _copy_sub_2d_plane_flat(const Mgr& init_mgr, const Mgr& target_mgr,
OutArray out, const FlatPlane& flat,
const Func& func = Func())
{
typedef typename OutArray::reference OutRef;
ConsoleContext<LOG_DEBUG> ctx("_copy_sub_2d_plane_flat");
long h_N2 = target_mgr.N2_HC-1;
for (long i = 0; i < target_mgr.N1/2; i++) {
for (long j = 0; j < h_N2; j++) {
func(out[i][j], flat[i*init_mgr.N2_HC + j], false, false);
}
func(out[i][h_N2], flat[i*init_mgr.N2_HC + h_N2], false, true);
}
long half1 = target_mgr.N1/2;
long half2 = init_mgr.N1 - target_mgr.N1/2;
OutRef out_half = out[half1];
for (long j = 0; j < h_N2; j++) {
func(out_half[j], flat[half1*init_mgr.N2_HC + j], true, false);
func(out_half[j], flat[half2*init_mgr.N2_HC + j], true, false);
}
func(out_half[h_N2], flat[half1*init_mgr.N2_HC + h_N2], true, true);
func(out_half[h_N2], flat[half2*init_mgr.N2_HC + h_N2], true, true);
long base = init_mgr.N1-target_mgr.N1;
for (long i = target_mgr.N1/2+1; i < target_mgr.N1; i++) {
for (long j = 0; j < h_N2; j++) {
func(out[i][j], flat[(base+i)*init_mgr.N2_HC + j], false, false);
}
func(out[i][h_N2], flat[(base+i)*init_mgr.N2_HC + h_N2], false, true);
}
}
template<typename OutArray, typename InArray >
static
void _copy_sub_2d_plane(const Mgr& init_mgr, const Mgr& target_mgr,
OutArray out, const InArray& in_array)
{
_copy_sub_2d_plane(init_mgr, target_mgr, out, in_array, internal::AssignOperator<T,false>());
}
template<typename OutArray, typename FlatPlane >
static
void _copy_sub_2d_plane_flat(const Mgr& init_mgr, const Mgr& target_mgr,
OutArray out, const FlatPlane& flat)
{
_copy_sub_2d_plane_flat(init_mgr, target_mgr, out, flat, internal::AssignOperator<T,false>());
}
static inline
const Mgr& source(const Mgr& big_mgr, const Mgr& small_mgr) { return big_mgr; }
static inline
const Mgr& target(const Mgr& big_mgr, const Mgr& small_mgr) { return small_mgr; }
template<typename OutArray, typename InArray>
static
void _flat_copy_2d_array(const Mgr& init_mgr, const Mgr& target_mgr,
OutArray& out, const InArray& in)
{
ConsoleContext<LOG_DEBUG> ctx("_flat_copy_2d_array");
boost::multi_array_ref<complex_element, 2> out_ref(out.data(), boost::extents[init_mgr.N1][init_mgr.N2_HC]);
LibLSS::copy_array(out_ref, in);
}
};

View file

@ -0,0 +1,158 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/mpi_fftw/copy_utils_upgrade.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
template<typename T>
struct copy_utils<true, T> {
typedef T element;
typedef FFTW_Manager_3d<T> Mgr;
typedef std::complex<T> complex_element;
// This function upgrades the input array to output array. It assumes
// the current manager object if the high resolution and small_mgr is the low
// resolution descriptor. It transfers then the two Fourier square ([0:N1/2, 0:N2_HC] and [N1/2:N1, 0:N2_HC] to their
// adequate position in the target array.
// The array must have a 2D shape topology.
template<typename OutArray, typename InArray, typename Func >
static
void _copy_sub_2d_plane(Mgr const& target_mgr, Mgr const& init_mgr,
OutArray out, const InArray& in_array, const Func& func)
{
long last_plane = init_mgr.N2_HC-1;
typedef typename OutArray::reference OutRef;
typedef typename OutArray::const_reference InRef;
for (long i = 0; i < init_mgr.N1/2; i++) {
for (long j = 0; j < last_plane; j++) {
func(out[i][j], in_array[i][j], false, false);
}
func(out[i][last_plane], in_array[i][last_plane], false, true);
// There is missing half sum here. But the data are not necessarily here. (conjugate on the last plane).
// The final sum is delayed.
}
long base, base2;
long out1_half_N1, out2_half_N1;
long in1_half_N1, in2_half_N1;
base = target_mgr.N1-init_mgr.N1;
base2 = 0;
out1_half_N1 = init_mgr.N1/2;
out2_half_N1 = target_mgr.N1-init_mgr.N1/2;
in1_half_N1 = init_mgr.N1/2;
in2_half_N1 = init_mgr.N1/2;
{
OutRef out1 = out[out1_half_N1];
OutRef out2 = out[out2_half_N1];
InRef in1 = in_array[in1_half_N1];
InRef in2 = in_array[in2_half_N1];
for (long j = 0; j < last_plane; j++) {
func(out1[j], in_array[in1_half_N1][j], true, false);
func(out2[j], in_array[in2_half_N1][j], true, false);
}
func(out1[last_plane], in1[last_plane], true, true);
func(out2[last_plane], in2[last_plane], true, true);
}
for (long i = init_mgr.N1/2+1; i < init_mgr.N1; i++) {
OutRef out_i = out[base+i];
InRef in_i = in_array[base2+i];
for (long j = 0; j < last_plane; j++) {
func(out_i[j], in_i[j], false, false);
}
func(out_i[last_plane], in_i[last_plane], false, true);
// There is missing half sum here. But the data are not necessarily here. (conjugate on the last plane).
// The final sum is delayed.
}
}
// This function up/downgrades the input array to output array. It assumes
// the current manager object if the high resolution and small_mgr is the low
// resolution descriptor. It transfers then the two Fourier square ([0:N1/2, 0:N2_HC] and [N1/2:N1, 0:N2_HC] to their
// adequate position in the target array.
// The array must have a 1D flat topology.
template<typename OutArray, typename FlatPlane, typename Func >
static
void _copy_sub_2d_plane_flat(Mgr const& target_mgr, Mgr const& init_mgr,
OutArray out, const FlatPlane& flat,
const Func& func = Func())
{
typedef typename OutArray::reference OutRef;
ConsoleContext<LOG_DEBUG> ctx("_copy_sub_2d_plane_flat");
for (long i = 0; i < init_mgr.N1/2; i++) {
for (long j = 0; j < init_mgr.N2_HC; j++) {
func(out[i][j], flat[i*init_mgr.N2_HC + j], false, false);
}
}
long base = target_mgr.N1-init_mgr.N1;
long half1 = init_mgr.N1/2;
long half2 = target_mgr.N1 - init_mgr.N1/2;
OutRef out_half1 = out[half1];
OutRef out_half2 = out[half2];
for (long j = 0; j < init_mgr.N2_HC; j++) {
func(out_half1[j], flat[half1*init_mgr.N2_HC + j], true, false);
func(out_half2[j], flat[half1*init_mgr.N2_HC + j], true, false);
}
for (long i = init_mgr.N1/2+1; i < init_mgr.N1; i++) {
OutRef out_i = out[base+i];
for (long j = 0; j < init_mgr.N2_HC; j++) {
func(out_i[j], flat[i*init_mgr.N2_HC + j], false, false);
}
}
}
template<typename OutArray, typename InArray >
static
void _copy_sub_2d_plane(Mgr const& target_mgr, Mgr const& init_mgr,
OutArray out,
const InArray& in_array)
{
_copy_sub_2d_plane(target_mgr, init_mgr, out, in_array, internal::AssignOperator<T,true>());
}
template<typename OutArray, typename FlatPlane >
static
void _copy_sub_2d_plane_flat(Mgr const& target_mgr, const Mgr& init_mgr,
OutArray out, const FlatPlane& flat)
{
_copy_sub_2d_plane_flat(target_mgr, init_mgr, out, flat, internal::AssignOperator<T,true>());
}
// This function transforms 2D like array into a flattened 1D array.
// This assumes that the array has the correct shape (N1 x N2_HC)
// init_mgr is always the small one
template<typename OutArray, typename InArray, typename Func>
static
void _flat_copy_2d_array(const Mgr& target_mgr, const Mgr& init_mgr,
OutArray& out, const InArray& in, const Func& func)
{
boost::multi_array_ref<complex_element, 2> out_ref(out.data(), boost::extents[init_mgr.N1][init_mgr.N2_HC]);
LibLSS::copy_array(out_ref, in);
}
template<typename OutArray, typename InArray>
static
void _flat_copy_2d_array(const Mgr& target_mgr, const Mgr& init_mgr,
OutArray& out, const InArray& in)
{
_flat_copy_2d_array(target_mgr, init_mgr, out, in, internal::AssignOperator<T,true>());
}
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,76 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/mpi_fftw/nyquist_downgrade.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
template<typename T>
struct Nyquist_adjust<T, false> {
typedef FFTW_Manager<T,3> Mgr;
typedef typename Mgr::Plane Plane;
typedef typename Mgr::U_Plane U_Plane;
typedef typename Mgr::U_Array U_Array;
typedef internal::copy_utils<false, T> c_util;
template<typename InArray, typename OutArray>
static void handle(
const Mgr& small_mgr, const Mgr& big_mgr,
std::vector<U_Plane *>& request_planes,
std::vector<bool>& request_io,
RequestArray& request_array,
const InArray& in_modes, OutArray& out_modes) {
MPI_Status status;
long N0 = small_mgr.N0;
long N1 = small_mgr.N1;
long N2 = small_mgr.N2;
long half_N0 = small_mgr.N0/2;
long big_conjugate_plane = big_mgr.N0-half_N0;
Console& cons = Console::instance();
if (small_mgr.on_core(half_N0)) {
if(big_mgr.on_core(half_N0)) {
// both planes are here. push them into out_modes
c_util::_copy_sub_2d_plane(big_mgr, small_mgr, out_modes[half_N0], in_modes[half_N0], AccumOperator<T>());
} else {
// Hmm... we have to grab the request plane
assert(request_array[half_N0].is_active());
request_array[half_N0].wait(&status);
request_io[half_N0] = false;
c_util::_copy_sub_2d_plane_flat(big_mgr, small_mgr, out_modes[half_N0], request_planes[half_N0]->get_array(), AccumOperator<T>());
internal::safe_delete(request_planes[half_N0]);
}
if (big_mgr.on_core(big_conjugate_plane)) {
// both planes are here. push them into out_modes
c_util::_copy_sub_2d_plane(big_mgr, small_mgr, out_modes[half_N0], in_modes[big_conjugate_plane], AccumOperator<T>());
} else {
assert(request_array[N0].is_active());
request_array[N0].wait(&status);
request_io[N0] = false;
c_util::_copy_sub_2d_plane_flat(big_mgr, small_mgr, out_modes[half_N0], request_planes[N0]->get_array(), AccumOperator<T>());
internal::safe_delete(request_planes[N0]);
}
// Clear up imaginary parts
out_modes[half_N0][N1/2][0].imag(0);
out_modes[half_N0][N1/2][N2/2].imag(0);
out_modes[half_N0][0][0].imag(0);
out_modes[half_N0][0][N2/2].imag(0);
}
if (small_mgr.on_core(0)) {
out_modes[0][N1/2][0].imag(0);
out_modes[0][N1/2][N2/2].imag(0);
}
// There is no point for those two.
//out_modes[0][0][0].imag() = 0;
//out_modes[0][0][N2/2].imag() = 0;
}
};

View file

@ -0,0 +1,75 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/tools/mpi_fftw/nyquist_upgrade.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
template<typename T> struct Nyquist_adjust<T, true> {
typedef FFTW_Manager<T,3> Mgr;
typedef typename Mgr::Plane Plane;
typedef typename Mgr::U_Plane U_Plane;
typedef typename Mgr::U_Array U_Array;
typedef internal::copy_utils<true, T> c_util;
template<typename InArray, typename OutArray>
static void handle(
const Mgr& small_mgr, const Mgr& big_mgr,
std::vector<U_Plane *>& request_planes,
std::vector<bool>& request_io,
RequestArray& request_array,
const InArray& in_modes, OutArray& out_modes) {
using boost::format;
Console& cons = Console::instance();
MPI_Status status;
MPI_Communication *comm = small_mgr.comm;
long half_N0 = small_mgr.N0/2;
long conjugate_big_plane = big_mgr.N0 - half_N0;
if (small_mgr.on_core(small_mgr.N0/2) && big_mgr.on_core(small_mgr.N0/2)) {
c_util::_copy_sub_2d_plane(big_mgr, small_mgr, out_modes[small_mgr.N0/2], in_modes[small_mgr.N0/2]);
}
if (small_mgr.on_core(small_mgr.N0/2) && big_mgr.on_core(conjugate_big_plane)) {
c_util::_copy_sub_2d_plane(big_mgr, small_mgr, out_modes[big_mgr.N0-small_mgr.N0/2], in_modes[small_mgr.N0/2]);
}
if (!small_mgr.on_core(half_N0) && big_mgr.on_core(half_N0)) {
U_Array& a_plane = request_planes[half_N0]->get_array();
cons.c_assert(request_planes[half_N0] != 0, "No half_N0 plane, though we need it here");
// Wait for the recv to complete
request_array[half_N0].wait(&status);
request_io[half_N0] = false;
cons.print<LOG_DEBUG>(format("Received plane %d (big is %d)") % half_N0 % half_N0);
// Copy the plane
c_util::_copy_sub_2d_plane_flat(big_mgr, small_mgr, out_modes[half_N0], a_plane);
// If the other plane is on this core, copy the data.
if (big_mgr.on_core(conjugate_big_plane)) {
c_util::_copy_sub_2d_plane_flat(big_mgr, small_mgr, out_modes[conjugate_big_plane], a_plane);
}
// Cleanup
internal::safe_delete(request_planes[half_N0]);
} else
if (!small_mgr.on_core(half_N0) && big_mgr.on_core(conjugate_big_plane)) {
// If we do not have the half_N0 plane and we are in the negative freq range
// just wait for the transfer to finish.
cons.print<LOG_DEBUG>(format("Half plane, big = %d") % conjugate_big_plane);
cons.c_assert(request_io[small_mgr.N0], "Invalid I/O state");
U_Array& a_plane = request_planes[small_mgr.N0]->get_array();
request_array[small_mgr.N0].wait(&status);
request_io[small_mgr.N0] = false;
cons.print<LOG_DEBUG>(format("Received plane %d (big is %d)") % half_N0 % conjugate_big_plane);
c_util::_copy_sub_2d_plane_flat(big_mgr, small_mgr, out_modes[conjugate_big_plane], a_plane);
internal::safe_delete(request_planes[half_N0]);
}
}
};