Skip to content

File complexfield.h

File List > algebra > complexalgebra > complexfield.h

Go to the documentation of this file

#ifndef COSMOINTERFACE_COMPLEXFIELDALGEBRA_COMPLEXFIELD_H
#define COSMOINTERFACE_COMPLEXFIELDALGEBRA_COMPLEXFIELD_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): Adrien Florio, Franz R. Sattler, Year: 2025

#include "TempLat/parallel/device.h"
#include "TempLat/lattice/field/assignablefieldcollection.h"
#include "TempLat/lattice/algebra/complexalgebra/helpers/complexfieldget.h"
#include "TempLat/lattice/algebra/helpers/getdx.h"
#include "TempLat/lattice/algebra/helpers/getkir.h"
#include "TempLat/lattice/algebra/complexalgebra/complexwrapper.h"
#include "TempLat/lattice/algebra/complexalgebra/complexfieldfourierview.h"
#include "TempLat/lattice/algebra/helpers/isvariadicindex.h"
#include <memory>

namespace TempLat
{
  template <typename T, size_t _NDim = 0> class ComplexField
  {
  public:
    // Put public methods here. These should change very little over time.
    static_assert(_NDim != 0, "NDim template parameter is required. Use e.g. ComplexField<double, 3>.");

    static constexpr size_t NDim = _NDim;

    ComplexField(Field<T, NDim> f1, Field<T, NDim> f2)
        : mR(f1), mI(f2), mName("complex(" + f1.getName() + ", " + f2.getName() + ")"),
          mToolBox(mR.getToolBox() == nullptr ? mI.getToolBox() : mR.getToolBox()),
          mLayout(mToolBox->mLayouts.getConfigSpaceLayout())
    {
    }

    ComplexField(std::string name, device::memory::host_ptr<MemoryToolBox<NDim>> toolBox,
                 LatticeParameters<T> pLatPar = LatticeParameters<T>())
        : mR("Re_" + name, toolBox, pLatPar), mI("Im_" + name, toolBox, pLatPar), mName(name), mToolBox(toolBox),
          mLayout(mToolBox->mLayouts.getConfigSpaceLayout())
    {
    }

    auto &ComplexFieldGet(Tag<0> t) { return mR; }
    const auto &ComplexFieldGet(Tag<0> t) const { return mR; }
    auto &operator()(Tag<0> t) { return mR; }
    const auto &operator()(Tag<0> t) const { return mR; }

    auto &ComplexFieldGet(Tag<1> t) { return mI; }
    const auto &ComplexFieldGet(Tag<1> t) const { return mI; }
    auto &operator()(Tag<1> t) { return mI; }
    const auto &operator()(Tag<1> t) const { return mI; }

    template <int N> auto &operator()(Tag<N> t)
    {
      static_assert(N >= 0 && N <= 1, "Operator(): N must be 0 or 1 for ComplexField");
      return ComplexFieldGet(t);
    }
    template <int N> const auto &operator()(Tag<N> t) const
    {
      static_assert(N >= 0 && N <= 1, "Operator(): N must be 0 or 1 for ComplexField");
      return ComplexFieldGet(t);
    }

    template <typename... IDX>
      requires IsVariadicNDIndex<NDim, IDX...>
    DEVICE_INLINE_FUNCTION auto eval(const IDX &...idx) const
    {
      device::array<T, 2> result;
      result[0] = mR.eval(idx...);
      result[1] = mI.eval(idx...);
      return result;
    }

    ComplexFieldFourierView<T, NDim> inFourierSpace() { return {mR.inFourierSpace(), mI.inFourierSpace()}; }

    template <typename R> void operator=(R &&g)
    {
      const auto &gR = ComplexFieldGetter::get(g, 0_c);
      const auto &gI = ComplexFieldGetter::get(g, 1_c);

      mR.onBeforeAssignment(gR);
      mI.onBeforeAssignment(gI);

      PreGet::apply(g);

      const auto viewR = mR.getView();
      const auto viewI = mI.getView();

      auto functor = DEVICE_CLASS_LAMBDA(const device::IdxArray<NDim> &idx)
      {
        device::apply(
            [&](auto &&...args) {
              auto result = DoEval::eval(g, args...);
              viewR(args...) = result[0];
              viewI(args...) = result[1];
            },
            idx);
      };
      device::iteration::foreach ("ComplexConfigViewAssign", mLayout, functor);

      PostGet::apply(g);

      mR.setGhostsAreStale();
      mI.setGhostsAreStale();
    }

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

    std::string toString() const { return *mName; }

    auto getDx() const { return mR.getDx(); }
    auto getKIR() const { return mR.getKIR(); }

    void updateGhosts()
    {
      MemoryManager<T, NDim> *mgrs[] = {mR.getMemoryManager().get(), mI.getMemoryManager().get()};
      MemoryManager<T, NDim>::updateGhostsBatch(mgrs);
    }

    void setGhostsAreStale()
    {
      mR.setGhostsAreStale();
      mI.setGhostsAreStale();
    }

    using Getter = ComplexFieldGetter;
    static constexpr size_t SHIFTIND = 0;
    static constexpr size_t size = 2;

  private:
    /* Put all member variables and private methods here. These may change arbitrarily. */
    Field<T, NDim> mR;
    Field<T, NDim> mI;

    device::memory::host_string mName;

    device::memory::host_ptr<MemoryToolBox<NDim>> mToolBox;

    LayoutStruct<NDim> mLayout;
  };

  template <typename T, size_t NDim> auto CField(Field<T, NDim> f1, Field<T, NDim> f2)
  {
    return ComplexField<T, NDim>(f1, f2);
  }
} // namespace TempLat

#endif