Files
mfem/linalg/tlayout.hpp
T
Tzanio f1e04e7282 Merge branch 'master' into mfem-4.1-dev
Conflicts:
	fem/quadinterpolator.cpp
	fem/restriction.cpp
2020-03-10 16:56:01 -07:00

589 lines
17 KiB
C++

// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_TEMPLATE_LAYOUT
#define MFEM_TEMPLATE_LAYOUT
#include "../config/tconfig.hpp"
#include "../fem/fespace.hpp"
#include "../general/cuda.hpp"
#include "../general/hip.hpp"
namespace mfem
{
// Layout classes
template <int N1, int S1>
struct OffsetStridedLayout1D;
template <int N1, int S1, int N2, int S2>
struct StridedLayout2D;
template <int N1, int S1>
struct StridedLayout1D
{
static const int rank = 1;
static const int dim_1 = N1;
static const int size = N1;
MFEM_HOST_DEVICE static inline int ind(int i1)
{
return S1*i1;
}
template <int M1>
static OffsetStridedLayout1D<M1,S1> sub(int o1)
{
return OffsetStridedLayout1D<M1,S1>(S1*o1);
}
// reshape methods
template <int N1_1, int N1_2>
static StridedLayout2D<N1_1,S1,N1_2,S1*N1_1> split_1()
{
// S1*i1 == S1*(i1_1+N1_1*i1_2)
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return StridedLayout2D<N1_1,S1,N1_2,S1*N1_1>();
}
};
template <int N1, int S1, int N2, int S2>
struct OffsetStridedLayout2D;
template <int N1, int S1>
struct OffsetStridedLayout1D
{
static const int rank = 1;
static const int dim_1 = N1;
static const int size = N1;
int offset;
OffsetStridedLayout1D() { }
OffsetStridedLayout1D(int offset_) : offset(offset_) { }
MFEM_HOST_DEVICE inline int ind(int i1) const
{
return offset+S1*i1;
}
template <int M1>
OffsetStridedLayout1D<M1,S1> sub(int o1) const
{
return OffsetStridedLayout1D<M1,S1>(offset+S1*o1);
}
// reshape methods
template <int N1_1, int N1_2>
OffsetStridedLayout2D<N1_1,S1,N1_2,S1*N1_1> split_1() const
{
// S1*i1 == S1*(i1_1+N1_1*i1_2)
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return OffsetStridedLayout2D<N1_1,S1,N1_2,S1*N1_1>(offset);
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3>
struct StridedLayout3D;
template <int N1, int S1, int N2, int S2, int N3, int S3, int N4, int S4>
struct StridedLayout4D;
template <int N1, int S1, int N2, int S2>
struct StridedLayout2D
{
static const int rank = 2;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int size = N1*N2;
MFEM_HOST_DEVICE static inline int ind(int i1, int i2)
{
return (S1*i1+S2*i2);
}
static OffsetStridedLayout1D<N2,S2> ind1(int i1)
{
return OffsetStridedLayout1D<N2,S2>(S1*i1);
}
static OffsetStridedLayout1D<N1,S1> ind2(int i2)
{
return OffsetStridedLayout1D<N1,S1>(S2*i2);
}
template <int M1, int M2>
static OffsetStridedLayout2D<M1,S1,M2,S2> sub(int o1, int o2)
{
return OffsetStridedLayout2D<M1,S1,M2,S2>(S1*o1+S2*o2);
}
// reshape methods
template <int N1_1, int N1_2>
static StridedLayout3D<N1_1,S1,N1_2,S1*N1_1,N2,S2> split_1()
{
// S1*i1+S2*i2 == S1*(i1_1+N1_1*i1_2)+S2*i2
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return StridedLayout3D<N1_1,S1,N1_2,S1*N1_1,N2,S2>();
}
template <int N2_1, int N2_2>
static StridedLayout3D<N1,S1,N2_1,S2,N2_2,S2*N2_1> split_2()
{
// S1*i1+S2*i2 == S1*i1+S2*(i2_1*N2_1*i2_2)
MFEM_STATIC_ASSERT(N2_1*N2_2 == N2, "invalid dimensions");
return StridedLayout3D<N1,S1,N2_1,S2,N2_2,S2*N2_1>();
}
template <int N1_1, int N1_2, int N2_1, int N2_2>
static StridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2_1,S2,N2_2,S2*N2_1> split_12()
{
// S1*i1+S2*i2 == S1*(i1_1+N1_1*i1_2)+S2*(i2_1+N2_1*i2_2)
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1 && N2_1*N2_2 == N2,
"invalid dimensions");
return StridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2_1,S2,N2_2,S2*N2_1>();
}
static StridedLayout1D<N1*N2,(S1<S2)?S1:S2> merge_12()
{
// use: (S1*i1+S2*i2) == (S1*(i1+S2/S1*i2))
// or (S1*i1+S2*i2) == (S2*(S1/S2*i1+i2))
// assuming: S2 == S1*N1 || S1 == S2*N2
MFEM_STATIC_ASSERT(S2 == S1*N1 || S1 == S2*N2, "invalid reshape");
return StridedLayout1D<N1*N2,(S1<S2)?S1:S2>();
}
static StridedLayout2D<N2,S2,N1,S1> transpose_12()
{
return StridedLayout2D<N2,S2,N1,S1>();
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3>
struct OffsetStridedLayout3D;
template <int N1, int S1, int N2, int S2, int N3, int S3, int N4, int S4>
struct OffsetStridedLayout4D;
template <int N1, int S1, int N2, int S2>
struct OffsetStridedLayout2D
{
static const int rank = 2;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int size = N1*N2;
int offset;
OffsetStridedLayout2D() { }
OffsetStridedLayout2D(int offset_) : offset(offset_) { }
MFEM_HOST_DEVICE inline int ind(int i1, int i2) const
{
return offset+S1*i1+S2*i2;
}
OffsetStridedLayout1D<N2,S2> ind1(int i1) const
{
return OffsetStridedLayout1D<N2,S2>(offset+S1*i1);
}
OffsetStridedLayout1D<N1,S1> ind2(int i2) const
{
return OffsetStridedLayout1D<N1,S1>(offset+S2*i2);
}
template <int M1, int M2>
OffsetStridedLayout2D<M1,S1,M2,S2> sub(int o1, int o2) const
{
return OffsetStridedLayout2D<M1,S1,M2,S2>(offset+S1*o1+S2*o2);
}
// reshape methods
template <int N1_1, int N1_2>
OffsetStridedLayout3D<N1_1,S1,N1_2,S1*N1_1,N2,S2> split_1() const
{
// S1*i1+S2*i2 == S1*(i1_1+N1_1*i1_2)+S2*i2
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return OffsetStridedLayout3D<N1_1,S1,N1_2,S1*N1_1,N2,S2>(offset);
}
template <int N2_1, int N2_2>
OffsetStridedLayout3D<N1,S1,N2_1,S2,N2_2,S2*N2_1> split_2() const
{
// S1*i1+S2*i2 == S1*i1+S2*(i2_1*N2_1*i2_2)
MFEM_STATIC_ASSERT(N2_1*N2_2 == N2, "invalid dimensions");
return OffsetStridedLayout3D<N1,S1,N2_1,S2,N2_2,S2*N2_1>(offset);
}
template <int N1_1, int N1_2, int N2_1, int N2_2>
OffsetStridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2_1,S2,N2_2,S2*N2_1>
split_12() const
{
// S1*i1+S2*i2 == S1*(i1_1+N1_1*i1_2)+S2*(i2_1+N2_1*i2_2)
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1 && N2_1*N2_2 == N2,
"invalid dimensions");
return OffsetStridedLayout4D<
N1_1,S1,N1_2,S1*N1_1,N2_1,S2,N2_2,S2*N2_1>(offset);
}
OffsetStridedLayout1D<N1*N2,(S1<S2)?S1:S2> merge_12() const
{
// use: (S1*i1+S2*i2) == (S1*(i1+S2/S1*i2))
// or (S1*i1+S2*i2) == (S2*(S1/S2*i1+i2))
// assuming: S2 == S1*N1 || S1 == S2*N2
MFEM_STATIC_ASSERT(S2 == S1*N1 || S1 == S2*N2, "invalid reshape");
return OffsetStridedLayout1D<N1*N2,(S1<S2)?S1:S2>(offset);
}
OffsetStridedLayout2D<N2,S2,N1,S1> transpose_12() const
{
return OffsetStridedLayout2D<N2,S2,N1,S1>(offset);
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3>
struct StridedLayout3D
{
static const int rank = 3;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int dim_3 = N3;
static const int size = N1*N2*N3;
static inline int ind(int i1, int i2, int i3)
{
return S1*i1+S2*i2+S3*i3;
}
static OffsetStridedLayout2D<N2,S2,N3,S3> ind1(int i1)
{
return OffsetStridedLayout2D<N2,S2,N3,S3>(S1*i1);
}
static OffsetStridedLayout2D<N1,S1,N3,S3> ind2(int i2)
{
return OffsetStridedLayout2D<N1,S1,N3,S3>(S2*i2);
}
static OffsetStridedLayout2D<N1,S1,N2,S2> ind3(int i3)
{
return OffsetStridedLayout2D<N1,S1,N2,S2>(S3*i3);
}
// reshape methods
static StridedLayout2D<N1*N2,S1,N3,S3> merge_12()
{
// use: (S1*i1+S2*i2+S3*i3) == (S1*(i1+S2/S1*i2)+S3*i3)
// assuming: S2 == S1*N1
MFEM_STATIC_ASSERT(S2 == S1*N1, "invalid reshape");
return StridedLayout2D<N1*N2,S1,N3,S3>();
// alternative:
// use: (S1*i1+S2*i2+S3*i3) == (S2*(S1/S2*i1+i2)+S3*i3)
// assuming: S1 == S2*N2
// result is: StridedLayout2D<N1*N2,S2,N3,S3>
}
static StridedLayout2D<N1,S1,N2*N3,S2> merge_23()
{
// use: (S1*i1+S2*i2+S3*i3) == (S1*i1+S2*(i2+S3/S2*i3))
// assuming: S3 == S2*N2
MFEM_STATIC_ASSERT(S3 == S2*N2, "invalid reshape");
return StridedLayout2D<N1,S1,N2*N3,S2>();
}
template <int N1_1, int N1_2>
static StridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2,S2,N3,S3> split_1()
{
// S1*i1+S2*i2+S3*i3 == S1*(i1_1+N1_1*i1_2)+S2*i2+S3*i3
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return StridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2,S2,N3,S3>();
}
template <int N2_1, int N2_2>
static StridedLayout4D<N1,S1,N2_1,S2,N2_2,S2*N2_1,N3,S3> split_2()
{
// S1*i1+S2*i2+S3*i3 == S1*i1+S2*(i2_1+N2_1*i2_2)+S3*i3
MFEM_STATIC_ASSERT(N2_1*N2_2 == N2, "invalid dimensions");
return StridedLayout4D<N1,S1,N2_1,S2,N2_2,S2*N2_1,N3,S3>();
}
template <int N3_1, int N3_2>
static StridedLayout4D<N1,S1,N2,S2,N3_1,S3,N3_2,S3*N3_1> split_3()
{
// S1*i1+S2*i2+S3*i3 == S1*i1+S2*i2+S3*(i3_1+N3_1*i3_2)
MFEM_STATIC_ASSERT(N3_1*N3_2 == N3, "invalid dimensions");
return StridedLayout4D<N1,S1,N2,S2,N3_1,S3,N3_2,S3*N3_1>();
}
static StridedLayout3D<N2,S2,N1,S1,N3,S3> transpose_12()
{
return StridedLayout3D<N2,S2,N1,S1,N3,S3>();
}
static StridedLayout3D<N3,S3,N2,S2,N1,S1> transpose_13()
{
return StridedLayout3D<N3,S3,N2,S2,N1,S1>();
}
static StridedLayout3D<N1,S1,N3,S3,N2,S2> transpose_23()
{
return StridedLayout3D<N1,S1,N3,S3,N2,S2>();
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3>
struct OffsetStridedLayout3D
{
static const int rank = 3;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int dim_3 = N3;
static const int size = N1*N2*N3;
int offset;
OffsetStridedLayout3D() { }
OffsetStridedLayout3D(int offset_) : offset(offset_) { }
inline int ind(int i1, int i2, int i3) const
{
return offset+S1*i1+S2*i2+S3*i3;
}
OffsetStridedLayout2D<N2,S2,N3,S3> ind1(int i1) const
{
return OffsetStridedLayout2D<N2,S2,N3,S3>(offset+S1*i1);
}
OffsetStridedLayout2D<N1,S1,N3,S3> ind2(int i2) const
{
return OffsetStridedLayout2D<N1,S1,N3,S3>(offset+S2*i2);
}
OffsetStridedLayout2D<N1,S1,N2,S2> ind3(int i3) const
{
return OffsetStridedLayout2D<N1,S1,N2,S2>(offset+S3*i3);
}
// reshape methods
OffsetStridedLayout2D<N1*N2,S1,N3,S3> merge_12() const
{
// use: (S1*i1+S2*i2+S3*i3) == (S1*(i1+S2/S1*i2)+S3*i3)
// assuming: S2 == S1*N1
MFEM_STATIC_ASSERT(S2 == S1*N1, "invalid reshape");
return OffsetStridedLayout2D<N1*N2,S1,N3,S3>(offset);
}
OffsetStridedLayout2D<N1,S1,N2*N3,S2> merge_23() const
{
// use: (S1*i1+S2*i2+S3*i3) == (S1*i1+S2*(i2+S3/S2*i3))
// assuming: S3 == S2*N2
MFEM_STATIC_ASSERT(S3 == S2*N2, "invalid reshape");
return OffsetStridedLayout2D<N1,S1,N2*N3,S2>(offset);
}
template <int N1_1, int N1_2>
OffsetStridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2,S2,N3,S3> split_1() const
{
// S1*i1+S2*i2+S3*i3 == S1*(i1_1+N1_1*i1_2)+S2*i2+S3*i3
MFEM_STATIC_ASSERT(N1_1*N1_2 == N1, "invalid dimensions");
return OffsetStridedLayout4D<N1_1,S1,N1_2,S1*N1_1,N2,S2,N3,S3>(offset);
}
template <int N2_1, int N2_2>
OffsetStridedLayout4D<N1,S1,N2_1,S2,N2_2,S2*N2_1,N3,S3> split_2() const
{
// S1*i1+S2*i2+S3*i3 == S1*i1+S2*(i2_1+N2_1*i2_2)+S3*i3
MFEM_STATIC_ASSERT(N2_1*N2_2 == N2, "invalid dimensions");
return OffsetStridedLayout4D<N1,S1,N2_1,S2,N2_2,S2*N2_1,N3,S3>(offset);
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3, int N4, int S4>
struct StridedLayout4D
{
static const int rank = 4;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int dim_3 = N3;
static const int dim_4 = N4;
static const int size = N1*N2*N3*N4;
static inline int ind(int i1, int i2, int i3, int i4)
{
return S1*i1+S2*i2+S3*i3+S4*i4;
}
static OffsetStridedLayout2D<N1,S1,N4,S4> ind23(int i2, int i3)
{
return OffsetStridedLayout2D<N1,S1,N4,S4>(S2*i2+S3*i3);
}
static OffsetStridedLayout2D<N2,S2,N3,S3> ind14(int i1, int i4)
{
return OffsetStridedLayout2D<N2,S2,N3,S3>(S1*i1+S4*i4);
}
static OffsetStridedLayout3D<N1,S1,N2,S2,N3,S3> ind4(int i4)
{
return OffsetStridedLayout3D<N1,S1,N2,S2,N3,S3>(S4*i4);
}
static StridedLayout3D<N1*N2,S1,N3,S3,N4,S4> merge_12()
{
// use: (S1*i1+S2*i2+S3*i3+S4*i4) == (S1*(i1+S2/S1*i2)+S3*i3+S4*i4)
// assuming S2 == S1*N1
MFEM_STATIC_ASSERT(S2 == S1*N1, "invalid reshape");
return StridedLayout3D<N1*N2,S1,N3,S3,N4,S4>();
}
static StridedLayout3D<N1,S1,N2,S2,N3*N4,S3> merge_34()
{
// use: (S1*i1+S2*i2+S3*i3+S4*i4) == (S1*i1+S2*i2+S3*(i3+S4/S3*i4))
// assuming S4 == S3*N3
MFEM_STATIC_ASSERT(S4 == S3*N3, "invalid reshape");
return StridedLayout3D<N1,S1,N2,S2,N3*N4,S3>();
}
};
template <int N1, int S1, int N2, int S2, int N3, int S3, int N4, int S4>
struct OffsetStridedLayout4D
{
static const int rank = 4;
static const int dim_1 = N1;
static const int dim_2 = N2;
static const int dim_3 = N3;
static const int dim_4 = N4;
static const int size = N1*N2*N3*N4;
int offset;
OffsetStridedLayout4D() { }
OffsetStridedLayout4D(int offset_) : offset(offset_) { }
inline int ind(int i1, int i2, int i3, int i4) const
{
return offset+S1*i1+S2*i2+S3*i3+S4*i4;
}
};
template <int N1, int N2>
struct ColumnMajorLayout2D
: public StridedLayout2D<N1,1,N2,N1> { };
template <int N1, int N2, int N3>
struct ColumnMajorLayout3D
: public StridedLayout3D<N1,1,N2,N1,N3,N1*N2> { };
template <int N1, int N2, int N3, int N4>
struct ColumnMajorLayout4D
: public StridedLayout4D<N1,1,N2,N1,N3,N1*N2,N4,N1*N2*N3> { };
// Vector layout classes
class DynamicVectorLayout
{
public:
static const int vec_dim = 0; // 0 - dynamic
protected:
int scal_stride, comp_stride;
int num_components;
void Init(Ordering::Type ordering, int scalar_size, int num_comp)
{
num_components = num_comp;
if (ordering == Ordering::byNODES)
{
scal_stride = 1;
comp_stride = scalar_size;
}
else
{
scal_stride = num_comp;
comp_stride = 1;
}
}
public:
DynamicVectorLayout(Ordering::Type ordering, int scalar_size, int num_comp)
{
Init(ordering, scalar_size, num_comp);
}
DynamicVectorLayout(const FiniteElementSpace &fes)
{
Init(fes.GetOrdering(), fes.GetNDofs(), fes.GetVDim());
}
// default copy constructor
int NumComponents() const { return num_components; }
int ind(int scalar_idx, int comp_idx) const
{
return scal_stride * scalar_idx + comp_stride * comp_idx;
}
static bool Matches(const FiniteElementSpace &fes)
{
return true;
}
};
// The default value (NumComp = 0) indicates that the number of components is
// dynamic, i.e. it will be specified at run-time.
template <Ordering::Type Ord, int NumComp = 0>
class VectorLayout
{
public:
static const int vec_dim = NumComp;
protected:
int num_components, scalar_size;
public:
VectorLayout(int scalar_size_, int num_comp_ = NumComp)
: num_components(num_comp_),
scalar_size(scalar_size_)
{
MFEM_ASSERT(NumComp == 0 || num_components == NumComp,
"invalid number of components");
}
VectorLayout(const FiniteElementSpace &fes)
: num_components(fes.GetVDim()),
scalar_size(fes.GetNDofs())
{
MFEM_ASSERT(fes.GetOrdering() == Ord, "ordering mismatch");
MFEM_ASSERT(NumComp == 0 || num_components == NumComp,
"invalid number of components");
}
// default copy constructor
int NumComponents() const { return (NumComp ? NumComp : num_components); }
int ind(int scalar_idx, int comp_idx) const
{
if (Ord == Ordering::byNODES)
{
return scalar_idx + comp_idx * scalar_size;
}
else
{
return comp_idx + (NumComp ? NumComp : num_components) * scalar_idx;
}
}
static bool Matches(const FiniteElementSpace &fes)
{
return (Ord == fes.GetOrdering() &&
(NumComp == 0 || NumComp == fes.GetVDim()));
}
};
class ScalarLayout
{
public:
static const int vec_dim = 1;
ScalarLayout() { }
ScalarLayout(const FiniteElementSpace &fes)
{
MFEM_ASSERT(fes.GetVDim() == 1, "invalid number of components");
}
int NumComponents() const { return 1; }
int ind(int scalar_idx, int comp_idx) const { return scalar_idx; }
static bool Matches(const FiniteElementSpace &fes)
{
return (fes.GetVDim() == 1);
}
};
} // namespace mfem
#endif // MFEM_TEMPLATE_LAYOUT