File assignablefieldcollection.h
File List > code_source > templat > include > TempLat > lattice > field > assignablefieldcollection.h
Go to the documentation of this file
#ifndef TEMPLAT_LATTICE_FIELD_ASSIGNABLEFIELDCOLLECTION_H
#define TEMPLAT_LATTICE_FIELD_ASSIGNABLEFIELDCOLLECTION_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, Year: 2019
#include "TempLat/lattice/field/field.h"
#include "TempLat/util/shiftedindexsequence.h"
#include "TempLat/util/foreach.h"
#include "TempLat/util/concat.h"
#include "TempLat/util/istuplelike.h"
#include "TempLat/util/tuple_size.h"
#include "TempLat/util/rangeiteration/for_in_range.h"
#include "TempLat/util/tuplemaker.h"
#include "TempLat/util/flattentuple.h"
namespace TempLat
{
// if want to try to have dynamical access somehow, see
// https://www.justsoftwaresolutions.co.uk/cplusplus/getting-tuple-elements-with-runtime-index.html
// seems hardly compatible with indexed fields though.
template <class Q, class... Args> class AssignableCollectionBase
{
public:
static constexpr size_t size = sizeof...(Args);
AssignableCollectionBase(Args... args)
: // This constructor is used to create composite structure such as SU(N) matrices, from fields.
fs(std::make_tuple(args...))
{
}
void operator=(const AssignableCollectionBase<Q, Args...> &other)
{
for_in_range<0, size>([&](auto j) { std::get<j>(fs) = std::get<j>(other.fs); });
}
template <typename R>
requires(!std::is_same_v<R, AssignableCollectionBase<Q, Args...>>)
void operator=(R &&r)
{
using nakedR = std::decay_t<R>;
for_in_range<0, size>([&](auto j) { std::get<j>(fs) = nakedR::Getter::get(r, j); });
}
template <int M> auto &operator()(Tag<M> t)
{
static_assert(M >= Q::SHIFTIND && M < size + Q::SHIFTIND, "Index out of bounds in field collection.");
// Also work with operator [], but might be confusing that it is NOT an int (cant call f[1] -> f[1_c])
return std::get<M - Q::SHIFTIND>(fs);
}
template <int M> const auto &operator()(Tag<M> t) const
{
static_assert(M >= Q::SHIFTIND && M < size + Q::SHIFTIND, "Index out of bounds in field collection.");
return std::get<M - Q::SHIFTIND>(fs);
}
protected:
std::tuple<Args...> fs;
};
template <class Q> // Specialise to empty field collection, that does nothing. Useful to define general models for
// example, which may have some empty collections.
class AssignableCollectionBase<Q>
{
public:
// Put public methods here. These should change very little over time.
AssignableCollectionBase() = default;
template <int N> int operator()(Tag<N> t) { return 0; }
template <int N> int getComp(Tag<N> t) { return 0; }
template <typename R> void operator=(R &&g) {}
static constexpr size_t size = 0;
};
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int... I>
class CollectionBase : public AssignableCollectionBase<Q, Field<T, NDim>>
{
public:
using AssignableCollectionBase<Q, Field<T, NDim>>::operator=;
// Put public methods here. These should change very little over time.
template <class... Args>
CollectionBase(std::string name, device::memory::host_ptr<MemoryToolBox<NDim>> toolBox,
LatticeParameters<T> pLatPar = LatticeParameters<T>())
: AssignableCollectionBase<Q, Args...>(
Args(name + std::to_string(I - std::get<0>(std::make_tuple(I...))), toolBox, pLatPar)...)
{
}
template <class... Args>
CollectionBase(Args... args)
: // This constructor is used to create composite structure such as SU(N) matrices, from fields.
AssignableCollectionBase<Q, Args...>(args...)
{
}
private:
/* Put all member variables and private methods here. These may change arbitrarily. */
};
template <class Q, typename T, size_t NDim,
CANONICALTYPE ISMOMENTUM> // Specialise to empty field collection, that does nothing. Useful to define
// general models for example, which may have some empty collections.
class CollectionBase<Q, T, NDim, ISMOMENTUM> : public AssignableCollectionBase<Q>
{
public:
// Put public methods here. These should change very little over time.
CollectionBase(std::string name, device::memory::host_ptr<MemoryToolBox<NDim>> toolBox,
LatticeParameters<T> pLatPar = LatticeParameters<T>())
{
}
};
// Now we want to be able to use it like an array; we need to have a way to unpack an integer into a list.
// This comes from http://spraetor.github.io/2016/01/02/template-integer-sequence.html
// Unpack the FieldCollection<T,N> in CollectionBase<T,0,1,2,...> in Olog(N) compile time.
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int Start, int End> struct CollectionHelper;
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int Start, int End>
using MakeSeqImpl_t = typename CollectionHelper<Q, T, NDim, ISMOMENTUM, Start, End>::type;
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int N>
using MakeSeq_t = typename CollectionHelper<Q, T, NDim, ISMOMENTUM, 0, N - 1>::type;
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int... I1s, int... I2s>
struct Concat<CollectionBase<Q, T, NDim, ISMOMENTUM, I1s...>, CollectionBase<Q, T, NDim, ISMOMENTUM, I2s...>> {
using type = CollectionBase<Q, T, NDim, ISMOMENTUM, I1s..., I2s...>;
};
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int Start, int End> struct CollectionHelper {
using type = Concat_t<MakeSeqImpl_t<Q, T, NDim, ISMOMENTUM, Start, (Start + End) / 2>,
MakeSeqImpl_t<Q, T, NDim, ISMOMENTUM, (Start + End) / 2 + 1, End>>;
};
// break condition:
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int I>
struct CollectionHelper<Q, T, NDim, ISMOMENTUM, I, I> {
using type = CollectionBase<Q, T, NDim, ISMOMENTUM, I>;
};
// template <typename T, CANONICALTYPE ISMOMENTUM, int N, int SHIFT = 0>
// using FieldCollection = typename CollectionHelper<T,ISMOMENTUM, SHIFT,N+SHIFT-1>::type;
// This allows to switch between empty and non empty field collection.
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int N, int SHIFT, bool ENABLE>
struct CollectionSelector {
using type = CollectionBase<Q, T, NDim, ISMOMENTUM>;
};
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int N, int SHIFT>
struct CollectionSelector<Q, T, NDim, ISMOMENTUM, N, SHIFT, false> {
using type = typename CollectionHelper<Q, T, NDim, ISMOMENTUM, SHIFT, N + SHIFT - 1>::type;
};
template <class Q, typename T, size_t NDim, CANONICALTYPE ISMOMENTUM, int N, int SHIFT>
using Collection = typename CollectionSelector<Q, T, NDim, ISMOMENTUM, N, SHIFT, N == 0>::type;
} // namespace TempLat
#endif