Skip to content

File fieldviewconfig.h

File List > code_source > templat > include > TempLat > lattice > field > views > fieldviewconfig.h

Go to the documentation of this file

#ifndef TEMPLAT_LATTICE_FIELD_VIEWS_FIELDVIEWCONFIG_H
#define TEMPLAT_LATTICE_FIELD_VIEWS_FIELDVIEWCONFIG_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: 2025

#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/memory/memorylayouts/layoutstruct.h"

#include "TempLat/lattice/algebra/helpers/preget.h"
#include "TempLat/lattice/algebra/helpers/postget.h"

#include "TempLat/parallel/device.h"
#include "TempLat/parallel/device_memory.h"
#include "TempLat/parallel/device_iteration.h"

namespace TempLat
{
  MakeException(FieldViewConfigWrongSpaceConfirmation);
  MakeException(FieldViewConfigMissingToolBox);

  template <typename T, size_t _NDim> class ConfigView : public AbstractField<T, _NDim>
  {
  public:
    // Put public methods here. These should change very little over time.
    static constexpr size_t NDim = _NDim;

    using AbstractField<T, NDim>::mManager;
    using AbstractField<T, NDim>::mToolBox;

    ConfigView(std::string name, device::memory::host_ptr<MemoryToolBox<NDim>> toolBox, LatticeParameters<T> pLatPar)
        : AbstractField<T, NDim>(name, toolBox, pLatPar), mDisableFFTBlocking(false)
    {
      if (toolBox != nullptr)
        mLayout = mToolBox->mLayouts.getConfigSpaceLayout();
      else
        throw FieldViewConfigMissingToolBox("A FieldViewConfig must be constructed with a valid MemoryToolBox.");

      mManager->setGhostsAreStale();
      mManager->confirmConfigSpace(); // allocation happens here

      const auto localSizes = mLayout.getLocalSizes();
      const size_t nGhosts = mLayout.getNGhosts();

      memorySizes = mLayout.getSizesInMemory();
      for (size_t d = 0; d < NDim; ++d) {
        memorySizes[d] += nGhosts + nGhosts; // add padding to the local sizes
        localSlicing[d] = std::make_pair(nGhosts, nGhosts + localSizes[d]);
      }

      mView = mManager->getNDView(memorySizes);
      mRawView = mManager->getRawView();
    }

    auto getView() const { return mView; }

    template <typename R> void assign(R &&g)
    {
      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 ("ConfigViewAssign", mLayout, functor);

      PostGet::apply(g);

      mManager->setGhostsAreStale();
    }

    inline auto getLocalNDHostView() const { return mManager->getNDHostSubView(memorySizes, localSlicing); }
    inline auto getFullNDHostView() const { return mManager->getNDHostView(memorySizes); }
    inline auto getRawHostView() const { return mManager->getRawHostView(); }

    template <typename R> void operator=(R &&g) { this->assign(std::forward<R>(g)); }

    template <typename R> void operator+=(R &&g) { this->operator=(*this + g); }

    void operator=(const ConfigView<T, NDim> &other) { this->assign(other); }

    template <typename... IDX>
      requires IsVariadicNDIndex<NDim, IDX...>
    DEVICE_INLINE_FUNCTION T &getSet(IDX &&...idx) const
    {
      return mView(idx...);
    }

    inline void confirmSpace(const LayoutStruct<NDim> &newLayout, const SpaceStateType &spaceType) const
    {
      switch (spaceType) {
      case SpaceStateType::Fourier:
        if (!mDisableFFTBlocking)
          throw FieldViewConfigWrongSpaceConfirmation(
              "FieldViewConfig explicitly only can be used in configuration space. Do not transform to Fourier space "
              "in place. Or, if you know what you are doing and you are not doing multiple in-place FFT's on your "
              "integration data, you can call Field<T>::setDisableFFTBlocking() to disable this block, and enable "
              "going from configuration to Fourier space.");
        break;
      case SpaceStateType::Configuration:
      default:
        AbstractField<T, NDim>::confirmSpace(newLayout, spaceType);
        break;
      }
    }

    const auto &getLayout() const { return mLayout; }

    void updateGhosts() const { this->mManager->updateGhosts(); }

    std::string toString() const { return mManager->getName() + "(x)"; }

    void setDisableFFTBlocking() { mDisableFFTBlocking = true; }

    template <typename... IDX>
      requires IsVariadicNDIndex<NDim, IDX...>
    DEVICE_INLINE_FUNCTION auto eval(const IDX &...idx) const
    {
      return mView(idx...);
    }

    template <typename R> void onBeforeAssignment(R &&g)
    {
      /* likewise, make sure we are in configuration space (here the FFT may be fired!). */
      mManager->confirmConfigSpace();

      ConfirmSpace::apply(g, mLayout, SpaceStateType::Configuration);

      GhostsHunter::apply(g);
      mManager->flagHostMirrorOutdated();
    }

    std::string to_string() const { return mManager->getName() + "(x)"; }

  private:
    LayoutStruct<NDim> mLayout;

    device::memory::NDViewUnmanaged<T, NDim> mView;
    device::memory::NDViewUnmanaged<T, 1> mRawView;
    device::memory::NDViewUnmanagedHost<T, NDim> mHostView;

    device::IdxArray<NDim> memorySizes;
    device::array<std::pair<device::Idx, device::Idx>, NDim> localSlicing;

    bool mDisableFFTBlocking;
  };
} // namespace TempLat

#endif