File fieldviewfourier.h
File List > code_source > templat > include > TempLat > lattice > field > views > fieldviewfourier.h
Go to the documentation of this file
#ifndef TEMPLAT_LATTICE_FIELD_VIEWS_FIELDVIEWFOURIER_H
#define TEMPLAT_LATTICE_FIELD_VIEWS_FIELDVIEWFOURIER_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, Franz R. Sattler, Year: 2026
#include "TempLat/lattice/algebra/helpers/confirmspace.h"
#include "TempLat/lattice/algebra/helpers/doeval.h"
#include "TempLat/lattice/algebra/helpers/ghostshunter.h"
#include "TempLat/lattice/field/abstractfield.h"
#include "TempLat/lattice/algebra/helpers/preget.h"
#include "TempLat/lattice/algebra/helpers/postget.h"
#include "TempLat/util/rangeiteration/tagliteral.h"
#include "TempLat/parallel/device.h"
#include "TempLat/parallel/device_memory.h"
#include "TempLat/parallel/device_iteration.h"
namespace TempLat
{
MakeException(FieldViewFourierWrongSpaceConfirmation);
template <typename T, size_t _NDim> class FourierView : public AbstractField<T, _NDim>
{
public:
static constexpr size_t NDim = _NDim;
using AbstractField<T, NDim>::mManager;
using AbstractField<T, NDim>::mToolBox;
template <typename R> void operator=(R &&g) { this->assign(std::forward<R>(g)); }
template <typename R> void assign(R &&g)
{
const auto layout = mToolBox->mLayouts.getFourierSpaceLayout();
onBeforeAssignment(g);
PreGet::apply(g);
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
device::apply([&](auto &&...args) { mView(args...) = DoEval::eval(g, args...); }, idx);
};
device::iteration::foreach ("FourierViewAssign", layout, functor);
PostGet::apply(g);
}
template <typename R>
requires requires(R r) {
r.ComplexFieldGet(0_c);
r.ComplexFieldGet(1_c);
}
void assign(R &&g)
{
const auto layout = mToolBox->mLayouts.getFourierSpaceLayout();
onBeforeAssignment(g);
PreGet::apply(g);
auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
{
device::apply(
[&](auto &&...args) {
const auto result = DoEval::eval(g, args...);
mView(args...) = complex<T>(result[0], result[1]);
},
idx);
};
device::iteration::foreach ("FourierViewAssign", layout, functor);
PostGet::apply(g);
}
inline auto getLocalNDHostView() const
{
// As we have no ghosts in Fourier space, we can return the full view.
return mManager->template getNDHostView<complex<T>>(memorySizes);
}
inline auto getFullNDHostView() const { return mManager->template getNDHostView<complex<T>>(memorySizes); }
inline auto getRawHostView() const { return mManager->template getRawHostView<complex<T>>(); }
template <typename R> void onBeforeAssignment(R &&g)
{
/* likewise, make sure we are in configuration space (here the FFT may be fired!). */
mManager->confirmFourierSpace();
ConfirmSpace::apply(g, mToolBox->mLayouts.getFourierSpaceLayout(), SpaceStateType::Fourier);
GhostsHunter::apply(g);
mManager->flagHostMirrorOutdated();
}
template <typename... IDX>
requires IsVariadicNDIndex<NDim, IDX...>
DEVICE_INLINE_FUNCTION complex<T> &getSet(const IDX &...idx) const
{
return mView(idx...);
}
template <typename... IDX>
requires IsVariadicNDIndex<NDim, IDX...>
DEVICE_INLINE_FUNCTION auto eval(const IDX &...idx) const
{
return mView(idx...);
}
inline void confirmSpace(const LayoutStruct<NDim> &newLayout, const SpaceStateType &spaceType) const
{
switch (spaceType) {
case SpaceStateType::Configuration:
throw FieldViewFourierWrongSpaceConfirmation("FieldViewFourier explicitly only can be used in Fourier space. "
"Do not transform to configuration space in place.");
break;
case SpaceStateType::Fourier:
default:
AbstractField<T, NDim>::confirmSpace(newLayout, spaceType);
break;
}
}
auto getView() const { return mView; }
std::string toString() const { return mManager->getName() + "(k)"; }
const auto &getLayout() const { return mToolBox->mLayouts.getFourierSpaceLayout(); }
// MPI aware setting of value. Use exceptionally (remove zero mode for example)
template <typename... Args> void setZeroMode(const complex<T> &toSet)
{
// This is dimension-aware.
device::IdxArray<NDim> global_coord{{}};
device::IdxArray<NDim> mem_pos{{}};
const auto &layout = mToolBox->mLayouts.getFourierSpaceLayout();
const bool owned = device::apply(
[&](const auto &...idx) { return layout.putMemoryIndexFromSpatialLocationInto(mem_pos, idx...); },
global_coord);
// do this only if this process owns the zero mode!
if (owned) device::memory::setAtOnePoint(*this, mem_pos, toSet);
}
std::string to_string() const { return mManager->getName() + "(k)"; }
template <typename S, size_t __NDim> friend class Field;
private:
FourierView(const AbstractField<T, NDim> &f) : AbstractField<T, NDim>(f)
{
if (mToolBox == nullptr) return;
auto layout = mToolBox->mLayouts.getFourierSpaceLayout();
memorySizes = layout.getSizesInMemory();
mView = mManager->template getNDView<complex<T>>(memorySizes);
mRawView = mManager->template getRawView<complex<T>>();
}
device::memory::NDViewUnmanaged<complex<T>, NDim> mView;
device::memory::NDViewUnmanaged<complex<T>, 1> mRawView;
device::memory::NDViewUnmanagedHost<complex<T>, NDim> mHostView;
device::IdxArray<NDim> memorySizes;
device::array<device::pair<device::Idx, device::Idx>, NDim> localSlicing;
};
} // namespace TempLat
#endif