Files
mfem/linalg/tlayout.hpp
T
John CamiercamierjsVladimir Z TomovMittal, Ketan <mittal3@llnl.gov>
50368046bc [TMOP] Simplify kernels (#3658)
* Simplify TMOP kernels, fix unit tests to run --all tests with adjusted tolerance

* make style

* Split TMOP h3s file with metrics

* TMOP kernel MFEM_HOST_DEVICE fix

* Cleanup TMOP CUDA kernels from base class

* Added TMOP PA metrics directory

* meld toward master

* [tmop] struct to class friends

* Simplify tmop file names

* make style

* Cleanup

* Style and vscode gitignore

* WIP resolve conflicts

* 2024 headers

* Tmop pass

* All tmop tests

* make style

* Add astyle to clang format

* make style

* Fix class visibility

* Include cleanup

* real_t pass

* style

* MFEM_REGISTER_KERNELS for TMOPAssembleGradPA_001

* make style

* add config files

* Update config

* metric_t

* wip with T

* wip

* wip T Specialization

* c++20, fmt make_format_args

* print types and values

* wip Kernel<decltype(M)>

* wip

* Working with metric_t, int, int

* C++20 ok

* C++17 cleaned

* Rename tmop files

* Sync TMOP kernels with dispatch

* make style

* Cleanup metrics

* Use TMOPKernel

* 3D metrics standalone

* Chdir assemble

* tmop 2d/3d directories

* TMOP assemble using specializations

* All TMOP kernel specializations

* MFEM_REPORT_KERNELS

* make style

* Sync with master

* Sync with master

* make style

* make style

* Removed 2d/3d TMOP sub-directories

* CMake TMOP file list update

* makefile directories order

* With style

* Re-enable vscode gitignore

* Fix merge conflicts

* make style

* Sync

* Meld toward master

* Changes toward master

* make style

* Meld back fem tmop files

* Fix TMOP_Integrator friends

* PA tests fix & history bump

* Cleanup test tmop and fix energy2 metric data

* Update copyright 2010-2025

* 2D energy metrics

* 3D energy metrics

* make style

* Simplify metric registration

* TMOP fem kernels with double buffering

* grad3, grad3_coef

* grad3_coef, grad3, mult3_coefs, mult3

* TMOP sm kernels tools

* Rename kernels smem and use regs

* Grad3 w/ vector reg grad

* Kernel register cleanup

* Add MAX_TMOP_1D and HIP tmop ctests

* Add kernels_foreach

* Add kernels foreach

* Prefix foreach_thread

* Kernels regs w/ foreach threads

* Swap Y and X in forward only

* Backward kernels_regs

* Use simplified grad3d

* Wip D1D Q1D

* Runtime D1D Q1D

* Remove T1D

* Cleanup

* AddKernelSpecializations

* Sync with SetMaxOf

* Rename to LoadDofs and use deduced templated parameters

* Grad2d & factorization

* Eval3d for grad3 coef

* Eval2d for grad2 coef

* Cleanup TMOP_SetupGradPA_C0_2D

* Use Bld and B

* Use other accessors

* TMOPAddMultPA3D

* TMOP_AddMultPA_C0_2D

* TMOP_AddMultGradPA_3D

* TMOP_AddMultGradPA_2D

* TMOP_AddMultGradPA_C0_3D

* AddMultGradPA_C0_2D

* TMOP_AssembleDiagonalPA_2D

* Wip TMOP_AssembleDiagonalPA_C0_3D

* TMOP_AssembleDiagonalPA_3D

* TMOP_MinDetJpr_3D

* TMOP_EnergyPA_C0_2D

* TMOPEnergyPA3D

* TMOP_TcIdealShapeGivenSize_3D

* TMOP_DatcSize_3D

* Remove MAX_TMOP_1D

* Remove smem kernels

* TMOP cleanup

* TMOP - solve for displacements #4694 changes

* Cleanup and move verifications

* Rename TMOP Assemble kernels

* Move kernel regs to TMOP pa

* make style

* Meld back toward master

* Meld back to master

* Use static constexpr

* Temporary branch-history

* Help msvc with namespaces

* MSVC inner static constexpr

* Move regs to mfem namespace

* MSVC all static constexpr

* TMOP_AssembleDiagPA_C0_3D w/o regs

* Avoid set but unused variable

* MSVC TMOP_AssembleDiagPA_C0_3D ternary test try

* MSVC MFEM_TMOP_REGISTER_MDQ_KERNEL

* Switch to MFEM_TMOP_MDQ_REGISTER

* MSVC help with static constexpr

* MSVC conversions try

* MSVC as_regs2d_ref

* MSVC Explicitly bind as reference

* MSCV with reinterpret_cast

* MSVC avoiding required l-values

* MSVC avoid explicit ref bindings

* MSVC avoid explicit ref bindings 2D

* Cleanup

* Enable MFEM_TMOP_PA_DEVICE with makefile

* TMOP tests w/o Kernel Specializations

* TMOP re-enable kernels specializations

* TMOP PA tests tolerances

* TMOP tests adjustments

* Fix transposed eval regs access

* MSVC remove not allowed dllimport definitions

* MSVC linalg vector warning fix

* MSVC avoiding definition of dllimport function not allowed

* Re-enable DetKernels specializations

* Sync latest TMOP changes

* TMOP PA tests normalization wip

* Sync TMOP tests

* Remove debug file

* Meld back toward master

* Add missing tmop make source dir

* tmop shadowing, CMake & make mpi tests

* TMOP periodic tests, shadowing fix

* TMOP pa mpi tests, fix shadowing

* TMOP tighten Square01 + Combo tests

* TMOP MSVC include ordering

* Revert TMOP MPI debug device tests

* Add TMOP_DatcSize_2D

* Use mfem::future for tensor

* Move TMOP PA specific kernels to sync'ed fem kernels

* makefile source dirs fix

* use explicit namespace to avoid clash (swap)

* Revert to MFEM_FOREACH_THREAD
Use scalar/vector regs types

* Sync kernels

* Sync kernels

* Avoid applying non-zero offset to null pointer runtime error

* Remove debug include

* TMOP rename coef to limit

* Comments.

* minor

* changelog

* Replace TMOP's MFEM_FOREACH_THREAD with MFEM_FOREACH_THREAD_DIRECT

* add some missing metric IDs

* Revert branch-history

* Add missing MFEM_SYNC_THREAD in kernels
Verify TMOP isfinite energy

* UseDevice for local vectors

* make style

* No grids in TMOP_DatcSize kernels

* Remove isfinite assertions
Cleanup unused header files
Add 3D energy finite verifications

* Filter out TMOP PA tests

---------

Co-authored-by: camierjs <camierjs@Io>
Co-authored-by: Vladimir Z Tomov <tomov2@llnl.gov>
Co-authored-by: Mittal, Ketan <mittal3@llnl.gov>
2025-11-13 08:47:32 -08:00

587 lines
17 KiB
C++

// Copyright (c) 2010-2025, 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"
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