File radialprojector.h
File List > code_source > templat > include > TempLat > lattice > measuringtools > radialprojector.h
Go to the documentation of this file
#ifndef TEMPLAT_LATTICE_MEASUREMENTS_RADIALPROJECTOR_H
#define TEMPLAT_LATTICE_MEASUREMENTS_RADIALPROJECTOR_H
/* This file is part of TempLat, available at https://cosmolattice.github.io/templat .
Copyright 2021-2026 The TempLat authors, see AUTHORS.md.
Released under the MIT license, see LICENSE.md. */
// File info: Main contributor(s): Wessel Valkenburg, Year: 2019
// Modified by: Jorge Baeza-Ballesteros, Year: 2024
#include <algorithm>
#include <cstddef>
#include "TempLat/lattice/algebra/helpers/doeval.h"
#include "TempLat/lattice/measuringtools/projectionhelpers/radialprojectionresult.h"
#include "TempLat/lattice/measuringtools/projectionhelpers/unbinnedradialprojectionresult.h"
#include "TempLat/lattice/measuringtools/projectionhelpers/radialprojectionsinglequantity.h"
#include "TempLat/lattice/measuringtools/projectionhelpers/radialbincomputer.h"
#include "TempLat/lattice/algebra/operators/squareroot.h"
#include "TempLat/lattice/algebra/helpers/getgetreturntype.h"
#include "TempLat/lattice/algebra/helpers/getndim.h"
#include "TempLat/lattice/algebra/helpers/getfloattype.h"
#include "TempLat/lattice/algebra/spacestateinterface.h"
#include "TempLat/lattice/algebra/helpers/confirmspace.h"
#include "TempLat/lattice/algebra/helpers/ghostshunter.h"
#include "TempLat/lattice/algebra/helpers/getngrid.h"
namespace TempLat
{
template <typename T> class RadialProjector
{
public:
using vType = typename GetGetReturnType<T>::type;
using sType = typename GetFloatType<vType>::type;
static constexpr bool isComplexValued = GetGetReturnType<T>::isComplex;
using floatType = typename RadialProjectionResult<sType>::floatType;
using resultType = RadialProjectionResult<sType>;
static constexpr size_t NDim = GetNDim::get<T>();
RadialProjector(const T &instance, SpaceStateType spaceType, device::memory::host_ptr<MemoryToolBox<NDim>> pToolBox,
bool pUseCentralBinValues)
: mSpaceType(spaceType), mInstance(instance), mToolBox(pToolBox), mUseBinCentralValues(pUseCentralBinValues),
mLayout((mSpaceType == SpaceStateType::Fourier) ? mToolBox->mLayouts.getFourierSpaceLayout()
: mToolBox->mLayouts.getConfigSpaceLayout())
{
}
RadialProjectionResult<sType> measure(sType maxValue, sType deltakBins = 1, bool excludeOrigin = true)
{
sType minValue = !excludeOrigin ? 0.0 : deltakBins >= 1.0 ? 0.5 : 1.0 - deltakBins / 2.;
device::Idx nLinearBins = ceil((maxValue - minValue) / deltakBins);
RadialProjectionResult<sType> baseWorkSpace(nLinearBins, deltakBins, mUseBinCentralValues,
mSpaceType == SpaceStateType::Fourier);
RadialProjectionResult<sType> myResult =
mSpaceType == SpaceStateType::Configuration
? computeConfigurationSpace(makeBinComputer(nLinearBins, minValue, maxValue, deltakBins), baseWorkSpace,
excludeOrigin)
: computeFourierSpace(makeBinComputer(nLinearBins, minValue, maxValue, deltakBins), baseWorkSpace,
excludeOrigin);
myResult.finalize(mToolBox->mGroup.getBaseComm());
return myResult;
}
UnbinnedRadialProjectionResult<sType> measureUnbinned(device::Idx N, bool excludeOrigin = true)
{
device::Idx nLinearBins = NDim * pow<2>(N) / 4 + 1;
UnbinnedRadialProjectionResult<sType> baseWorkSpace(nLinearBins, mSpaceType == SpaceStateType::Fourier);
UnbinnedRadialProjectionResult<sType> myResult =
mSpaceType == SpaceStateType::Configuration ? computeConfigurationSpaceUnbinned(baseWorkSpace, excludeOrigin)
: computeFourierSpaceUnbinned(baseWorkSpace, excludeOrigin);
myResult.finalize(mToolBox->mGroup.getBaseComm());
return myResult;
}
private:
const SpaceStateType mSpaceType;
T mInstance;
device::memory::host_ptr<MemoryToolBox<NDim>> mToolBox;
bool mUseBinCentralValues;
LayoutStruct<NDim> mLayout;
public:
template <typename BINCOMPUTETYPE>
RadialProjectionResult<sType> computeConfigurationSpace(BINCOMPUTETYPE binComputer,
RadialProjectionResult<sType> baseWorkSpace,
bool excludeOrigin)
{
confirmGetterSpace();
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
// Get the global coordinates of this index.
device::IdxArray<NDim> global_coords;
device::apply([&](auto &&...args) { mLayout.putSpatialLocationFromMemoryIndexInto(global_coords, args...); },
idx);
// Check if we are at the origin.
bool isAtOrigin = true;
for (auto &&it : global_coords) {
if (it != 0) {
isAtOrigin = false;
break;
}
}
if (excludeOrigin && isAtOrigin) [[unlikely]]
return;
// get the radius
sType r{};
for (size_t i = 0; i < NDim; ++i)
r += global_coords[i] * global_coords[i];
r = device::sqrt(r);
// Map the radius to a bin
const device::Idx bin = binComputer(r);
// Add the bin contribution to the workspace.
device::apply(
[&](auto &&...args) { baseWorkSpace.add_device(bin, DoEval::eval(mInstance, args...), r, sType(1.)); },
idx);
};
device::iteration::foreach ("RadialProjectorConfiguration", mLayout, functor);
baseWorkSpace.pull();
binComputer.setCentralBinBounds(baseWorkSpace.getCentralBinBounds());
return baseWorkSpace;
}
template <typename BINCOMPUTETYPE>
RadialProjectionResult<sType> computeFourierSpace(BINCOMPUTETYPE binComputer,
RadialProjectionResult<sType> baseWorkSpace, bool excludeOrigin)
{
confirmGetterSpace();
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
// Get the global coordinates of this index.
device::IdxArray<NDim> global_coords;
device::apply([&](auto &&...args) { mLayout.putSpatialLocationFromMemoryIndexInto(global_coords, args...); },
idx);
// Check if we are at the origin.
bool isAtOrigin = true;
for (auto &&it : global_coords) {
if (it != 0) {
isAtOrigin = false;
break;
}
}
if (excludeOrigin && isAtOrigin) [[unlikely]]
return;
const HermitianRedundancy quality = mLayout.getHermitianPartners().qualify(global_coords);
if (quality != HermitianRedundancy::negativePartner) {
// get the radius
sType r{};
for (size_t i = 0; i < NDim; ++i)
r += global_coords[i] * global_coords[i];
r = device::sqrt(r);
// Map the radius to a bin
const device::Idx bin = binComputer(r);
// don't over-weight the real-valued entries: only one float value, only half the weight.
floatType weight = quality == HermitianRedundancy::realValued ? 0.5 : 1;
// Add the bin contribution to the workspace.
device::apply(
[&](auto &&...args) { baseWorkSpace.add_device(bin, DoEval::eval(mInstance, args...), r, weight); }, idx);
}
};
device::iteration::foreach ("RadialProjectorFourier", mLayout, functor);
baseWorkSpace.pull();
binComputer.setCentralBinBounds(baseWorkSpace.getCentralBinBounds());
return baseWorkSpace;
}
UnbinnedRadialProjectionResult<sType>
computeConfigurationSpaceUnbinned(UnbinnedRadialProjectionResult<sType> baseWorkSpace, bool excludeOrigin)
{
confirmGetterSpace();
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
// Get the global coordinates of this index.
device::IdxArray<NDim> global_coords;
device::apply([&](auto &&...args) { mLayout.putSpatialLocationFromMemoryIndexInto(global_coords, args...); },
idx);
// Check if we are at the origin.
bool isAtOrigin = true;
for (auto &&it : global_coords) {
if (it != 0) {
isAtOrigin = false;
break;
}
}
if (excludeOrigin && isAtOrigin) [[unlikely]]
return;
// get the radius
sType r2{};
for (size_t i = 0; i < NDim; ++i)
r2 += global_coords[i] * global_coords[i];
// Add the bin contribution to the workspace.
device::apply(
[&](auto &&...args) { baseWorkSpace.add_device(r2, DoEval::eval(mInstance, args...), sType(1.)); }, idx);
};
device::iteration::foreach ("UnbinnedRadialProjectorConfiguration", mLayout, functor);
baseWorkSpace.pull();
return baseWorkSpace;
}
UnbinnedRadialProjectionResult<sType>
computeFourierSpaceUnbinned(UnbinnedRadialProjectionResult<sType> baseWorkSpace, bool excludeOrigin)
{
confirmGetterSpace();
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
// Get the global coordinates of this index.
device::IdxArray<NDim> global_coords;
device::apply([&](auto &&...args) { mLayout.putSpatialLocationFromMemoryIndexInto(global_coords, args...); },
idx);
// Check if we are at the origin.
bool isAtOrigin = true;
for (auto &&it : global_coords) {
if (it != 0) {
isAtOrigin = false;
break;
}
}
if (excludeOrigin && isAtOrigin) [[unlikely]]
return;
const HermitianRedundancy quality = mLayout.getHermitianPartners().qualify(global_coords);
if (quality != HermitianRedundancy::negativePartner) {
// get the radius
sType k2{};
for (size_t i = 0; i < NDim; ++i)
k2 += global_coords[i] * global_coords[i];
// don't over-weight the real-valued entries: only one float value, only half the weight.
floatType weight = quality == HermitianRedundancy::realValued ? 0.5 : 1;
// Add the bin contribution to the workspace.
device::apply([&](auto &&...args) { baseWorkSpace.add_device(k2, DoEval::eval(mInstance, args...), weight); },
idx);
}
};
device::iteration::foreach ("RadialProjectorFourier", mLayout, functor);
baseWorkSpace.pull();
return baseWorkSpace;
}
private:
void confirmGetterSpace()
{
ConfirmSpace::apply(mInstance, mLayout, mSpaceType);
GhostsHunter::apply(mInstance);
}
inline auto makeBinComputer(device::Idx nLinearBins, sType minValue, sType maxValue = -1, sType deltakBins = -1)
{
auto rMax = maxValue < 0 ? mLayout.getMaxRadius() : maxValue;
return RadialBinComputer(minValue, rMax, nLinearBins, deltakBins);
}
};
template <size_t NDim, typename T>
RadialProjector<T> projectRadially(T instance, SpaceStateType spaceType,
device::memory::host_ptr<MemoryToolBox<NDim>> pToolBox,
bool useBinCentralValues = false)
{
return RadialProjector<T>(instance, spaceType, pToolBox, useBinCentralValues);
}
template <typename T> RadialProjector<T> projectRadially(T instance, bool useBinCentralValues = false)
{
return projectRadially(instance, SpaceStateType::Configuration, GetToolBox::get(instance), useBinCentralValues);
}
template <typename T> RadialProjector<T> projectRadiallyFourier(T instance, bool useBinCentralValues = false)
{
return projectRadially(instance, SpaceStateType::Fourier, GetToolBox::get(instance), useBinCentralValues);
}
} // namespace TempLat
#endif