50368046bc
* 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>
587 lines
17 KiB
C++
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
|