Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c11b2df36f | ||
|
|
1299e13e65 | ||
|
|
907a629f82 | ||
|
|
e032c15aef | ||
|
|
10ceb3e66b | ||
|
|
efa30a4a62 | ||
|
|
3ef9a5c668 | ||
|
|
7b85e1e9c1 | ||
|
|
775195b887 | ||
|
|
89adf27a44 | ||
|
|
a7dbea190f | ||
|
|
12e9b66eae | ||
|
|
713edd670d | ||
|
|
e2d6f5fb3b | ||
|
|
45b0e6e02c | ||
|
|
d37b7867ec | ||
|
|
73779b1de6 | ||
|
|
8307a751db | ||
|
|
9f12aee475 | ||
|
|
366157036e | ||
|
|
8afc1d1e36 | ||
|
|
2bc734468d | ||
|
|
c07c534f42 | ||
|
|
ccade73917 | ||
|
|
d169312edd | ||
|
|
8812081cfc | ||
|
|
b20051c06b | ||
|
|
d66068b754 | ||
|
|
362ca5b66d | ||
|
|
f9282b38f6 | ||
|
|
aab2e1ebf8 | ||
|
|
8c2a8580b6 | ||
|
|
9141e85e15 | ||
|
|
e57b63c660 | ||
|
|
5d1958cfdf | ||
|
|
8183755dbf | ||
|
|
614a355c04 | ||
|
|
79a88dfef5 | ||
|
|
bd13f53db1 | ||
|
|
eb738baebe | ||
|
|
46c5aed37b | ||
|
|
6b8f53308f | ||
|
|
1369d61457 | ||
|
|
e7d6b370dc | ||
|
|
ba07e91128 | ||
|
|
ebdf68a1c3 | ||
|
|
5f31928c2b | ||
|
|
0cf5aca53e | ||
|
|
2357771384 | ||
|
|
7efeb617b1 | ||
|
|
fe025de316 | ||
|
|
76b5f341cc | ||
|
|
ea8468ea95 | ||
|
|
2ea59935d8 | ||
|
|
4e5ebe6451 | ||
|
|
04f23f353c | ||
|
|
610a8f9c0b | ||
|
|
8f01292a45 | ||
|
|
790848019e | ||
|
|
3c9ee8ff42 | ||
|
|
8bfac662f4 | ||
|
|
ed563f3090 | ||
|
|
f14a9bb53f | ||
|
|
66dbe60cb1 | ||
|
|
f898d0bcde | ||
|
|
b8fcd640e5 | ||
|
|
86dc01be73 | ||
|
|
6e05112e5c | ||
|
|
e59487bf14 | ||
|
|
647750ffa9 | ||
|
|
eceb502df3 | ||
|
|
bfdaf07a19 | ||
|
|
31ec16fa8a | ||
|
|
c8b64fef23 | ||
|
|
195ebe8812 | ||
|
|
51a0058f65 | ||
|
|
eac57686c5 | ||
|
|
25a1c8f4a4 | ||
|
|
a60ba38833 | ||
|
|
2fa81463ae | ||
|
|
dc995c4aa0 | ||
|
|
ab6d0d9777 | ||
|
|
ffa3d0789b | ||
|
|
609a9c0e3b | ||
|
|
d6fffff08c | ||
|
|
17ecabf915 | ||
|
|
c8b1dcad70 | ||
|
|
fa006da71e | ||
|
|
1e5f9e4d6b | ||
|
|
ed9a29130f | ||
|
|
9a80c8cd14 | ||
|
|
143d7bf31b | ||
|
|
8358ee93fa | ||
|
|
eb38d6ecd8 | ||
|
|
5f80fb1eb7 | ||
|
|
52efc31130 | ||
|
|
b7dc53af15 | ||
|
|
2b5c0c6fe4 | ||
|
|
7b8af2b05f | ||
|
|
1433d4aec4 | ||
|
|
74d1579371 | ||
|
|
ea83267885 | ||
|
|
49201d41c3 | ||
|
|
50d58159bd | ||
|
|
bab4314cf3 | ||
|
|
e59d1835c3 | ||
|
|
3cdaebdcaa | ||
|
|
9e8a7c456f | ||
|
|
b39719984a | ||
|
|
a95278fe72 | ||
|
|
f2f366efa2 | ||
|
|
f4ad8b8f92 | ||
|
|
e04c90b678 | ||
|
|
abbfe7cf71 | ||
|
|
6c2a78d5bd | ||
|
|
63627acf30 | ||
|
|
86af0f883c | ||
|
|
dbb5fe2f0e | ||
|
|
94da954917 | ||
|
|
6ce18b2005 | ||
|
|
c09b6d8a1d | ||
|
|
19d9175833 | ||
|
|
e01d5afadb | ||
|
|
1ed3b48c2e | ||
|
|
fbd9189e7b | ||
|
|
1dd889cb16 | ||
|
|
2e8fbd661a | ||
|
|
6e424dba6e |
@@ -356,11 +356,6 @@ miniapps/performance/refined.mesh
|
||||
miniapps/performance/mesh.*
|
||||
miniapps/performance/sol.*
|
||||
|
||||
miniapps/plasma/g_eqdsk_viewer
|
||||
miniapps/plasma/gnuplot_eqdsk.*
|
||||
miniapps/plasma/G_EQDSK_Viewer*
|
||||
miniapps/plasma/ParaView
|
||||
|
||||
miniapps/shifted/distance
|
||||
miniapps/shifted/ParaViewDistance
|
||||
miniapps/shifted/ParaViewLSF
|
||||
|
||||
@@ -79,6 +79,11 @@ Linear and nonlinear solvers
|
||||
PRefinement multigrid methods for problems posed on trace spaces (see e.g. the
|
||||
DPG miniapps).
|
||||
|
||||
- Added new class MultiVector: an array of Vectors of different sizes where each
|
||||
Vector can be allocated independently. Also, added associated methods in class
|
||||
Operator: MultMV, MultTransposeMV, and GetGradientMV, that use MultiVector
|
||||
objects for input and/or output parameters. [PR #5249]
|
||||
|
||||
GPU computing
|
||||
-------------
|
||||
- Improved partial assembly for VectorDivergenceIntegrator with shared-memory
|
||||
@@ -92,6 +97,20 @@ GPU computing
|
||||
|
||||
- Added device assembly support for 3D H(curl) VectorFEDomainLFIntegrator.
|
||||
|
||||
- Added partial assembly support for MixedScalarWeakGradientIntegrator.
|
||||
|
||||
- Added partial assembly support for MixedDotProductIntegrator.
|
||||
|
||||
- Added partial assembly support for MixedScalarCrossProductIntegrator.
|
||||
|
||||
- Added partial assembly support for MixedScalarWeakCrossProductIntegrator.
|
||||
|
||||
- Added support for device partial assembly CurlInterpolator.
|
||||
This supports 2D and 3D variants:
|
||||
2D H1 (out-of-plane) to RT (in-plane)
|
||||
2D ND (in-plane) to Integral L2 (out-of-plane)
|
||||
3D ND to RT
|
||||
|
||||
- Added NVIDIA cuDSS library interface. Implementation examples have been
|
||||
added to ex1 and ex1p. See https://developer.nvidia.com/cudss for more
|
||||
details. Supported versions >= 0.6.0.
|
||||
@@ -104,6 +123,9 @@ GPU computing
|
||||
- Added support for FiniteElement::MapType::INTEGRAL spaces to
|
||||
QuadratureInterpolator.
|
||||
|
||||
- Added support for FiniteElement::MapType::INTEGRAL spaces to
|
||||
MixedScalarCurlIntegrator.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- The Lorentz miniapp (in miniapps/electromagnetics) has been updated to
|
||||
@@ -118,6 +140,12 @@ Miscellaneous
|
||||
using the new method ApplyDofSigns() in class ParFiniteElementSpace: the
|
||||
method will return immediately if no sign flips are needed.
|
||||
|
||||
API changes
|
||||
-----------
|
||||
- Removed ProjectGrad from 2D RT elements. Users should use ProjectCurl instead.
|
||||
This also fixes a bug where ProjectCurl was returning the negative curl,
|
||||
identical to ProjectGrad.
|
||||
|
||||
|
||||
Version 4.9, released on Dec 11, 2025
|
||||
=====================================
|
||||
|
||||
+3
-12
@@ -88,18 +88,9 @@ if (MFEM_USE_STRUMPACK OR MFEM_USE_MUMPS)
|
||||
# Just needed to find the MPI_Fortran libraries to link with
|
||||
set(XSDK_ENABLE_Fortran ON)
|
||||
endif()
|
||||
# Ginkgo requires C++17:
|
||||
if ((MFEM_USE_GINKGO) AND ("${CMAKE_CXX_STANDARD}" LESS "17"))
|
||||
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to use." FORCE)
|
||||
# Google Benchmark, SUNDIALS, STRUMPACK, Tribol, RAJA and Umpire require C++14:
|
||||
elseif ((MFEM_USE_BENCHMARK OR
|
||||
MFEM_USE_SUNDIALS OR
|
||||
MFEM_USE_STRUMPACK OR
|
||||
MFEM_USE_TRIBOL OR
|
||||
MFEM_USE_RAJA OR
|
||||
MFEM_USE_UMPIRE) AND
|
||||
("${CMAKE_CXX_STANDARD}" LESS "14"))
|
||||
set(CMAKE_CXX_STANDARD 14 CACHE STRING "C++ standard to use." FORCE)
|
||||
# RAJA requires C++20:
|
||||
if ((MFEM_USE_UMPIRE OR MFEM_USE_RAJA) AND ("${CMAKE_CXX_STANDARD}" LESS "20"))
|
||||
set(CMAKE_CXX_STANDARD 20 CACHE STRING "C++ standard to use." FORCE)
|
||||
endif()
|
||||
|
||||
# Include xSDK default CMake file.
|
||||
|
||||
+33
-8
@@ -28,11 +28,8 @@ MPICXX = mpicxx
|
||||
BASE_FLAGS = -std=c++17
|
||||
OPTIM_FLAGS = -O3 $(BASE_FLAGS)
|
||||
|
||||
# Shadow warnings for clang only; GCC's -Wshadow flags more.
|
||||
SHADOW_WARNING_FLAG = $(if $(findstring clang,\
|
||||
$(shell $(MFEM_HOST_CXX) --version 2>/dev/null)),-Wshadow,)
|
||||
WARNING_FLAGS = -pedantic -Wall $(SHADOW_WARNING_FLAG)
|
||||
|
||||
# The variable WARNING_FLAGS depends on which compiler is used, and is defined
|
||||
# later in this file.
|
||||
DEBUG_FLAGS = $(strip -g $(addprefix $(XCOMPILER),$(WARNING_FLAGS)) $(BASE_FLAGS))
|
||||
|
||||
# Prefixes for passing flags to the compiler and linker when using CXX or MPICXX
|
||||
@@ -52,6 +49,10 @@ SHARED = NO
|
||||
#
|
||||
# If you set MFEM_USE_ENZYME=YES, must use CUDA_CXX=clang++
|
||||
CUDA_CXX = nvcc
|
||||
# CUDA compute capability used during compilation, e.g. sm_60. Multiple
|
||||
# architectures can be requested as a comma-separated list, e.g. sm_70,sm_80.
|
||||
# A single value may also be one of the nvcc special values "all",
|
||||
# "all-major", or "native".
|
||||
CUDA_ARCH = sm_60
|
||||
# Base CUDA install directory, only needed if building with clang+cuda:
|
||||
# The default setting is:
|
||||
@@ -60,11 +61,23 @@ CUDA_ARCH = sm_60
|
||||
# 3. Use /usr/local/cuda
|
||||
CUDA_DIR = $(or $(CUDA_HOME),$(patsubst %/,%,$(dir \
|
||||
$(patsubst %/,%,$(dir $(shell command -v nvcc))))),/usr/local/cuda)
|
||||
# Derive nvcc/clang architecture flags from CUDA_ARCH. A comma-separated list
|
||||
# expands into one -gencode / --cuda-gpu-arch flag per architecture; otherwise
|
||||
# use the -arch / --cuda-gpu-arch shorthand.
|
||||
MFEM_COMMA := ,
|
||||
CUDA_ARCH_NUMS = $(patsubst sm_%,%,$(subst $(MFEM_COMMA), ,$(CUDA_ARCH)))
|
||||
NVCC_ARCH_FLAGS = $(strip $(if $(findstring $(MFEM_COMMA),$(CUDA_ARCH)),\
|
||||
$(foreach arch,$(CUDA_ARCH_NUMS),\
|
||||
-gencode arch=compute_$(arch)$(MFEM_COMMA)code=sm_$(arch)),\
|
||||
-arch=$(CUDA_ARCH)))
|
||||
CLANG_ARCH_FLAGS = $(strip $(if $(findstring $(MFEM_COMMA),$(CUDA_ARCH)),\
|
||||
$(foreach arch,$(CUDA_ARCH_NUMS),--cuda-gpu-arch=sm_$(arch)),\
|
||||
--cuda-gpu-arch=$(CUDA_ARCH)))
|
||||
# flags for clang+cuda
|
||||
CLANG_CUDA_FLAGS = -xcuda --cuda-path=$(CUDA_DIR) --cuda-gpu-arch=$(CUDA_ARCH)
|
||||
CLANG_CUDA_FLAGS = -xcuda --cuda-path=$(CUDA_DIR) $(CLANG_ARCH_FLAGS)
|
||||
# flags for nvcc
|
||||
NVCC_FLAGS = -x=cu --expt-extended-lambda --expt-relaxed-constexpr \
|
||||
-arch=$(CUDA_ARCH) -isystem "$(CUDA_DIR)/include"
|
||||
$(NVCC_ARCH_FLAGS) -isystem "$(CUDA_DIR)/include"
|
||||
# Prefixes for passing flags to the host compiler and linker when using
|
||||
# CUDA_CXX=nvcc
|
||||
CUDA_XCOMPILER = -Xcompiler=
|
||||
@@ -382,7 +395,7 @@ CUDSS_LIBRARY_DIR = $(CUDSS_DIR)/lib
|
||||
CUDSS_OPT = -I$(CUDSS_INCLUDE_DIR)
|
||||
CUDSS_LIB = \
|
||||
$(XLINKER)-rpath,$(CUDSS_LIBRARY_DIR) -L$(CUDSS_LIBRARY_DIR) -lcudss
|
||||
# The cuDSS communication and threading libraries.
|
||||
# The cuDSS communication and threading libraries.
|
||||
MFEM_CUDSS_COMM_LIB = $(abspath $(wildcard $(or $(CUDSS_COMM_LIB),\
|
||||
$(subst @MFEM_DIR@,$(MFEM_DIR), $(CUDSS_LIBRARY_DIR)/libcudss_commlayer_openmpi.so))))
|
||||
MFEM_CUDSS_THREADING_LIB = $(abspath $(wildcard $(or $(CUDSS_THREADING_LIB),\
|
||||
@@ -665,3 +678,15 @@ VERBOSE = NO
|
||||
|
||||
# Optional build tag
|
||||
MFEM_BUILD_TAG = $(shell uname -snm)
|
||||
|
||||
# Enable -pedantic flag only for gcc or clang. nvcc complains with -pedantic
|
||||
# because of line directives.
|
||||
PEDANTIC_FLAG = $(if \
|
||||
$(findstring NVIDIA,$(shell $(MFEM_CXX) --version 2>&1)),, \
|
||||
$(if $(or \
|
||||
$(findstring gcc version,$(shell $(MFEM_CXX) -v 2>&1)), \
|
||||
$(findstring clang version,$(shell $(MFEM_CXX) -v 2>&1))),-pedantic,))
|
||||
# Enable shadow warnings for clang only; GCC's -Wshadow flags more.
|
||||
SHADOW_WARNING_FLAG = $(if $(findstring clang,\
|
||||
$(shell $(MFEM_HOST_CXX) --version 2>/dev/null)),-Wshadow,)
|
||||
WARNING_FLAGS = $(PEDANTIC_FLAG) -Wall $(SHADOW_WARNING_FLAG)
|
||||
|
||||
@@ -1083,7 +1083,8 @@ EXCLUDE_PATTERNS =
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
|
||||
EXCLUDE_SYMBOLS = mfem::internal \
|
||||
mfem::kernels::internal
|
||||
mfem::kernels::internal \
|
||||
mfem::future::detail
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
|
||||
# that contain example code fragments that are included (see the \include
|
||||
|
||||
@@ -1255,6 +1255,31 @@ void BilinearForm::Mult(const Vector &x, Vector &y) const
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::AddMult(const Vector &x, Vector &y, const real_t a) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
ext->AddMult(x, y, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat->AddMult(x, y, a);
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::AddMultTranspose(const Vector &x, Vector &y,
|
||||
const real_t a) const
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
ext->AddMultTranspose(x, y, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
mat->AddMultTranspose(x, y, a);
|
||||
}
|
||||
}
|
||||
|
||||
void BilinearForm::MultTranspose(const Vector & x, Vector & y) const
|
||||
{
|
||||
if (ext)
|
||||
|
||||
@@ -307,8 +307,8 @@ public:
|
||||
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
|
||||
|
||||
/// Add the matrix vector multiple to a vector: $ y += a M x $
|
||||
void AddMult(const Vector &x, Vector &y, const real_t a = 1.0) const override
|
||||
{ mat -> AddMult (x, y, a); }
|
||||
void AddMult(const Vector &x, Vector &y,
|
||||
const real_t a = 1.0) const override;
|
||||
|
||||
/** @brief Add the original uneliminated matrix vector multiple to a vector.
|
||||
The original matrix is $ M + Me $ so we have:
|
||||
@@ -318,8 +318,7 @@ public:
|
||||
|
||||
/// Add the matrix transpose vector multiplication: $ y += a M^T x $
|
||||
void AddMultTranspose(const Vector & x, Vector & y,
|
||||
const real_t a = 1.0) const override
|
||||
{ mat->AddMultTranspose(x, y, a); }
|
||||
const real_t a = 1.0) const override;
|
||||
|
||||
/** @brief Add the original uneliminated matrix transpose vector
|
||||
multiple to a vector. The original matrix is $ M + M_e $
|
||||
|
||||
@@ -1997,7 +1997,11 @@ void PADiscreteLinearOperatorExtension::Assemble()
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem_error("A real ElementRestriction is required in this setting!");
|
||||
const L2ElementRestriction* l2_elem_restrict =
|
||||
dynamic_cast<const L2ElementRestriction*>(elem_restrict_test);
|
||||
MFEM_VERIFY(l2_elem_restrict,
|
||||
"A real ElementRestriction is required in this setting!");
|
||||
test_multiplicity = 1.0;
|
||||
}
|
||||
|
||||
auto tm = test_multiplicity.ReadWrite();
|
||||
@@ -2036,7 +2040,13 @@ void PADiscreteLinearOperatorExtension::AddMult(
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem_error("In this setting you need a real ElementRestriction!");
|
||||
const L2ElementRestriction* l2_elem_restrict =
|
||||
dynamic_cast<const L2ElementRestriction*>(elem_restrict_test);
|
||||
MFEM_VERIFY(l2_elem_restrict,
|
||||
"In this setting you need a real ElementRestriction!");
|
||||
tempY.SetSize(y.Size());
|
||||
l2_elem_restrict->MultTranspose(localTest, tempY);
|
||||
y += tempY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+437
-327
File diff suppressed because it is too large
Load Diff
+113
-138
@@ -588,6 +588,38 @@ SesquilinearForm::AssembleComplexSparseMatrix()
|
||||
false, false, conv);
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::BuildComplexOperator(OperatorHandle &A_r,
|
||||
OperatorHandle &A_i,
|
||||
OperatorHandle &A) const
|
||||
{
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
|
||||
{
|
||||
ComplexSparseMatrix * A_sp =
|
||||
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
|
||||
A_i.As<SparseMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexSparseMatrix>(A_sp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.Ptr(),
|
||||
A_i.Ptr(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
}
|
||||
|
||||
void
|
||||
SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &x, Vector &b,
|
||||
@@ -716,31 +748,7 @@ SesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
|
||||
{
|
||||
ComplexSparseMatrix * A_sp =
|
||||
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
|
||||
A_i.As<SparseMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexSparseMatrix>(A_sp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.Ptr(),
|
||||
A_i.Ptr(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
BuildComplexOperator(A_r, A_i, A);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -777,31 +785,7 @@ SesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
|
||||
}
|
||||
}
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::MFEM_SPARSEMAT) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::MFEM_SPARSEMAT))
|
||||
{
|
||||
ComplexSparseMatrix * A_sp =
|
||||
new ComplexSparseMatrix(A_r.As<SparseMatrix>(),
|
||||
A_i.As<SparseMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexSparseMatrix>(A_sp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.Ptr(),
|
||||
A_i.Ptr(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
BuildComplexOperator(A_r, A_i, A);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1893,6 +1877,81 @@ ParSesquilinearForm::ParallelAssemble()
|
||||
true, true, conv);
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::BuildComplexOperator(OperatorHandle &A_r,
|
||||
OperatorHandle &A_i,
|
||||
OperatorHandle &A) const
|
||||
{
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
|
||||
{
|
||||
ComplexHypreParMatrix * A_hyp =
|
||||
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
|
||||
A_i.As<HypreParMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.As<Operator>(),
|
||||
A_i.As<Operator>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ZeroDiagonalHypreKernel
|
||||
{
|
||||
const int *ess_tdof_list;
|
||||
const HYPRE_Int *diag_i;
|
||||
real_t *diag_data;
|
||||
|
||||
void MFEM_HOST_DEVICE operator()(int k) const
|
||||
{
|
||||
const int j = ess_tdof_list[k];
|
||||
diag_data[diag_i[j]] = 0.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::SetImaginaryEssentialDiagonalToZero(
|
||||
const Array<int> &ess_tdof_list, OperatorHandle &A)
|
||||
{
|
||||
if (A.Type() == Operator::Hypre_ParCSR)
|
||||
{
|
||||
const int n = ess_tdof_list.Size();
|
||||
HypreParMatrix *Ah;
|
||||
A.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(GetHypreForallMemoryClass(), n);
|
||||
HYPRE_Int *d_diag_i = Aih->diag->i;
|
||||
real_t *d_diag_data = Aih->diag->data;
|
||||
mfem::hypre_forall(n, ZeroDiagonalHypreKernel
|
||||
{
|
||||
d_ess_tdof_list, d_diag_i, d_diag_data
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
A.As<ConstrainedOperator>()->SetDiagonalPolicy
|
||||
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &x, Vector &b,
|
||||
@@ -1993,27 +2052,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
});
|
||||
// Modify off-diagonal blocks (imaginary parts of the matrix) to conform
|
||||
// with standard essential BC treatment
|
||||
if (A_i.Type() == Operator::Hypre_ParCSR)
|
||||
{
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix *Aih = *Ah;
|
||||
Ah->HypreReadWrite();
|
||||
const int *d_ess_tdof_list =
|
||||
ess_tdof_list.GetMemory().Read(GetHypreForallMemoryClass(), n);
|
||||
HYPRE_Int *d_diag_i = Aih->diag->i;
|
||||
real_t *d_diag_data = Aih->diag->data;
|
||||
mfem::hypre_forall(n, [=] MFEM_HOST_DEVICE (int k)
|
||||
{
|
||||
const int j = d_ess_tdof_list[k];
|
||||
d_diag_data[d_diag_i[j]] = 0.0;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
|
||||
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
|
||||
}
|
||||
SetImaginaryEssentialDiagonalToZero(ess_tdof_list, A_i);
|
||||
}
|
||||
|
||||
if (conv == ComplexOperator::BLOCK_SYMMETRIC)
|
||||
@@ -2032,31 +2071,7 @@ ParSesquilinearForm::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
B_r.SyncAliasMemory(B);
|
||||
B_i.SyncAliasMemory(B);
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
|
||||
{
|
||||
ComplexHypreParMatrix * A_hyp =
|
||||
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
|
||||
A_i.As<HypreParMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.As<Operator>(),
|
||||
A_i.As<Operator>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
BuildComplexOperator(A_r, A_i, A);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2081,50 +2096,10 @@ ParSesquilinearForm::FormSystemMatrix(const Array<int> &ess_tdof_list,
|
||||
{
|
||||
// Modify off-diagonal blocks (imaginary parts of the matrix) to conform
|
||||
// with standard essential BC treatment
|
||||
if ( A_i.Type() == Operator::Hypre_ParCSR )
|
||||
{
|
||||
int n = ess_tdof_list.Size();
|
||||
HypreParMatrix * Ah;
|
||||
A_i.Get(Ah);
|
||||
hypre_ParCSRMatrix * Aih = *Ah;
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
int j = ess_tdof_list[k];
|
||||
Aih->diag->data[Aih->diag->i[j]] = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
A_i.As<ConstrainedOperator>()->SetDiagonalPolicy
|
||||
(mfem::Operator::DiagonalPolicy::DIAG_ZERO);
|
||||
}
|
||||
SetImaginaryEssentialDiagonalToZero(ess_tdof_list, A_i);
|
||||
}
|
||||
|
||||
// A = A_r + i A_i
|
||||
A.Clear();
|
||||
if ((!A_r.Ptr() || A_r.Type() == Operator::Hypre_ParCSR) &&
|
||||
(!A_i.Ptr() || A_i.Type() == Operator::Hypre_ParCSR))
|
||||
{
|
||||
ComplexHypreParMatrix * A_hyp =
|
||||
new ComplexHypreParMatrix(A_r.As<HypreParMatrix>(),
|
||||
A_i.As<HypreParMatrix>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexHypreParMatrix>(A_hyp, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ComplexOperator * A_op =
|
||||
new ComplexOperator(A_r.As<Operator>(),
|
||||
A_i.As<Operator>(),
|
||||
A_r.OwnsOperator(),
|
||||
A_i.OwnsOperator(),
|
||||
conv);
|
||||
A.Reset<ComplexOperator>(A_op, true);
|
||||
}
|
||||
A_r.SetOperatorOwner(false);
|
||||
A_i.SetOperatorOwner(false);
|
||||
BuildComplexOperator(A_r, A_i, A);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -392,6 +392,9 @@ private:
|
||||
bool RealInteg();
|
||||
bool ImagInteg();
|
||||
|
||||
void BuildComplexOperator(OperatorHandle &A_r, OperatorHandle &A_i,
|
||||
OperatorHandle &A) const;
|
||||
|
||||
public:
|
||||
SesquilinearForm(FiniteElementSpace *fes,
|
||||
ComplexOperator::Convention
|
||||
@@ -986,6 +989,12 @@ private:
|
||||
bool RealInteg();
|
||||
bool ImagInteg();
|
||||
|
||||
void SetImaginaryEssentialDiagonalToZero(
|
||||
const Array<int> &ess_tdof_list, OperatorHandle &A);
|
||||
|
||||
void BuildComplexOperator(OperatorHandle &A_r, OperatorHandle &A_i,
|
||||
OperatorHandle &A) const;
|
||||
|
||||
public:
|
||||
ParSesquilinearForm(ParFiniteElementSpace *pf,
|
||||
ComplexOperator::Convention
|
||||
|
||||
@@ -51,4 +51,52 @@ DifferentiableOperator::DifferentiableOperator(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FDJacobian::Mult(const Vector &v, Vector &y) const
|
||||
{
|
||||
// See [1] for choice of eps.
|
||||
//
|
||||
// [1] Woodward, C.S., Gardner, D.J. and Evans, K.J., 2015. On the use of
|
||||
// finite difference matrix-vector products in Newton-Krylov solvers for
|
||||
// implicit climate dynamics with spectral elements. Procedia Computer
|
||||
// Science, 51, pp.2036-2045.
|
||||
real_t eps;
|
||||
if (fixed_eps > 0.0)
|
||||
{
|
||||
eps = fixed_eps;
|
||||
}
|
||||
else
|
||||
{
|
||||
const real_t vnorm_local = v.Norml2();
|
||||
real_t vnorm;
|
||||
MPI_Allreduce(&vnorm_local, &vnorm, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
eps = lambda * (lambda + xnorm / vnorm);
|
||||
}
|
||||
|
||||
// x + eps * v
|
||||
{
|
||||
const auto d_v = v.Read();
|
||||
const auto d_x = x.Read();
|
||||
auto d_xpev = xpev.Write();
|
||||
mfem::forall(x.Size(), [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
d_xpev[i] = d_x[i] + eps * d_v[i];
|
||||
});
|
||||
}
|
||||
|
||||
// y = f(x + eps * v)
|
||||
op.Mult(xpev, y);
|
||||
|
||||
// y = (f(x + eps * v) - f(x)) / eps
|
||||
{
|
||||
const auto d_f = f.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
mfem::forall(f.Size(), [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
d_y[i] = (d_y[i] - d_f[i]) / eps;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
+23
-22
@@ -697,17 +697,18 @@ void DifferentiableOperator::AddIntegrator(
|
||||
|
||||
// The explicit captures are necessary to avoid dependency on
|
||||
// the specific instance of this class (this pointer).
|
||||
restriction_callback =
|
||||
[=, solutions = this->solutions, parameters = this->parameters]
|
||||
(std::vector<Vector> &sol,
|
||||
const std::vector<Vector> &par,
|
||||
std::vector<Vector> &f)
|
||||
restriction_callback = [element_dof_ordering,
|
||||
solutions_ = this->solutions,
|
||||
parameters_ = this->parameters]
|
||||
(std::vector<Vector> &sol,
|
||||
const std::vector<Vector> &par,
|
||||
std::vector<Vector> &f)
|
||||
{
|
||||
restriction<entity_t>(solutions, sol, f,
|
||||
restriction<entity_t>(solutions_, sol, f,
|
||||
element_dof_ordering);
|
||||
restriction<entity_t>(parameters, par, f,
|
||||
restriction<entity_t>(parameters_, par, f,
|
||||
element_dof_ordering,
|
||||
solutions.size());
|
||||
solutions_.size());
|
||||
};
|
||||
|
||||
prolongation_transpose = get_prolongation_transpose(
|
||||
@@ -835,19 +836,19 @@ void DifferentiableOperator::AddIntegrator(
|
||||
|
||||
// capture by ref:
|
||||
&restriction_cb = this->restriction_callback,
|
||||
&fields_e = this->fields_e,
|
||||
&residual_e = this->residual_e,
|
||||
&output_restriction_transpose = this->output_restriction_transpose
|
||||
&fields_e_ = this->fields_e,
|
||||
&residual_e_ = this->residual_e,
|
||||
&output_restriction_transpose_ = this->output_restriction_transpose
|
||||
]
|
||||
(std::vector<Vector> &sol, const std::vector<Vector> &par, Vector &res)
|
||||
mutable // mutable: needed to modify 'shmem_cache'
|
||||
{
|
||||
restriction_cb(sol, par, fields_e);
|
||||
restriction_cb(sol, par, fields_e_);
|
||||
|
||||
residual_e = 0.0;
|
||||
auto ye = Reshape(residual_e.ReadWrite(), test_vdim, num_test_dof, num_entities);
|
||||
residual_e_ = 0.0;
|
||||
auto ye = Reshape(residual_e_.ReadWrite(), test_vdim, num_test_dof, num_entities);
|
||||
|
||||
auto wrapped_fields_e = wrap_fields(fields_e,
|
||||
auto wrapped_fields_e = wrap_fields(fields_e_,
|
||||
action_shmem_info.field_sizes,
|
||||
num_entities);
|
||||
|
||||
@@ -878,7 +879,7 @@ void DifferentiableOperator::AddIntegrator(
|
||||
y, fhat, output_fop, output_dtq_shmem[0],
|
||||
scratch_shmem, dimension, use_sum_factorization);
|
||||
}, num_entities, thread_blocks, action_shmem_info.total_size, shmem_cache.ReadWrite());
|
||||
output_restriction_transpose(residual_e, res);
|
||||
output_restriction_transpose_(residual_e_, res);
|
||||
});
|
||||
|
||||
// Without this compile-time check, some valid instantiations of this method
|
||||
@@ -1193,7 +1194,7 @@ void DifferentiableOperator::AddIntegrator(
|
||||
|
||||
// capture by ref:
|
||||
&qpdc_mem = derivative_qp_caches_ref,
|
||||
&fields = fields_ref
|
||||
&fields_ = fields_ref
|
||||
](std::vector<Vector> &f_e, SparseMatrix *&A) mutable
|
||||
{
|
||||
auto wrapped_fields_e = wrap_fields(f_e, shmem_info.field_sizes,
|
||||
@@ -1241,14 +1242,14 @@ void DifferentiableOperator::AddIntegrator(
|
||||
{
|
||||
if (input_is_dependent[s])
|
||||
{
|
||||
trial_field = &fields[input_to_field[s]];
|
||||
trial_field = &fields_[input_to_field[s]];
|
||||
}
|
||||
}
|
||||
|
||||
auto trial_fes = *std::get_if<const ParFiniteElementSpace *>
|
||||
(&trial_field->data);
|
||||
auto test_fes = *std::get_if<const ParFiniteElementSpace *>
|
||||
(&fields[output_to_field[0]].data);
|
||||
(&fields_[output_to_field[0]].data);
|
||||
|
||||
A = new SparseMatrix(test_fes->GetVSize(), trial_fes->GetVSize());
|
||||
|
||||
@@ -1334,7 +1335,7 @@ void DifferentiableOperator::AddIntegrator(
|
||||
input_to_field,
|
||||
output_to_field,
|
||||
&spmatcb = assemble_derivative_sparsematrix_callbacks_ref,
|
||||
&fields = fields_ref
|
||||
&fields_ = fields_ref
|
||||
](std::vector<Vector> &f_e, HypreParMatrix *&A) mutable
|
||||
{
|
||||
SparseMatrix *spmat = nullptr;
|
||||
@@ -1366,14 +1367,14 @@ void DifferentiableOperator::AddIntegrator(
|
||||
{
|
||||
if (input_is_dependent[s])
|
||||
{
|
||||
trial_field = &fields[input_to_field[s]];
|
||||
trial_field = &fields_[input_to_field[s]];
|
||||
}
|
||||
}
|
||||
|
||||
auto trial_fes = *std::get_if<const ParFiniteElementSpace *>
|
||||
(&trial_field->data);
|
||||
auto test_fes = *std::get_if<const ParFiniteElementSpace *>
|
||||
(&fields[output_to_field[0]].data);
|
||||
(&fields_[output_to_field[0]].data);
|
||||
|
||||
if (same_test_and_trial)
|
||||
{
|
||||
|
||||
+742
-768
File diff suppressed because it is too large
Load Diff
+9
-52
@@ -597,7 +597,7 @@ struct ThreadBlocks
|
||||
int z = 1;
|
||||
};
|
||||
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP)
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
template <typename func_t>
|
||||
__global__ void forall_kernel_shmem(func_t f, int n)
|
||||
{
|
||||
@@ -617,10 +617,11 @@ void forall(func_t f,
|
||||
int num_shmem = 0,
|
||||
real_t *shmem = nullptr)
|
||||
{
|
||||
if (Device::Allows(Backend::CUDA_MASK) ||
|
||||
Device::Allows(Backend::HIP_MASK))
|
||||
internal::RequireKernelCompilation();
|
||||
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
if (Device::Allows(Backend::CUDA_MASK | Backend::HIP_MASK))
|
||||
{
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP)
|
||||
// int gridsize = (N + Z - 1) / Z;
|
||||
int num_bytes = num_shmem * sizeof(decltype(shmem));
|
||||
dim3 block_size(blocks.x, blocks.y, blocks.z);
|
||||
@@ -631,9 +632,10 @@ void forall(func_t f,
|
||||
MFEM_GPU_CHECK(hipGetLastError());
|
||||
#endif
|
||||
MFEM_DEVICE_SYNC;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else if (Device::Allows(Backend::CPU_MASK))
|
||||
#endif
|
||||
if (Device::Allows(Backend::CPU_MASK))
|
||||
{
|
||||
MFEM_ASSERT(!((bool)num_shmem != (bool)shmem),
|
||||
"Backend::CPU needs a pre-allocated shared memory block");
|
||||
@@ -671,52 +673,7 @@ public:
|
||||
MPI_COMM_WORLD);
|
||||
}
|
||||
|
||||
void Mult(const Vector &v, Vector &y) const override
|
||||
{
|
||||
// See [1] for choice of eps.
|
||||
//
|
||||
// [1] Woodward, C.S., Gardner, D.J. and Evans, K.J., 2015. On the use of
|
||||
// finite difference matrix-vector products in Newton-Krylov solvers for
|
||||
// implicit climate dynamics with spectral elements. Procedia Computer
|
||||
// Science, 51, pp.2036-2045.
|
||||
real_t eps;
|
||||
if (fixed_eps > 0.0)
|
||||
{
|
||||
eps = fixed_eps;
|
||||
}
|
||||
else
|
||||
{
|
||||
const real_t vnorm_local = v.Norml2();
|
||||
real_t vnorm;
|
||||
MPI_Allreduce(&vnorm_local, &vnorm, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
eps = lambda * (lambda + xnorm / vnorm);
|
||||
}
|
||||
|
||||
// x + eps * v
|
||||
{
|
||||
const auto d_v = v.Read();
|
||||
const auto d_x = x.Read();
|
||||
auto d_xpev = xpev.Write();
|
||||
mfem::forall(x.Size(), [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
d_xpev[i] = d_x[i] + eps * d_v[i];
|
||||
});
|
||||
}
|
||||
|
||||
// y = f(x + eps * v)
|
||||
op.Mult(xpev, y);
|
||||
|
||||
// y = (f(x + eps * v) - f(x)) / eps
|
||||
{
|
||||
const auto d_f = f.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
mfem::forall(f.Size(), [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
d_y[i] = (d_y[i] - d_f[i]) / eps;
|
||||
});
|
||||
}
|
||||
}
|
||||
void Mult(const Vector &v, Vector &y) const override;
|
||||
|
||||
virtual MemoryClass GetMemoryClass() const override
|
||||
{
|
||||
|
||||
+6
-5
@@ -1316,13 +1316,14 @@ void VectorFiniteElement::Project_RT(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectGrad_RT(
|
||||
void VectorFiniteElement::ProjectCurl2D_RT(
|
||||
const real_t *nk, const Array<int> &d2n, const FiniteElement &fe,
|
||||
ElementTransformation &Trans, DenseMatrix &grad) const
|
||||
{
|
||||
// 2D "ProjectCurl_RT"
|
||||
if (dim != 2)
|
||||
{
|
||||
mfem_error("VectorFiniteElement::ProjectGrad_RT works only in 2D!");
|
||||
mfem_error("VectorFiniteElement::ProjectCurl2D_RT works only in 2D!");
|
||||
}
|
||||
|
||||
DenseMatrix dshape(fe.GetDof(), fe.GetDim());
|
||||
@@ -1333,8 +1334,8 @@ void VectorFiniteElement::ProjectGrad_RT(
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
fe.CalcDShape(Nodes.IntPoint(k), dshape);
|
||||
tk[0] = nk[d2n[k]*dim+1];
|
||||
tk[1] = -nk[d2n[k]*dim];
|
||||
tk[0] = -nk[d2n[k]*dim+1];
|
||||
tk[1] = nk[d2n[k]*dim];
|
||||
dshape.Mult(tk, grad_k);
|
||||
for (int j = 0; j < grad_k.Size(); j++)
|
||||
{
|
||||
@@ -1381,7 +1382,7 @@ void VectorFiniteElement::ProjectCurl_ND(
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::ProjectCurl_RT(
|
||||
void VectorFiniteElement::ProjectCurl3D_RT(
|
||||
const real_t *nk, const Array<int> &d2n, const FiniteElement &fe,
|
||||
ElementTransformation &Trans, DenseMatrix &curl) const
|
||||
{
|
||||
|
||||
+10
-7
@@ -957,10 +957,11 @@ protected:
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
// rotated gradient in 2D
|
||||
void ProjectGrad_RT(const real_t *nk, const Array<int> &d2n,
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
// Input is a scalar representing the Z (out of plane) component, Output is
|
||||
// the X-Y (in-plane) RT curl
|
||||
void ProjectCurl2D_RT(const real_t *nk, const Array<int> &d2n,
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
|
||||
// Compute the curl as a discrete operator from ND FE (fe) to ND FE (this).
|
||||
// The natural FE for the range is RT, so this is an approximation.
|
||||
@@ -968,9 +969,9 @@ protected:
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
|
||||
void ProjectCurl_RT(const real_t *nk, const Array<int> &d2n,
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
void ProjectCurl3D_RT(const real_t *nk, const Array<int> &d2n,
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
|
||||
/** @brief Project a vector coefficient onto the ND basis functions
|
||||
@param tk Edge tangent vectors for this element type
|
||||
@@ -1446,6 +1447,8 @@ public:
|
||||
dof2quad_array_open);
|
||||
}
|
||||
|
||||
const Poly_1D::Basis &GetOpenBasis1D() const { return obasis1d; }
|
||||
|
||||
virtual ~VectorTensorFiniteElement();
|
||||
};
|
||||
|
||||
|
||||
+6
-16
@@ -73,16 +73,11 @@ public:
|
||||
void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
{ Project_RT(nk, dof2nk, fe, Trans, I); }
|
||||
// Gradient + rotation = Curl: H1 -> H(div)
|
||||
void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const override
|
||||
{ ProjectGrad_RT(nk, dof2nk, fe, Trans, grad); }
|
||||
// Curl = Gradient + rotation: H1 -> H(div)
|
||||
void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const override
|
||||
{ ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl2D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
|
||||
void GetFaceMap(const int face_id, Array<int> &face_map) const override;
|
||||
|
||||
@@ -148,7 +143,7 @@ public:
|
||||
void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const override
|
||||
{ ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl3D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
|
||||
/// @brief Return the mapping from lexicographically ordered face DOFs to
|
||||
/// lexicographically ordered element DOFs corresponding to local face
|
||||
@@ -210,16 +205,11 @@ public:
|
||||
void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const override
|
||||
{ Project_RT(nk, dof2nk, fe, Trans, I); }
|
||||
// Gradient + rotation = Curl: H1 -> H(div)
|
||||
void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const override
|
||||
{ ProjectGrad_RT(nk, dof2nk, fe, Trans, grad); }
|
||||
// Curl = Gradient + rotation: H1 -> H(div)
|
||||
void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const override
|
||||
{ ProjectGrad_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl2D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
};
|
||||
|
||||
|
||||
@@ -274,7 +264,7 @@ public:
|
||||
void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const override
|
||||
{ ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl3D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
};
|
||||
|
||||
class RT_WedgeElement : public VectorFiniteElement
|
||||
@@ -332,7 +322,7 @@ public:
|
||||
void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const override
|
||||
{ ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl3D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
};
|
||||
|
||||
/** Arbitrary order H(Div) basis functions defined on pyramid-shaped elements
|
||||
@@ -428,7 +418,7 @@ public:
|
||||
virtual void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const
|
||||
{ ProjectCurl_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
{ ProjectCurl3D_RT(nk, dof2nk, fe, Trans, curl); }
|
||||
|
||||
void CalcRawVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
+4
-4
@@ -556,7 +556,7 @@ void obboxsurf_calc_3(Vector &bb,
|
||||
gslib::lagrange_fun *const lag = gslib::gll_lag_setup(work, n);
|
||||
lag(I0, work, n, 1, 0);
|
||||
|
||||
for (int ie = 0; ie < nel; ie++,x+=n2,y+=n2,z+=n2)
|
||||
for (int ie = 0; (unsigned)ie < nel; ie++,x+=n2,y+=n2,z+=n2)
|
||||
{
|
||||
struct gslib::dbl_range ab[3];
|
||||
struct gslib::dbl_range tb[3];
|
||||
@@ -780,7 +780,7 @@ void obboxedge_calc_2(Vector &bb,
|
||||
gslib::lagrange_fun *const lag = gslib::gll_lag_setup(work, nr);
|
||||
lag(I0r, work, nr,1, 0);
|
||||
|
||||
for (int ie = 0; ie < nel; ie++,x+=nr,y+=nr)
|
||||
for (int ie = 0; (unsigned)ie < nel; ie++,x+=nr,y+=nr)
|
||||
{
|
||||
double x0[2], A[4];
|
||||
struct gslib::dbl_range ab[2], tb[2];
|
||||
@@ -892,7 +892,7 @@ void obboxedge_calc_3(Vector &bb,
|
||||
gslib::lagrange_fun *const lag = gslib::gll_lag_setup(work, nr);
|
||||
lag(I0r, work, nr, 1, 0);
|
||||
|
||||
for (int ie = 0; ie < nel; ie++,x+=nr,y+=nr,z+=nr)
|
||||
for (int ie = 0; (unsigned)ie < nel; ie++,x+=nr,y+=nr,z+=nr)
|
||||
{
|
||||
double x0[3], A[9], Ai[9];
|
||||
struct gslib::dbl_range ab[3], tb[3];
|
||||
@@ -4518,7 +4518,7 @@ Mesh* FindPointsGSLIB::GetBoundingBoxMesh(int type)
|
||||
int eidx = 0;
|
||||
if (myid == save_rank)
|
||||
{
|
||||
for (int p = 0; p < gsl_comm->np; p++)
|
||||
for (int p = 0; (unsigned)p < gsl_comm->np; p++)
|
||||
{
|
||||
if (static_cast<unsigned int>(p) != save_rank)
|
||||
{
|
||||
|
||||
@@ -368,6 +368,8 @@ void HybridizationExtension::ConstructH()
|
||||
|
||||
CAhatInvCt = 0.0;
|
||||
|
||||
// Fill the face-to-face adjacency array. Two faces are adjacent if they are
|
||||
// incident to a common element.
|
||||
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int fi)
|
||||
{
|
||||
const int begin_f = d_face_face_offsets[fi];
|
||||
@@ -403,6 +405,12 @@ void HybridizationExtension::ConstructH()
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fill unused entries with -1 to indicate invalid
|
||||
const int end_f = d_face_face_offsets[fi + 1];
|
||||
for (int i = begin_f + idx; i < end_f; ++i)
|
||||
{
|
||||
d_face_to_face[i] = -1;
|
||||
}
|
||||
});
|
||||
|
||||
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int fi)
|
||||
@@ -412,6 +420,7 @@ void HybridizationExtension::ConstructH()
|
||||
for (int idx_j = begin; idx_j < end; ++idx_j)
|
||||
{
|
||||
const int fj = d_face_to_face[idx_j];
|
||||
if (fj < 0) { break; }
|
||||
for (int ei = 0; ei < 2; ++ei)
|
||||
{
|
||||
const int e = d_face_to_el(0, ei, fi);
|
||||
|
||||
@@ -178,6 +178,8 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
MFEM_VERIFY(el.GetMapType() == FiniteElement::VALUE,
|
||||
"Only value map type currently supported");
|
||||
ElementTransformation &Trans = *mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Trans);
|
||||
if (DeviceCanUseCeed())
|
||||
|
||||
@@ -785,6 +785,23 @@ void PAHcurlL2Setup2D(const int Q1D,
|
||||
});
|
||||
}
|
||||
|
||||
void PAHcurlL2IntSetup2D(const int Q1D, const int NE, const Array<real_t> &w,
|
||||
Vector &coeff, const Vector &detJ, Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D;
|
||||
auto W = w.Read();
|
||||
auto C = Reshape(coeff.Read(), NQ, NE);
|
||||
auto J = Reshape(detJ.Read(), NQ, NE);
|
||||
auto y = Reshape(op.Write(), NQ, NE);
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
y(q,e) = W[q] * C(q,e) / J(q,e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PAHcurlL2Setup3D(const int NQ,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
|
||||
@@ -1889,13 +1889,17 @@ inline void SmemPACurlCurlApply3D(const int d1d,
|
||||
ForallWrap<3>(true, NE, device_kernel, host_kernel, Q1D, Q1D, Q1D);
|
||||
}
|
||||
|
||||
// PA H(curl)-L2 Assemble 2D kernel
|
||||
// PA H(curl)-L2 value Assemble 2D kernel
|
||||
void PAHcurlL2Setup2D(const int Q1D,
|
||||
const int NE,
|
||||
const Array<real_t> &w,
|
||||
Vector &coeff,
|
||||
Vector &op);
|
||||
|
||||
// PA H(curl)-L2 integral Assemble 2D kernel
|
||||
void PAHcurlL2IntSetup2D(const int Q1D, const int NE, const Array<real_t> &w,
|
||||
Vector &coeff, const Vector &detJ, Vector &op);
|
||||
|
||||
// PA H(curl)-L2 Assemble 3D kernel
|
||||
void PAHcurlL2Setup3D(const int NQ,
|
||||
const int coeffDim,
|
||||
|
||||
@@ -864,8 +864,656 @@ inline void PAHcurlHdivApplyTranspose3D(const int d1d,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
namespace curlinterp
|
||||
{
|
||||
constexpr int NBZ3D(int ndof_o, int nquad_o, int mdq)
|
||||
{
|
||||
if (ndof_o <= 0 || nquad_o <= 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int ndof_c = ndof_o + 1;
|
||||
int nquad_c = nquad_o + 1;
|
||||
// z dimension is capped at 64 on nvidia and amd gpus
|
||||
int tmp =
|
||||
std::min((128 + mdq * mdq * (mdq - 1) - 1) / (mdq * mdq * (mdq - 1)), 64);
|
||||
int smem_req =
|
||||
sizeof(mfem::real_t) *
|
||||
((3 * ndof_c * ndof_c * ndof_o + 2 * 2 * mdq * mdq * mdq) * tmp +
|
||||
ndof_c * nquad_o + ndof_c * nquad_c + ndof_o * nquad_o);
|
||||
// assume GPU has at least 48k shared memory
|
||||
return std::max(std::min(tmp, (48 * 1024 + smem_req - 1) / smem_req), 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <int T_NDOF_O, int T_NQUAD_O>
|
||||
void CurlInterpolatorApply3DSmem(const int ne, const int ndof_o,
|
||||
const int nquad_o, const Vector &pa,
|
||||
const Vector &x_, Vector &y_)
|
||||
{
|
||||
constexpr int mnd_o = T_NDOF_O ? T_NDOF_O : DofQuadLimits::HCURL_MAX_D1D - 1;
|
||||
constexpr int mnq_o =
|
||||
T_NQUAD_O ? T_NQUAD_O : DofQuadLimits::HDIV_MAX_D1D - 1;
|
||||
constexpr int mndq = std::max(mnd_o + 1, mnq_o + 1);
|
||||
constexpr int tbatch = curlinterp::NBZ3D(T_NDOF_O, T_NQUAD_O, mndq);
|
||||
MFEM_VERIFY(ndof_o <= mnd_o, "Error: H(curl) order larger than supported");
|
||||
MFEM_VERIFY(nquad_o <= mnq_o, "Error: H(div) order larger than supported");
|
||||
int mnq = std::max(ndof_o + 1, nquad_o + 1);
|
||||
auto pa_data = pa.Read();
|
||||
auto x_d = x_.Read();
|
||||
auto y_d = y_.ReadWrite();
|
||||
mfem::forall_2D_batch<mndq * mndq * (mndq - 1) * tbatch>(
|
||||
ne, mnq * mnq * (mnq - 1), 1, tbatch, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
constexpr int MND_O =
|
||||
T_NDOF_O ? T_NDOF_O : DofQuadLimits::HCURL_MAX_D1D - 1;
|
||||
constexpr int MNQ_O =
|
||||
T_NQUAD_O ? T_NQUAD_O : DofQuadLimits::HDIV_MAX_D1D - 1;
|
||||
constexpr int MNDQ = std::max(MND_O + 1, MNQ_O + 1);
|
||||
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
|
||||
constexpr int nbz = curlinterp::NBZ3D(T_NDOF_O, T_NQUAD_O, MNDQ);
|
||||
int tidz = MFEM_THREAD_ID(z);
|
||||
// Make mnq a local variable since capturing would result in different
|
||||
// captures between host/device versions, and spuriously fails
|
||||
int mnq = std::max(ndof_o + 1, nquad_o + 1);
|
||||
#else
|
||||
constexpr int nbz = 1;
|
||||
constexpr int tidz = 0;
|
||||
#endif
|
||||
const int NDOF_O = T_NDOF_O ? T_NDOF_O : ndof_o;
|
||||
const int NQUAD_O = T_NQUAD_O ? T_NQUAD_O : nquad_o;
|
||||
const int NDOF_C = NDOF_O + 1;
|
||||
const int NQUAD_C = NQUAD_O + 1;
|
||||
MFEM_SHARED real_t
|
||||
sBG[(MND_O + 1) * MNQ_O + (MND_O + 1) * (MNQ_O + 1) + MND_O * MNQ_O];
|
||||
auto X_ = Reshape(x_d, 3 * NDOF_C * NDOF_C * NDOF_O, ne);
|
||||
auto Y = Reshape(y_d, 3 * NQUAD_C * NQUAD_O * NQUAD_O, ne);
|
||||
auto Gco = Reshape(sBG, NQUAD_O, NDOF_C);
|
||||
auto Bcc = Reshape(sBG + NDOF_C * NQUAD_O, NQUAD_C, NDOF_C);
|
||||
auto Boo =
|
||||
Reshape(sBG + NDOF_C * NQUAD_O + NDOF_C * NQUAD_C, NQUAD_O, NDOF_O);
|
||||
MFEM_SHARED real_t X[3][nbz][MND_O * (MND_O + 1) * (MND_O + 1)];
|
||||
MFEM_SHARED real_t sm0[nbz * 2 * MNDQ * MNDQ * MNDQ];
|
||||
MFEM_SHARED real_t sm1[nbz * 2 * MNDQ * MNDQ * MNDQ];
|
||||
|
||||
// shapes of buffers always use MNDQ to mitigate shared memory bank
|
||||
// conflicts
|
||||
real_t(*DDQ)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm0);
|
||||
real_t(*DQQ)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm1);
|
||||
real_t(*QQQ)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm0);
|
||||
const int offset = NDOF_O * NDOF_C * NDOF_C;
|
||||
const int offsetq = NQUAD_C * NQUAD_O * NQUAD_O;
|
||||
MFEM_FOREACH_THREAD_DIRECT(ix, x, offset)
|
||||
{
|
||||
for (int dim = 0; dim < 3; ++dim)
|
||||
{
|
||||
X[dim][tidz][ix] = X_(ix + dim * offset, e);
|
||||
}
|
||||
}
|
||||
// load basis functions data
|
||||
if (tidz == 0)
|
||||
{
|
||||
auto npts = NDOF_C * NQUAD_O + NDOF_C * NQUAD_C + NDOF_O * NQUAD_O;
|
||||
MFEM_FOREACH_THREAD(ix, x, npts) { sBG[ix] = pa_data[ix]; }
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// x: Vz Bcc Gco Boo - Vy Bcc Boo Gco
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_C, NDOF_C,
|
||||
NDOF_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_C; ++dx)
|
||||
{
|
||||
u += X[2][tidz][dx + (dy + dz * NDOF_C) * NDOF_C] * Bcc(qx, dx);
|
||||
}
|
||||
DDQ[0][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_C, NDOF_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_C; ++dx)
|
||||
{
|
||||
u += X[1][tidz][dx + (dy + dz * NDOF_O) * NDOF_C] * Bcc(qx, dx);
|
||||
}
|
||||
DDQ[1][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_C, NQUAD_O,
|
||||
NDOF_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_C; ++dy)
|
||||
{
|
||||
u += DDQ[0][tidz][dz][dy][qx] * Gco(qy, dy);
|
||||
}
|
||||
DQQ[0][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_C, NQUAD_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_O; ++dy)
|
||||
{
|
||||
u += DDQ[1][tidz][dz][dy][qx] * Boo(qy, dy);
|
||||
}
|
||||
DQQ[1][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_C, NQUAD_O,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_O; ++dz)
|
||||
{
|
||||
u += DQQ[0][tidz][dz][qy][qx] * Boo(qz, dz);
|
||||
}
|
||||
QQQ[0][tidz][qz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_C, NQUAD_O,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_C; ++dz)
|
||||
{
|
||||
u += DQQ[1][tidz][dz][qy][qx] * Gco(qz, dz);
|
||||
}
|
||||
Y(qx + (qy + qz * NQUAD_O) * NQUAD_C, e) =
|
||||
QQQ[0][tidz][qz][qy][qx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// y: Vx Boo Bcc Gco - Vz Gco Bcc Boo
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_O, NDOF_C,
|
||||
NDOF_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_O; ++dx)
|
||||
{
|
||||
u += X[0][tidz][dx + (dy + dz * NDOF_C) * NDOF_O] * Boo(qx, dx);
|
||||
}
|
||||
DDQ[0][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_O, NDOF_C,
|
||||
NDOF_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_C; ++dx)
|
||||
{
|
||||
u += X[2][tidz][dx + (dy + dz * NDOF_C) * NDOF_C] * Gco(qx, dx);
|
||||
}
|
||||
DDQ[1][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_O, NQUAD_C,
|
||||
NDOF_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_C; ++dy)
|
||||
{
|
||||
u += DDQ[0][tidz][dz][dy][qx] * Bcc(qy, dy);
|
||||
}
|
||||
DQQ[0][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_O, NQUAD_C,
|
||||
NDOF_O, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_C; ++dy)
|
||||
{
|
||||
u += DDQ[1][tidz][dz][dy][qx] * Bcc(qy, dy);
|
||||
}
|
||||
DQQ[1][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_O, NQUAD_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_C; ++dz)
|
||||
{
|
||||
u += DQQ[0][tidz][dz][qy][qx] * Gco(qz, dz);
|
||||
}
|
||||
QQQ[0][tidz][qz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_O, NQUAD_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_O; ++dz)
|
||||
{
|
||||
u += DQQ[1][tidz][dz][qy][qx] * Boo(qz, dz);
|
||||
}
|
||||
Y(qx + (qy + qz * NQUAD_C) * NQUAD_O + offsetq, e) =
|
||||
QQQ[0][tidz][qz][qy][qx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// z: Vy Gco Boo Bcc - Vx Boo Gco Bcc
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_O, NDOF_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_C; ++dx)
|
||||
{
|
||||
u += X[1][tidz][dx + (dy + dz * NDOF_O) * NDOF_C] * Gco(qx, dx);
|
||||
}
|
||||
DDQ[0][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, dy, dz, x, NQUAD_O, NDOF_C,
|
||||
NDOF_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dx = 0; dx < NDOF_O; ++dx)
|
||||
{
|
||||
u += X[0][tidz][dx + (dy + dz * NDOF_C) * NDOF_O] * Boo(qx, dx);
|
||||
}
|
||||
DDQ[1][tidz][dz][dy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_O, NQUAD_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_O; ++dy)
|
||||
{
|
||||
u += DDQ[0][tidz][dz][dy][qx] * Boo(qy, dy);
|
||||
}
|
||||
DQQ[0][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, dz, x, NQUAD_O, NQUAD_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dy = 0; dy < NDOF_C; ++dy)
|
||||
{
|
||||
u += DDQ[1][tidz][dz][dy][qx] * Gco(qy, dy);
|
||||
}
|
||||
DQQ[1][tidz][dz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_O, NQUAD_O,
|
||||
NQUAD_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_C; ++dz)
|
||||
{
|
||||
u += DQQ[0][tidz][dz][qy][qx] * Bcc(qz, dz);
|
||||
}
|
||||
QQQ[0][tidz][qz][qy][qx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(qx, qy, qz, x, NQUAD_O, NQUAD_O,
|
||||
NQUAD_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int dz = 0; dz < NDOF_C; ++dz)
|
||||
{
|
||||
u += DQQ[1][tidz][dz][qy][qx] * Bcc(qz, dz);
|
||||
}
|
||||
Y(qx + (qy + qz * NQUAD_O) * NQUAD_O + 2 * offsetq, e) =
|
||||
QQQ[0][tidz][qz][qy][qx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
});
|
||||
}
|
||||
|
||||
template <int T_NDOF_O, int T_NQUAD_O>
|
||||
void CurlInterpolatorTApply3DSmem(const int ne, const int ndof_o,
|
||||
const int nquad_o, const Vector &pa,
|
||||
const Vector &x_, Vector &y_)
|
||||
{
|
||||
constexpr int mnd_o = T_NDOF_O ? T_NDOF_O : DofQuadLimits::HCURL_MAX_D1D - 1;
|
||||
constexpr int mnq_o =
|
||||
T_NQUAD_O ? T_NQUAD_O : DofQuadLimits::HDIV_MAX_D1D - 1;
|
||||
constexpr int mndq = std::max(mnd_o + 1, mnq_o + 1);
|
||||
constexpr int tbatch = curlinterp::NBZ3D(T_NDOF_O, T_NQUAD_O, mndq);
|
||||
MFEM_VERIFY(ndof_o <= mnd_o, "Error: H(curl) order larger than supported");
|
||||
MFEM_VERIFY(nquad_o <= mnq_o, "Error: H(div) order larger than supported");
|
||||
int mnq = std::max(ndof_o + 1, nquad_o + 1);
|
||||
auto pa_data = pa.Read();
|
||||
auto x_d = x_.Read();
|
||||
auto y_d = y_.ReadWrite();
|
||||
mfem::forall_2D_batch<mndq * mndq * (mndq - 1) * tbatch>(
|
||||
ne, mnq * mnq * (mnq - 1), 1, tbatch, [=] MFEM_HOST_DEVICE(int e)
|
||||
{
|
||||
constexpr int MND_O =
|
||||
T_NDOF_O ? T_NDOF_O : DofQuadLimits::HCURL_MAX_D1D - 1;
|
||||
constexpr int MNQ_O =
|
||||
T_NQUAD_O ? T_NQUAD_O : DofQuadLimits::HDIV_MAX_D1D - 1;
|
||||
constexpr int MNDQ = std::max(MND_O + 1, MNQ_O + 1);
|
||||
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
|
||||
constexpr int nbz = curlinterp::NBZ3D(T_NDOF_O, T_NQUAD_O, MNDQ);
|
||||
int tidz = MFEM_THREAD_ID(z);
|
||||
// Make mnq a local variable since capturing would result in different
|
||||
// captures between host/device versions, and spuriously fails
|
||||
int mnq = std::max(ndof_o + 1, nquad_o + 1);
|
||||
#else
|
||||
constexpr int nbz = 1;
|
||||
constexpr int tidz = 0;
|
||||
#endif
|
||||
const int NDOF_O = T_NDOF_O ? T_NDOF_O : ndof_o;
|
||||
const int NQUAD_O = T_NQUAD_O ? T_NQUAD_O : nquad_o;
|
||||
const int NDOF_C = NDOF_O + 1;
|
||||
const int NQUAD_C = NQUAD_O + 1;
|
||||
MFEM_SHARED real_t
|
||||
sBG[(MND_O + 1) * MNQ_O + (MND_O + 1) * (MNQ_O + 1) + MND_O * MNQ_O];
|
||||
auto X_ = Reshape(x_d, 3 * NQUAD_C * NQUAD_O * NQUAD_O, ne);
|
||||
auto Y = Reshape(y_d, 3 * NDOF_C * NDOF_C * NDOF_O, ne);
|
||||
auto Gco = Reshape(sBG, NQUAD_O, NDOF_C);
|
||||
auto Bcc = Reshape(sBG + NDOF_C * NQUAD_O, NQUAD_C, NDOF_C);
|
||||
auto Boo =
|
||||
Reshape(sBG + NDOF_C * NQUAD_O + NDOF_C * NQUAD_C, NQUAD_O, NDOF_O);
|
||||
MFEM_SHARED real_t X[3][nbz][MNQ_O * MNQ_O * (MNQ_O + 1)];
|
||||
MFEM_SHARED real_t sm0[nbz * 2 * MNDQ * MNDQ * MNDQ];
|
||||
MFEM_SHARED real_t sm1[nbz * 2 * MNDQ * MNDQ * MNDQ];
|
||||
|
||||
// shapes of buffers always use MNDQ to mitigate shared memory bank
|
||||
// conflicts
|
||||
real_t(*QQD)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm0);
|
||||
real_t(*QDD)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm1);
|
||||
real_t(*DDD)[nbz][MNDQ][MNDQ][MNDQ] =
|
||||
(real_t(*)[nbz][MNDQ][MNDQ][MNDQ])(sm0);
|
||||
const int offset = NDOF_O * NDOF_C * NDOF_C;
|
||||
const int offsetq = NQUAD_C * NQUAD_O * NQUAD_O;
|
||||
MFEM_FOREACH_THREAD_DIRECT(ix, x, offsetq)
|
||||
{
|
||||
for (int dim = 0; dim < 3; ++dim)
|
||||
{
|
||||
X[dim][tidz][ix] = X_(ix + dim * offsetq, e);
|
||||
}
|
||||
}
|
||||
// load basis functions data
|
||||
if (tidz == 0)
|
||||
{
|
||||
auto npts = NDOF_C * NQUAD_O + NDOF_C * NQUAD_C + NDOF_O * NQUAD_O;
|
||||
MFEM_FOREACH_THREAD(ix, x, npts) { sBG[ix] = pa_data[ix]; }
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// x: Vy Boo Bcc Gco - Vz Boo Gco Bcc
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_C, NQUAD_O,
|
||||
NQUAD_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_O; ++qz)
|
||||
{
|
||||
u += X[1][tidz][qx + (qy + qz * NQUAD_C) * NQUAD_O] * Gco(qz, dz);
|
||||
}
|
||||
QQD[0][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_C, NQUAD_O,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_C; ++qz)
|
||||
{
|
||||
u += X[2][tidz][qx + (qy + qz * NQUAD_O) * NQUAD_O] * Bcc(qz, dz);
|
||||
}
|
||||
QQD[1][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_C, NDOF_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_C; ++qy)
|
||||
{
|
||||
u += QQD[0][tidz][qy][qx][dz] * Bcc(qy, dy);
|
||||
}
|
||||
QDD[0][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_C, NDOF_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_O; ++qy)
|
||||
{
|
||||
u += QQD[1][tidz][qy][qx][dz] * Gco(qy, dy);
|
||||
}
|
||||
QDD[1][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_O, NDOF_C,
|
||||
NDOF_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_O; ++qx)
|
||||
{
|
||||
u += QDD[0][tidz][qx][dz][dy] * Boo(qx, dx);
|
||||
}
|
||||
DDD[0][tidz][dz][dy][dx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_O, NDOF_C,
|
||||
NDOF_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_O; ++qx)
|
||||
{
|
||||
u += QDD[1][tidz][qx][dz][dy] * Boo(qx, dx);
|
||||
}
|
||||
Y(dx + (dy + dz * NDOF_C) * NDOF_O, e) =
|
||||
DDD[0][tidz][dz][dy][dx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// y: Vz Gco Boo Bcc - Vx Bcc Boo Gco
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_C, NQUAD_O,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_C; ++qz)
|
||||
{
|
||||
u += X[2][tidz][qx + (qy + qz * NQUAD_O) * NQUAD_O] * Bcc(qz, dz);
|
||||
}
|
||||
QQD[0][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_C, NQUAD_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_O; ++qz)
|
||||
{
|
||||
u += X[0][tidz][qx + (qy + qz * NQUAD_O) * NQUAD_C] * Gco(qz, dz);
|
||||
}
|
||||
QQD[1][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_O, NDOF_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_O; ++qy)
|
||||
{
|
||||
u += QQD[0][tidz][qy][qx][dz] * Boo(qy, dy);
|
||||
}
|
||||
QDD[0][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_O, NDOF_C,
|
||||
NQUAD_C, mnq - 1, mnq, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_O; ++qy)
|
||||
{
|
||||
u += QQD[1][tidz][qy][qx][dz] * Boo(qy, dy);
|
||||
}
|
||||
QDD[1][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_C, NDOF_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_O; ++qx)
|
||||
{
|
||||
u += QDD[0][tidz][qx][dz][dy] * Gco(qx, dx);
|
||||
}
|
||||
DDD[0][tidz][dz][dy][dx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_C, NDOF_O,
|
||||
NDOF_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_C; ++qx)
|
||||
{
|
||||
u += QDD[1][tidz][qx][dz][dy] * Bcc(qx, dx);
|
||||
}
|
||||
Y(dx + (dy + dz * NDOF_O) * NDOF_C + offset, e) =
|
||||
DDD[0][tidz][dz][dy][dx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// z: Vx Bcc Gco Boo - Vy Gco Bcc Boo
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_O, NQUAD_C,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_O; ++qz)
|
||||
{
|
||||
u += X[0][tidz][qx + (qy + qz * NQUAD_O) * NQUAD_C] * Boo(qz, dz);
|
||||
}
|
||||
QQD[0][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dz, qx, qy, x, NDOF_O, NQUAD_O,
|
||||
NQUAD_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qz = 0; qz < NQUAD_O; ++qz)
|
||||
{
|
||||
u += X[1][tidz][qx + (qy + qz * NQUAD_C) * NQUAD_O] * Boo(qz, dz);
|
||||
}
|
||||
QQD[1][tidz][qy][qx][dz] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_C, NDOF_O,
|
||||
NQUAD_C, mnq, mnq - 1, mnq)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_O; ++qy)
|
||||
{
|
||||
u += QQD[0][tidz][qy][qx][dz] * Gco(qy, dy);
|
||||
}
|
||||
QDD[0][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dy, dz, qx, x, NDOF_C, NDOF_O,
|
||||
NQUAD_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qy = 0; qy < NQUAD_C; ++qy)
|
||||
{
|
||||
u += QQD[1][tidz][qy][qx][dz] * Bcc(qy, dy);
|
||||
}
|
||||
QDD[1][tidz][qx][dz][dy] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_C, NDOF_C,
|
||||
NDOF_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_C; ++qx)
|
||||
{
|
||||
u += QDD[0][tidz][qx][dz][dy] * Bcc(qx, dx);
|
||||
}
|
||||
DDD[0][tidz][dz][dy][dx] = u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
// threads assigned to mitigate bank conflicts
|
||||
MFEM_FOREACH_THREAD_DIRECT_3D_OFFSET(dx, dy, dz, x, NDOF_C, NDOF_C,
|
||||
NDOF_O, mnq, mnq, mnq - 1)
|
||||
{
|
||||
real_t u = 0;
|
||||
for (int qx = 0; qx < NQUAD_O; ++qx)
|
||||
{
|
||||
u += QDD[1][tidz][qx][dz][dy] * Gco(qx, dx);
|
||||
}
|
||||
Y(dx + (dy + dz * NDOF_C) * NDOF_C + 2 * offset, e) =
|
||||
DDD[0][tidz][dz][dy][dx] - u;
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <int DIM, int NDOF_O, int NQUAD_O>
|
||||
CurlInterpolator::ApplyKernelType
|
||||
CurlInterpolator::ApplyPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 3)
|
||||
{
|
||||
return internal::CurlInterpolatorApply3DSmem<NDOF_O, NQUAD_O>;
|
||||
}
|
||||
MFEM_ABORT("Bad dimension!");
|
||||
}
|
||||
|
||||
template <int DIM, int NDOF_O, int NQUAD_O>
|
||||
CurlInterpolator::ApplyKernelType
|
||||
CurlInterpolator::ApplyTPAKernels::Kernel()
|
||||
{
|
||||
if constexpr (DIM == 3)
|
||||
{
|
||||
return internal::CurlInterpolatorTApply3DSmem<NDOF_O, NQUAD_O>;
|
||||
}
|
||||
MFEM_ABORT("Bad dimension!");
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
@@ -14,9 +14,218 @@
|
||||
#include "../gridfunc.hpp"
|
||||
#include "../qfunction.hpp"
|
||||
|
||||
#include "bilininteg_hcurlhdiv_kernels.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void PAHcurlApplyCurl2D(const int c_dofs1D,
|
||||
const int o_dofs1D,
|
||||
const int NE,
|
||||
const Array<real_t> &Bo_,
|
||||
const Array<real_t> &Gc_,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
auto Bo = Reshape(Bo_.Read(), o_dofs1D, o_dofs1D);
|
||||
auto Gc = Reshape(Gc_.Read(), o_dofs1D, c_dofs1D);
|
||||
auto X = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), o_dofs1D, o_dofs1D, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int iy = 0; iy < c_dofs1D; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < o_dofs1D; ++ix)
|
||||
{
|
||||
const real_t xv = X(ix + iy * o_dofs1D, e);
|
||||
for (int oy = 0; oy < o_dofs1D; ++oy)
|
||||
{
|
||||
const real_t gy = Gc(oy, iy);
|
||||
for (int ox = 0; ox < o_dofs1D; ++ox)
|
||||
{
|
||||
Y(ox, oy, e) -= Bo(ox, ix) * gy * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int y_nd = c_dofs1D * o_dofs1D;
|
||||
for (int iy = 0; iy < o_dofs1D; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < c_dofs1D; ++ix)
|
||||
{
|
||||
const real_t xv = X(y_nd + ix + iy * c_dofs1D, e);
|
||||
for (int oy = 0; oy < o_dofs1D; ++oy)
|
||||
{
|
||||
const real_t by = Bo(oy, iy);
|
||||
for (int ox = 0; ox < o_dofs1D; ++ox)
|
||||
{
|
||||
Y(ox, oy, e) += Gc(ox, ix) * by * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PAHcurlApplyCurlTranspose2D(const int c_dofs1D,
|
||||
const int o_dofs1D,
|
||||
const int NE,
|
||||
const Array<real_t> &Bo_,
|
||||
const Array<real_t> &Gc_,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
auto Bo = Reshape(Bo_.Read(), o_dofs1D, o_dofs1D);
|
||||
auto Gc = Reshape(Gc_.Read(), o_dofs1D, c_dofs1D);
|
||||
auto X = Reshape(x_.Read(), o_dofs1D, o_dofs1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int dy = 0; dy < c_dofs1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < o_dofs1D; ++dx)
|
||||
{
|
||||
real_t sum = 0.0;
|
||||
for (int oy = 0; oy < o_dofs1D; ++oy)
|
||||
{
|
||||
const real_t gy = Gc(oy, dy);
|
||||
for (int ox = 0; ox < o_dofs1D; ++ox)
|
||||
{
|
||||
sum -= Bo(ox, dx) * gy * X(ox, oy, e);
|
||||
}
|
||||
}
|
||||
Y(dx + dy * o_dofs1D, e) += sum;
|
||||
}
|
||||
}
|
||||
|
||||
const int y_nd = c_dofs1D * o_dofs1D;
|
||||
for (int dy = 0; dy < o_dofs1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < c_dofs1D; ++dx)
|
||||
{
|
||||
real_t sum = 0.0;
|
||||
for (int oy = 0; oy < o_dofs1D; ++oy)
|
||||
{
|
||||
const real_t by = Bo(oy, dy);
|
||||
for (int ox = 0; ox < o_dofs1D; ++ox)
|
||||
{
|
||||
sum += Gc(ox, dx) * by * X(ox, oy, e);
|
||||
}
|
||||
}
|
||||
Y(y_nd + dx + dy * c_dofs1D, e) += sum;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PAHdivApplyCurl2D(const int c_dofs1D,
|
||||
const int o_dofs1D,
|
||||
const int NE,
|
||||
const Array<real_t> &Bc_,
|
||||
const Array<real_t> &Gc_,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
auto Bc = Reshape(Bc_.Read(), c_dofs1D, c_dofs1D);
|
||||
auto Gc = Reshape(Gc_.Read(), o_dofs1D, c_dofs1D);
|
||||
auto X = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int iy = 0; iy < c_dofs1D; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < c_dofs1D; ++ix)
|
||||
{
|
||||
const real_t xv = X(ix, iy, e);
|
||||
for (int oy = 0; oy < o_dofs1D; ++oy)
|
||||
{
|
||||
const real_t gy = Gc(oy, iy);
|
||||
for (int ox = 0; ox < c_dofs1D; ++ox)
|
||||
{
|
||||
Y(ox + oy * c_dofs1D, e) += Bc(ox, ix) * gy * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int y_nd = c_dofs1D * o_dofs1D;
|
||||
for (int iy = 0; iy < c_dofs1D; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < c_dofs1D; ++ix)
|
||||
{
|
||||
const real_t xv = X(ix, iy, e);
|
||||
for (int oy = 0; oy < c_dofs1D; ++oy)
|
||||
{
|
||||
const real_t by = Bc(oy, iy);
|
||||
for (int ox = 0; ox < o_dofs1D; ++ox)
|
||||
{
|
||||
Y(y_nd + ox + oy * o_dofs1D, e) -= Gc(ox, ix) * by * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PAHdivApplyCurlTranspose2D(const int c_dofs1D,
|
||||
const int o_dofs1D,
|
||||
const int NE,
|
||||
const Array<real_t> &Bc_,
|
||||
const Array<real_t> &Gc_,
|
||||
const Vector &x_,
|
||||
Vector &y_)
|
||||
{
|
||||
auto Bc = Reshape(Bc_.Read(), c_dofs1D, c_dofs1D);
|
||||
auto Gc = Reshape(Gc_.Read(), o_dofs1D, c_dofs1D);
|
||||
auto X = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
|
||||
auto Y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
|
||||
|
||||
mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
for (int dy = 0; dy < o_dofs1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < c_dofs1D; ++dx)
|
||||
{
|
||||
const real_t xv = X(dx + dy * c_dofs1D, e);
|
||||
for (int iy = 0; iy < c_dofs1D; ++iy)
|
||||
{
|
||||
const real_t gy = Gc(dy, iy);
|
||||
for (int ix = 0; ix < c_dofs1D; ++ix)
|
||||
{
|
||||
Y(ix, iy, e) += Bc(dx, ix) * gy * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int y_nd = c_dofs1D * o_dofs1D;
|
||||
for (int dy = 0; dy < c_dofs1D; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < o_dofs1D; ++dx)
|
||||
{
|
||||
const real_t xv = X(y_nd + dx + dy * o_dofs1D, e);
|
||||
for (int iy = 0; iy < c_dofs1D; ++iy)
|
||||
{
|
||||
const real_t by = Bc(dy, iy);
|
||||
for (int ix = 0; ix < c_dofs1D; ++ix)
|
||||
{
|
||||
Y(ix, iy, e) -= Gc(dx, ix) * by * xv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Apply to x corresponding to DOFs in H^1 (domain) the (topological) gradient
|
||||
// to get a dof in H(curl) (range). You can think of the range as the "test" space
|
||||
// and the domain as the "trial" space, but there's no integration.
|
||||
@@ -1950,4 +2159,266 @@ void IdentityInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
}
|
||||
}
|
||||
|
||||
void CurlInterpolator::AssemblePA(const FiniteElementSpace &dom_fes,
|
||||
const FiniteElementSpace &ran_fes)
|
||||
{
|
||||
Mesh *mesh = dom_fes.GetMesh();
|
||||
dim = mesh->Dimension();
|
||||
ne = dom_fes.GetNE();
|
||||
pa_mode_2d = 0;
|
||||
MFEM_VERIFY(ne == ran_fes.GetNE(),
|
||||
"Different meshes for domain and range spaces");
|
||||
|
||||
if (dim == 2)
|
||||
{
|
||||
pa_data.SetSize(0);
|
||||
const FiniteElement *dom_fel = dom_fes.GetTypicalFE();
|
||||
const FiniteElement *ran_fel = ran_fes.GetTypicalFE();
|
||||
const bool hcurl_to_scalar =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(dom_fel) != NULL &&
|
||||
dom_fel->GetDerivType() == FiniteElement::CURL &&
|
||||
dynamic_cast<const TensorBasisElement*>(ran_fel) != NULL &&
|
||||
ran_fel->GetRangeType() == FiniteElement::SCALAR;
|
||||
const bool scalar_to_hdiv =
|
||||
dynamic_cast<const TensorBasisElement*>(dom_fel) != NULL &&
|
||||
dom_fel->GetRangeType() == FiniteElement::SCALAR &&
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(ran_fel) != NULL &&
|
||||
ran_fel->GetDerivType() == FiniteElement::DIV;
|
||||
|
||||
MFEM_VERIFY(hcurl_to_scalar || scalar_to_hdiv,
|
||||
"2D CurlInterpolator PA supports H(curl)->scalar and scalar->H(div) only.");
|
||||
|
||||
int closed_basis_type = -1;
|
||||
int open_basis_type = -1;
|
||||
if (hcurl_to_scalar)
|
||||
{
|
||||
const auto *trial_fec = dynamic_cast<const ND_FECollection*>(dom_fes.FEColl());
|
||||
const auto *range_fec = dynamic_cast<const L2_FECollection*>(ran_fes.FEColl());
|
||||
MFEM_VERIFY(trial_fec != NULL, "H(curl) domain must use ND_FECollection.");
|
||||
MFEM_VERIFY(range_fec != NULL, "Scalar range must use L2_FECollection.");
|
||||
MFEM_VERIFY(ran_fel->GetMapType() == FiniteElement::INTEGRAL,
|
||||
"2D H(curl)->scalar CurlInterpolator PA supports integral-map scalar range spaces only.");
|
||||
closed_basis_type = trial_fec->GetClosedBasisType();
|
||||
open_basis_type = trial_fec->GetOpenBasisType();
|
||||
MFEM_VERIFY(range_fec->GetBasisType() == open_basis_type,
|
||||
"Domain/range open basis types do not match.");
|
||||
pa_mode_2d = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto *trial_fec = dynamic_cast<const H1_FECollection*>(dom_fes.FEColl());
|
||||
const auto *range_fec = dynamic_cast<const RT_FECollection*>(ran_fes.FEColl());
|
||||
MFEM_VERIFY(trial_fec != NULL, "Scalar domain must use H1_FECollection.");
|
||||
MFEM_VERIFY(range_fec != NULL, "H(div) range must use RT_FECollection.");
|
||||
closed_basis_type = trial_fec->GetBasisType();
|
||||
open_basis_type = range_fec->GetOpenBasisType();
|
||||
MFEM_VERIFY(range_fec->GetClosedBasisType() == closed_basis_type,
|
||||
"Domain/range closed basis types do not match.");
|
||||
pa_mode_2d = 2;
|
||||
}
|
||||
|
||||
const int order = hcurl_to_scalar
|
||||
? dynamic_cast<const VectorTensorFiniteElement*>(dom_fel)->GetOrder()
|
||||
: dynamic_cast<const NodalTensorFiniteElement*>(dom_fel)->GetOrder();
|
||||
c_dofs1D = order + 1;
|
||||
o_dofs1D = order;
|
||||
|
||||
closed_dofquad_fe.reset(new H1_SegmentElement(order, closed_basis_type));
|
||||
open_dofquad_fe.reset(new L2_SegmentElement(order - 1, open_basis_type));
|
||||
|
||||
mfem::QuadratureFunctions1D qf1d;
|
||||
mfem::IntegrationRule closed_ir;
|
||||
closed_ir.SetSize(c_dofs1D);
|
||||
qf1d.GaussLobatto(c_dofs1D, &closed_ir);
|
||||
|
||||
mfem::IntegrationRule open_ir;
|
||||
open_ir.SetSize(o_dofs1D);
|
||||
qf1d.GaussLegendre(o_dofs1D, &open_ir);
|
||||
|
||||
maps_C_C = &closed_dofquad_fe->GetDofToQuad(closed_ir, DofToQuad::TENSOR);
|
||||
maps_O_C = &closed_dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR);
|
||||
maps_O_O = &open_dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR);
|
||||
|
||||
MFEM_VERIFY(maps_C_C->ndof == c_dofs1D && maps_C_C->nqpt == c_dofs1D, "");
|
||||
MFEM_VERIFY(maps_O_C->ndof == c_dofs1D && maps_O_C->nqpt == o_dofs1D, "");
|
||||
MFEM_VERIFY(maps_O_O->ndof == o_dofs1D && maps_O_O->nqpt == o_dofs1D, "");
|
||||
return;
|
||||
}
|
||||
|
||||
closed_dofquad_fe.reset();
|
||||
open_dofquad_fe.reset();
|
||||
maps_C_C = nullptr;
|
||||
maps_O_C = nullptr;
|
||||
maps_O_O = nullptr;
|
||||
|
||||
const VectorTensorFiniteElement *dom_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement *>(dom_fes.GetTypicalFE());
|
||||
const VectorTensorFiniteElement *ran_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement *>(ran_fes.GetTypicalFE());
|
||||
MFEM_VERIFY(dom_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
MFEM_VERIFY(ran_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
MFEM_VERIFY(dom_el->GetDerivType() == FiniteElement::CURL,
|
||||
"Domain space must be H(curl)");
|
||||
MFEM_VERIFY(ran_el->GetDerivType() == FiniteElement::DIV,
|
||||
"Range space must be H(div)");
|
||||
|
||||
const int dims = dom_el->GetDim();
|
||||
MFEM_VERIFY(dims == 3, "");
|
||||
|
||||
ndof_o = dom_el->GetOrder();
|
||||
int ndof_c = ndof_o + 1;
|
||||
nquad_o = ran_el->GetOrder();
|
||||
int nquad_c = nquad_o + 1;
|
||||
|
||||
// extract the tensor product range dof locations
|
||||
std::vector<real_t> qc(nquad_c);
|
||||
std::vector<real_t> qo(nquad_o);
|
||||
{
|
||||
const IntegrationRule &ran_nodes = ran_el->GetNodes();
|
||||
const Array<int> &quad_map = ran_el->GetDofMap();
|
||||
for (int i = 0; i < nquad_c; ++i)
|
||||
{
|
||||
int idx = UnsignIndex(quad_map[i]);
|
||||
qc[i] = ran_nodes.IntPoint(idx).x;
|
||||
}
|
||||
int offset = ndof_c * ndof_o * ndof_o;
|
||||
for (int i = 0; i < nquad_o; ++i)
|
||||
{
|
||||
int idx = UnsignIndex(quad_map[i + offset]);
|
||||
qo[i] = ran_nodes.IntPoint(idx).x;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate closed/open 1D basis (and their derivatives) at closed and
|
||||
// open quads
|
||||
// storage order: GCO, BCC, BOO
|
||||
pa_data.SetSize(ndof_c * nquad_o + ndof_c * nquad_c + ndof_o * nquad_o);
|
||||
auto ptr = pa_data.HostWrite();
|
||||
auto &cbasis1d = dom_el->GetBasis1D();
|
||||
auto &obasis1d = dom_el->GetOpenBasis1D();
|
||||
Vector b, g;
|
||||
b.SetSize(ndof_c);
|
||||
g.SetSize(ndof_c);
|
||||
for (int j = 0; j < nquad_o; ++j)
|
||||
{
|
||||
cbasis1d.Eval(qo[j], b, g);
|
||||
for (int i = 0; i < ndof_c; ++i)
|
||||
{
|
||||
ptr[j + i * nquad_o] = g[i];
|
||||
}
|
||||
}
|
||||
ptr += nquad_o * ndof_c;
|
||||
|
||||
for (int j = 0; j < nquad_c; ++j)
|
||||
{
|
||||
cbasis1d.Eval(qc[j], b);
|
||||
for (int i = 0; i < ndof_c; ++i)
|
||||
{
|
||||
ptr[j + i * nquad_c] = b[i];
|
||||
}
|
||||
}
|
||||
ptr += ndof_c * nquad_c;
|
||||
|
||||
b.SetSize(ndof_o);
|
||||
for (int j = 0; j < nquad_o; ++j)
|
||||
{
|
||||
obasis1d.Eval(qo[j], b);
|
||||
for (int i = 0; i < ndof_o; ++i)
|
||||
{
|
||||
ptr[j + i * nquad_o] = b[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CurlInterpolator::Kernels::Kernels()
|
||||
{
|
||||
CurlInterpolator::AddSpecialization<3, 1, 1>();
|
||||
CurlInterpolator::AddSpecialization<3, 2, 2>();
|
||||
CurlInterpolator::AddSpecialization<3, 3, 3>();
|
||||
CurlInterpolator::AddSpecialization<3, 4, 4>();
|
||||
CurlInterpolator::AddSpecialization<3, 5, 5>();
|
||||
}
|
||||
|
||||
CurlInterpolator::CurlInterpolator() { static Kernels kernels{}; }
|
||||
|
||||
void CurlInterpolator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
MFEM_VERIFY(maps_C_C != nullptr && maps_O_C != nullptr,
|
||||
"2D CurlInterpolator PA data is not assembled.");
|
||||
if (pa_mode_2d == 1)
|
||||
{
|
||||
MFEM_VERIFY(maps_O_O != nullptr,
|
||||
"2D CurlInterpolator scalar curl map is not assembled.");
|
||||
PAHcurlApplyCurl2D(c_dofs1D, o_dofs1D, ne, maps_O_O->B, maps_O_C->G,
|
||||
x, y);
|
||||
}
|
||||
else if (pa_mode_2d == 2)
|
||||
{
|
||||
PAHdivApplyCurl2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->G,
|
||||
x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported 2D CurlInterpolator mode.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyPAKernels::Run(dim, ndof_o, nquad_o, ne, ndof_o, nquad_o, pa_data, x, y);
|
||||
}
|
||||
|
||||
void CurlInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (dim == 2)
|
||||
{
|
||||
MFEM_VERIFY(maps_C_C != nullptr && maps_O_C != nullptr,
|
||||
"2D CurlInterpolator PA data is not assembled.");
|
||||
if (pa_mode_2d == 1)
|
||||
{
|
||||
MFEM_VERIFY(maps_O_O != nullptr,
|
||||
"2D CurlInterpolator scalar curl map is not assembled.");
|
||||
PAHcurlApplyCurlTranspose2D(c_dofs1D, o_dofs1D, ne, maps_O_O->B,
|
||||
maps_O_C->G, x, y);
|
||||
}
|
||||
else if (pa_mode_2d == 2)
|
||||
{
|
||||
PAHdivApplyCurlTranspose2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
|
||||
maps_O_C->G, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unsupported 2D CurlInterpolator mode.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyTPAKernels::Run(dim, ndof_o, nquad_o, ne, ndof_o, nquad_o, pa_data, x, y);
|
||||
}
|
||||
|
||||
/// \cond DO_NOT_DOCUMENT
|
||||
|
||||
CurlInterpolator::ApplyKernelType
|
||||
CurlInterpolator::ApplyPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 3)
|
||||
{
|
||||
return internal::CurlInterpolatorApply3DSmem<0, 0>;
|
||||
}
|
||||
MFEM_ABORT("Bad dimension!");
|
||||
}
|
||||
|
||||
CurlInterpolator::ApplyKernelType
|
||||
CurlInterpolator::ApplyTPAKernels::Fallback(int DIM, int, int)
|
||||
{
|
||||
if (DIM == 3)
|
||||
{
|
||||
return internal::CurlInterpolatorTApply3DSmem<0, 0>;
|
||||
}
|
||||
MFEM_ABORT("Bad dimension!");
|
||||
}
|
||||
|
||||
/// \endcond DO_NOT_DOCUMENT
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -672,6 +672,8 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
|
||||
const NodalTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
|
||||
MFEM_VERIFY(trial_el != NULL, "Only NodalTensorFiniteElement is supported!");
|
||||
MFEM_VERIFY(trial_el->GetMapType() == FiniteElement::VALUE,
|
||||
"Only value map type is supported!");
|
||||
|
||||
const VectorTensorFiniteElement *test_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
|
||||
|
||||
@@ -22,6 +22,8 @@ void VectorMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
MFEM_VERIFY(el.GetMapType() == FiniteElement::VALUE,
|
||||
"Only value map type supported");
|
||||
ElementTransformation &Trans = *mesh->GetTypicalElementTransformation();
|
||||
const auto *ir = IntRule ? IntRule : &MassIntegrator::GetRule(el, el, Trans);
|
||||
|
||||
|
||||
+4
-4
@@ -94,10 +94,10 @@ void BatchedLOR_AMS::Form2DEdgeToVertex_RT(Array<int> &edge2vert)
|
||||
const int iv0 = ix + iy*op1;
|
||||
const int iv1 = ix1 + iy1*op1;
|
||||
|
||||
// Rotated gradient in 2D (-dy, dx), so flip the sign for the first
|
||||
// component (c == 0).
|
||||
e2v(0, iedge) = (c == 1) ? iv0 : iv1;
|
||||
e2v(1, iedge) = (c == 1) ? iv1 : iv0;
|
||||
// 2D curl (dy, -dx), so flip the sign for the second
|
||||
// component (c == 1).
|
||||
e2v(0, iedge) = (c == 0) ? iv0 : iv1;
|
||||
e2v(1, iedge) = (c == 0) ? iv1 : iv0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -142,8 +142,6 @@ static MFEM_HOST_DEVICE int GetAndIncrementNnzIndex(const int i_L, int* I)
|
||||
|
||||
int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
{
|
||||
static constexpr int Max = 16;
|
||||
|
||||
const int nvdof = fes_ho.GetVSize();
|
||||
|
||||
const int ndof_per_el = fes_ho.GetTypicalFE()->GetDof();
|
||||
@@ -165,6 +163,8 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
const auto K = dof_glob2loc_offsets_.Read();
|
||||
const auto map = Reshape(sparse_mapping.Read(), nnz_per_row, ndof_per_el);
|
||||
|
||||
Array<int> ij_elts(dof_glob2loc_.Size() * 2);
|
||||
auto d_ij_elts = Reshape(ij_elts.Write(), dof_glob2loc_.Size(), 2);
|
||||
|
||||
auto I = A.WriteI();
|
||||
|
||||
@@ -176,10 +176,10 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
const int sii = el_dof_lex(ii_el, iel_ho);
|
||||
const int ii = (sii >= 0) ? sii : -1 -sii;
|
||||
// Get number and list of elements containing this DOF
|
||||
int i_elts[Max];
|
||||
const int i_offset = K[ii];
|
||||
const int i_next_offset = K[ii+1];
|
||||
const int i_ne = i_next_offset - i_offset;
|
||||
int *i_elts = &d_ij_elts(i_offset, 0);
|
||||
for (int e_i = 0; e_i < i_ne; ++e_i)
|
||||
{
|
||||
const int si_E = dof_glob2loc[i_offset+e_i]; // signed
|
||||
@@ -202,7 +202,7 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
}
|
||||
else // assembly required
|
||||
{
|
||||
int j_elts[Max];
|
||||
int *j_elts = &d_ij_elts(j_offset, 1);
|
||||
for (int e_j = 0; e_j < j_ne; ++e_j)
|
||||
{
|
||||
const int sj_E = dof_glob2loc[j_offset+e_j]; // signed
|
||||
@@ -269,7 +269,8 @@ void BatchedLORAssembly::FillJAndData(SparseMatrix &A) const
|
||||
mfem::forall(nvdof + 1, [=] MFEM_HOST_DEVICE (int i) { I[i] = I2[i]; });
|
||||
}
|
||||
|
||||
static constexpr int Max = 16;
|
||||
Array<int> ij_B_el(dof_glob2loc_.Size() * 4);
|
||||
auto d_ij_B_el = Reshape(ij_B_el.Write(), dof_glob2loc_.Size(), 4);
|
||||
|
||||
mfem::forall(ndof_per_el*nel_ho, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
@@ -279,11 +280,13 @@ void BatchedLORAssembly::FillJAndData(SparseMatrix &A) const
|
||||
const int sii = el_dof_lex(ii_el, iel_ho); // signed
|
||||
const int ii = (sii >= 0) ? sii : -1 - sii;
|
||||
// Get number and list of elements containing this DOF
|
||||
int i_elts[Max];
|
||||
int i_B[Max];
|
||||
const int i_offset = K[ii];
|
||||
const int i_next_offset = K[ii+1];
|
||||
const int i_ne = i_next_offset - i_offset;
|
||||
|
||||
int *i_elts = &d_ij_B_el(i_offset, 0);
|
||||
int *i_B = &d_ij_B_el(i_offset, 1);
|
||||
|
||||
for (int e_i = 0; e_i < i_ne; ++e_i)
|
||||
{
|
||||
const int si_E = dof_glob2loc[i_offset+e_i]; // signed
|
||||
@@ -312,8 +315,8 @@ void BatchedLORAssembly::FillJAndData(SparseMatrix &A) const
|
||||
}
|
||||
else // assembly required
|
||||
{
|
||||
int j_elts[Max];
|
||||
int j_B[Max];
|
||||
int *j_elts = &d_ij_B_el(j_offset, 2);
|
||||
int *j_B = &d_ij_B_el(j_offset, 3);
|
||||
for (int e_j = 0; e_j < j_ne; ++e_j)
|
||||
{
|
||||
const int sj_E = dof_glob2loc[j_offset+e_j]; // signed
|
||||
|
||||
+28
-7
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "../config/config.hpp"
|
||||
|
||||
#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
#include <cusparse.h>
|
||||
#include <library_types.h>
|
||||
#include <cuda_runtime.h>
|
||||
@@ -22,7 +22,7 @@
|
||||
#endif
|
||||
#include "cuda.hpp"
|
||||
|
||||
#if defined(MFEM_USE_HIP) && defined(__HIP__)
|
||||
#if defined(MFEM_USE_HIP)
|
||||
#include <hip/hip_runtime.h>
|
||||
#endif
|
||||
#include "hip.hpp"
|
||||
@@ -45,15 +45,17 @@
|
||||
#endif
|
||||
|
||||
#if !defined(MFEM_USE_CUDA_OR_HIP)
|
||||
constexpr bool mfem_use_gpu = false;
|
||||
#define MFEM_DEVICE
|
||||
#define MFEM_HOST
|
||||
#define MFEM_LAMBDA
|
||||
// #define MFEM_HOST_DEVICE // defined in config/config.hpp
|
||||
// MFEM_DEVICE_SYNC is made available for debugging purposes
|
||||
#define MFEM_DEVICE_SYNC
|
||||
// MFEM_STREAM_SYNC is used for UVM and MPI GPU-Aware kernels
|
||||
#define MFEM_STREAM_SYNC
|
||||
#endif
|
||||
|
||||
#if !defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
#define MFEM_DEVICE
|
||||
#define MFEM_HOST
|
||||
#define MFEM_LAMBDA
|
||||
// #define MFEM_HOST_DEVICE // defined in config/config.hpp
|
||||
#define MFEM_LAUNCH_BOUNDS(...)
|
||||
#endif
|
||||
|
||||
@@ -126,4 +128,23 @@ MFEM_HOST_DEVICE T AtomicAdd(T &add, const T val)
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace mfem::internal
|
||||
{
|
||||
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP) && !defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
static constexpr bool can_compile_kernels = false;
|
||||
#else
|
||||
static constexpr bool can_compile_kernels = true;
|
||||
#endif
|
||||
|
||||
template <bool can_compile_kernels = can_compile_kernels>
|
||||
void RequireKernelCompilation()
|
||||
{
|
||||
static_assert(
|
||||
can_compile_kernels,
|
||||
"The calling function needs to be compiled with CUDA/HIP language!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_BACKENDS_HPP
|
||||
|
||||
+13
-9
@@ -18,14 +18,8 @@
|
||||
// CUDA block size used by MFEM.
|
||||
#define MFEM_CUDA_BLOCKS 256
|
||||
|
||||
#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
#define MFEM_USE_CUDA_OR_HIP
|
||||
constexpr bool mfem_use_gpu = true;
|
||||
#define MFEM_DEVICE __device__
|
||||
#define MFEM_HOST __host__
|
||||
#define MFEM_LAMBDA __host__
|
||||
#define MFEM_LAUNCH_BOUNDS __launch_bounds__
|
||||
// #define MFEM_HOST_DEVICE __host__ __device__ // defined in config/config.hpp
|
||||
#define MFEM_DEVICE_SYNC MFEM_GPU_CHECK(cudaDeviceSynchronize())
|
||||
#define MFEM_STREAM_SYNC MFEM_GPU_CHECK(cudaStreamSynchronize(0))
|
||||
// Define a CUDA error check macro, MFEM_GPU_CHECK(x), where x returns/is of
|
||||
@@ -40,6 +34,15 @@ constexpr bool mfem_use_gpu = true;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Macros defined only when compiling with CUDA language
|
||||
#if defined(__CUDACC__)
|
||||
#define MFEM_USE_CUDA_OR_HIP_LANG
|
||||
#define MFEM_DEVICE __device__
|
||||
#define MFEM_HOST __host__
|
||||
#define MFEM_LAMBDA __host__
|
||||
#define MFEM_LAUNCH_BOUNDS __launch_bounds__
|
||||
// #define MFEM_HOST_DEVICE __host__ __device__ // defined in config/config.hpp
|
||||
|
||||
// Define the MFEM inner threading macros
|
||||
#if defined(__CUDA_ARCH__)
|
||||
#define MFEM_SHARED __shared__
|
||||
@@ -67,12 +70,13 @@ constexpr bool mfem_use_gpu = true;
|
||||
if (int ix = threadIdx.k % (OX), iy = threadIdx.k / (OX), iz = iy / (OY); \
|
||||
(ix < (SX)) && ((iy %= (OY)) < (SY)) && (iz < (SZ)))
|
||||
#endif // defined(__CUDA_ARCH__)
|
||||
#endif // defined(MFEM_USE_CUDA) && defined(__CUDACC__)
|
||||
#endif // defined(__CUDACC__)
|
||||
#endif // defined(MFEM_USE_CUDA)
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
#if defined(MFEM_USE_CUDA) && defined(__CUDACC__)
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
// Function used by the macro MFEM_GPU_CHECK.
|
||||
void mfem_cuda_error(cudaError_t err, const char *expr, const char *func,
|
||||
const char *file, int line);
|
||||
|
||||
+1
-1
@@ -171,7 +171,7 @@ void mfem_error(const char *msg)
|
||||
#ifdef MFEM_USE_EXCEPTIONS
|
||||
if (mfem_error_action == MFEM_ERROR_THROW)
|
||||
{
|
||||
throw ErrorException(msg);
|
||||
throw ErrorException(msg ? msg : "");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+2
-10
@@ -15,7 +15,7 @@
|
||||
#include "../config/config.hpp"
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#ifdef MFEM_USE_HIP
|
||||
#if defined(MFEM_USE_HIP)
|
||||
#include <hip/hip_runtime.h>
|
||||
#endif
|
||||
|
||||
@@ -153,21 +153,13 @@ void mfem_warning(const char *msg = NULL);
|
||||
|
||||
|
||||
// Additional abort functions for HIP
|
||||
#if defined(MFEM_USE_HIP)
|
||||
#ifndef __HIP_DEVICE_COMPILE__
|
||||
template<typename T>
|
||||
__host__ void abort_msg(T & msg)
|
||||
{
|
||||
MFEM_ABORT(msg);
|
||||
}
|
||||
#else
|
||||
#if defined(__HIP_DEVICE_COMPILE__)
|
||||
template<typename T>
|
||||
__device__ void abort_msg(T & msg)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Abort inside a device kernel
|
||||
#if defined(__CUDA_ARCH__)
|
||||
|
||||
@@ -1044,6 +1044,8 @@ inline void ForallWrap(const bool use_dev, const int N,
|
||||
const int X=0, const int Y=0, const int Z=0,
|
||||
const int G=0)
|
||||
{
|
||||
internal::RequireKernelCompilation();
|
||||
|
||||
MFEM_CONTRACT_VAR(X);
|
||||
MFEM_CONTRACT_VAR(Y);
|
||||
MFEM_CONTRACT_VAR(Z);
|
||||
@@ -1276,6 +1278,9 @@ inline void hypre_forall_cpu(int N, lambda &&body)
|
||||
template<typename lambda>
|
||||
inline void hypre_forall_gpu(int N, lambda &&body)
|
||||
{
|
||||
internal::RequireKernelCompilation();
|
||||
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
#if defined(HYPRE_USING_CUDA)
|
||||
CuWrap1D(N, body);
|
||||
#elif defined(HYPRE_USING_HIP)
|
||||
@@ -1283,6 +1288,7 @@ inline void hypre_forall_gpu(int N, lambda &&body)
|
||||
#else
|
||||
#error Unknown HYPRE GPU backend!
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+12
-8
@@ -18,14 +18,8 @@
|
||||
// HIP block size used by MFEM.
|
||||
#define MFEM_HIP_BLOCKS 256
|
||||
|
||||
#if defined(MFEM_USE_HIP) && defined(__HIP__)
|
||||
#if defined(MFEM_USE_HIP)
|
||||
#define MFEM_USE_CUDA_OR_HIP
|
||||
constexpr bool mfem_use_gpu = true;
|
||||
#define MFEM_DEVICE __device__
|
||||
#define MFEM_HOST __host__
|
||||
#define MFEM_LAMBDA __host__ __device__
|
||||
#define MFEM_LAUNCH_BOUNDS __launch_bounds__
|
||||
// #define MFEM_HOST_DEVICE __host__ __device__ // defined in config/config.hpp
|
||||
#define MFEM_DEVICE_SYNC MFEM_GPU_CHECK(hipDeviceSynchronize())
|
||||
#define MFEM_STREAM_SYNC MFEM_GPU_CHECK(hipStreamSynchronize(0))
|
||||
// Define a HIP error check macro, MFEM_GPU_CHECK(x), where x returns/is of
|
||||
@@ -40,6 +34,15 @@ constexpr bool mfem_use_gpu = true;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Macros defined only when compiling with HIP language
|
||||
#if defined(__HIP__)
|
||||
#define MFEM_USE_CUDA_OR_HIP_LANG
|
||||
#define MFEM_DEVICE __device__
|
||||
#define MFEM_HOST __host__
|
||||
#define MFEM_LAMBDA __host__ __device__
|
||||
#define MFEM_LAUNCH_BOUNDS __launch_bounds__
|
||||
// #define MFEM_HOST_DEVICE __host__ __device__ // defined in config/config.hpp
|
||||
|
||||
// Define the MFEM inner threading macros
|
||||
#if defined(__HIP_DEVICE_COMPILE__)
|
||||
#define MFEM_SHARED __shared__
|
||||
@@ -71,7 +74,8 @@ constexpr bool mfem_use_gpu = true;
|
||||
iz = iy / (OY); \
|
||||
(ix < (SX)) && ((iy %= (OY)) < (SY)) && (iz < (SZ)))
|
||||
#endif // defined(__HIP_DEVICE_COMPILE__)
|
||||
#endif // defined(MFEM_USE_HIP) && defined(__HIP__)
|
||||
#endif // defined(__HIP__)
|
||||
#endif // defined(MFEM_USE_HIP)
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -550,10 +550,10 @@ void reduce(int N, T &res, B &&body, const R &reducer, bool use_dev,
|
||||
|
||||
int num_mp = Device::NumMultiprocessors(Device::GetId());
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
// good value of mp_sat found experimentally on Lassen
|
||||
// good value of mp_sat found experimentally on Lassen (V100)
|
||||
constexpr int mp_sat = 8;
|
||||
#elif defined(MFEM_USE_HIP)
|
||||
// good value of mp_sat found experimentally on Tuolumne
|
||||
// good value of mp_sat found experimentally on Tuolumne (MI300A)
|
||||
constexpr int mp_sat = 4;
|
||||
#else
|
||||
num_mp = 1;
|
||||
|
||||
+7
-1
@@ -15,6 +15,10 @@
|
||||
#include "backends.hpp"
|
||||
#include "forall.hpp"
|
||||
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP) && !defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
#error "This header requires compilation with CUDA/HIP language!"
|
||||
#else
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
#include <cub/device/device_scan.cuh>
|
||||
#include <cub/device/device_select.cuh>
|
||||
@@ -406,4 +410,6 @@ void CopyUnique(bool use_dev, InputIt d_in, OutputIt d_out,
|
||||
|
||||
#undef MFEM_CUB_NAMESPACE
|
||||
|
||||
#endif
|
||||
#endif // defined(MFEM_USE_CUDA_OR_HIP) && !defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
|
||||
#endif // MFEM_SCAN_HPP
|
||||
|
||||
@@ -27,6 +27,7 @@ list(APPEND SRCS
|
||||
handle.cpp
|
||||
matrix.cpp
|
||||
mma.cpp
|
||||
multivector.cpp
|
||||
ode.cpp
|
||||
operator.cpp
|
||||
ordering.cpp
|
||||
@@ -63,6 +64,7 @@ list(APPEND HDRS
|
||||
linalg.hpp
|
||||
matrix.hpp
|
||||
mma.hpp
|
||||
multivector.hpp
|
||||
ode.hpp
|
||||
operator.hpp
|
||||
ordering.hpp
|
||||
|
||||
+40
-20
@@ -87,6 +87,9 @@ CuDSSSolver::CuDSSSolver(MPI_Comm comm_) : mpi_comm(comm_)
|
||||
|
||||
CuDSSSolver::~CuDSSSolver()
|
||||
{
|
||||
// Sync the stream to make sure any pending asynchronous operations have
|
||||
// completed.
|
||||
MFEM_STREAM_SYNC;
|
||||
// Destroy the system Matrix, RHS vector and solution vector
|
||||
if (Ac)
|
||||
{
|
||||
@@ -99,7 +102,6 @@ CuDSSSolver::~CuDSSSolver()
|
||||
MFEM_CUDSS_CHECK(cudssDataDestroy(handle, solverData));
|
||||
MFEM_CUDSS_CHECK(cudssConfigDestroy(solverConfig));
|
||||
|
||||
|
||||
MFEM_CUDSS_CHECK(cudssDestroy(handle));
|
||||
handle = nullptr;
|
||||
|
||||
@@ -125,6 +127,9 @@ void CuDSSSolver::InitCuDSS()
|
||||
// Create the cuDSS handle
|
||||
MFEM_CUDSS_CHECK(cudssCreate(&handle));
|
||||
|
||||
// Set CuDSS to use MFEM's default stream of 0.
|
||||
MFEM_CUDSS_CHECK(cudssSetStream(handle, 0));
|
||||
|
||||
#ifdef MFEM_USE_OPENMP
|
||||
// NOTE: Set the threading layer library name to NULL so that cuDSS picks
|
||||
// it from the environment variable "CUDSS_THREADING_LIB"
|
||||
@@ -251,27 +256,42 @@ void CuDSSSolver::SetMatrixCuDSS(int *csr_offsets, int *csr_columns,
|
||||
Ac = std::make_unique<cudssMatrix_t>();
|
||||
// Create empty RHS and solution vectors
|
||||
SetNumRHS(1);
|
||||
// Allocate device memory for csr values
|
||||
CuMemAlloc(&csr_values_d, nnz * sizeof(real_t));
|
||||
}
|
||||
|
||||
if (cuDSSObjectInitialized && !reorder_reuse)
|
||||
{
|
||||
MFEM_STREAM_SYNC;
|
||||
MFEM_CUDSS_CHECK(cudssMatrixDestroy(*Ac));
|
||||
}
|
||||
|
||||
// Allocate device memory for csr values. Unless reuse is specified, the
|
||||
// nnz may be different, so we will free and reallocate.
|
||||
if (csr_values_d == NULL || !reorder_reuse)
|
||||
{
|
||||
if (csr_values_d != NULL) { CuMemFree(csr_values_d); }
|
||||
CuMemAlloc(&csr_values_d, nnz * sizeof(real_t));
|
||||
}
|
||||
CuMemcpyDtoD(csr_values_d, csr_values, nnz * sizeof(real_t));
|
||||
|
||||
// We copy and store the I and J arrays, since the CuDSS matrix object
|
||||
// technically needs these to be valid, so we protect against the caller
|
||||
// destroying the original matrix.
|
||||
if (!cuDSSObjectInitialized || !reorder_reuse)
|
||||
{
|
||||
if (csr_offsets_d != NULL) { CuMemFree(csr_offsets_d); }
|
||||
CuMemAlloc(&csr_offsets_d, (n_loc + 1) * sizeof(int));
|
||||
if (csr_columns_d != NULL) { CuMemFree(csr_columns_d); }
|
||||
CuMemAlloc(&csr_columns_d, nnz * sizeof(int));
|
||||
CuMemcpyDtoD(csr_offsets_d, csr_offsets, (n_loc + 1) * sizeof(int));
|
||||
CuMemcpyDtoD(csr_columns_d, csr_columns, nnz * sizeof(int));
|
||||
}
|
||||
|
||||
// New cuDSS CSR matrix object and analysis or reuse the one from a previous
|
||||
// matrix
|
||||
if (!cuDSSObjectInitialized || !reorder_reuse)
|
||||
{
|
||||
if (reorder_reuse) // !cuDSSObjectInitialized && reorder_reuse
|
||||
{
|
||||
// NOTE: For CuDSS solver to reuse the reordering (skipping analysis
|
||||
// phase), it needs to access the I and J arrays of the **initial**
|
||||
// matrix. Therefore, we need to copy and keep I and J in device memory.
|
||||
CuMemAlloc(&csr_offsets_d, (n_loc + 1) * sizeof(int));
|
||||
CuMemAlloc(&csr_columns_d, nnz * sizeof(int));
|
||||
|
||||
CuMemcpyDtoD(csr_offsets_d, csr_offsets, (n_loc + 1) * sizeof(int));
|
||||
CuMemcpyDtoD(csr_columns_d, csr_columns, nnz * sizeof(int));
|
||||
|
||||
#if CUDSS_VERSION >= 800
|
||||
MFEM_CUDSS_CHECK(
|
||||
cudssMatrixCreateCsr(
|
||||
@@ -288,21 +308,17 @@ void CuDSSSolver::SetMatrixCuDSS(int *csr_offsets, int *csr_columns,
|
||||
}
|
||||
else // !reorder_reuse
|
||||
{
|
||||
if (cuDSSObjectInitialized)
|
||||
{
|
||||
MFEM_CUDSS_CHECK(cudssMatrixDestroy(*Ac));
|
||||
}
|
||||
#if CUDSS_VERSION >= 800
|
||||
MFEM_CUDSS_CHECK(
|
||||
cudssMatrixCreateCsr(
|
||||
Ac.get(), n_global, n_global, nnz, csr_offsets, NULL,
|
||||
csr_columns, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
|
||||
Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
|
||||
csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_INT_T, CUDSS_REAL_T,
|
||||
mat_type, mview, CUDSS_BASE_ZERO));
|
||||
#else
|
||||
MFEM_CUDSS_CHECK(
|
||||
cudssMatrixCreateCsr(
|
||||
Ac.get(), n_global, n_global, nnz, csr_offsets, NULL,
|
||||
csr_columns, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
|
||||
Ac.get(), n_global, n_global, nnz, csr_offsets_d, NULL,
|
||||
csr_columns_d, csr_values_d, CUDSS_INT_T, CUDSS_REAL_T,
|
||||
mat_type, mview, CUDSS_BASE_ZERO));
|
||||
#endif
|
||||
}
|
||||
@@ -326,6 +342,9 @@ void CuDSSSolver::SetMatrixCuDSS(int *csr_offsets, int *csr_columns,
|
||||
// Factorization
|
||||
MFEM_CUDSS_CHECK(cudssExecute(handle, CUDSS_PHASE_FACTORIZATION, solverConfig,
|
||||
solverData, *Ac, yc, xc));
|
||||
|
||||
// In serial, the factorization can execute asynchronously.
|
||||
MFEM_STREAM_SYNC;
|
||||
}
|
||||
|
||||
void CuDSSSolver::SetOperator(const Operator &op)
|
||||
@@ -360,6 +379,7 @@ void CuDSSSolver::SetNumRHS(int nrhs_) const
|
||||
if (nrhs > 0)
|
||||
{
|
||||
// Destroy the previous RHS vector and solution vector
|
||||
MFEM_STREAM_SYNC;
|
||||
MFEM_CUDSS_CHECK(cudssMatrixDestroy(xc));
|
||||
MFEM_CUDSS_CHECK(cudssMatrixDestroy(yc));
|
||||
}
|
||||
|
||||
+1
-2
@@ -157,8 +157,7 @@ private:
|
||||
mutable int nrhs = 0; // the number of the RHSs
|
||||
int nnz = 0; // the number of non zeros
|
||||
|
||||
// copy and keep the I and J arrays in device memory when skipping analysis
|
||||
// phase
|
||||
// copy and keep the I and J arrays in device memory
|
||||
void *csr_offsets_d = NULL; // copy and keep I in device
|
||||
void *csr_columns_d = NULL; // copy and keep J in device
|
||||
void *csr_values_d = NULL; // copy and keep csr data in device
|
||||
|
||||
@@ -1136,6 +1136,17 @@ private:
|
||||
public:
|
||||
DenseTensor() : ni(0), nj(0), nk(0) { }
|
||||
|
||||
DenseTensor(const DenseTensor &other)
|
||||
: tdata(other.tdata), ni(other.ni), nj(other.nj), nk(other.nk) { }
|
||||
|
||||
DenseTensor(DenseTensor &&other)
|
||||
: tdata(std::move(other.tdata)), ni(other.ni), nj(other.nj), nk(other.nk)
|
||||
{
|
||||
// Reset other; other.tdata is reset in Array<T> move constructror.
|
||||
other.Mk.ClearExternalData();
|
||||
other.ni = other.nj = other.nk = 0;
|
||||
}
|
||||
|
||||
DenseTensor(int i, int j, int k) : tdata(i*j*k), ni(i), nj(j), nk(k) { }
|
||||
|
||||
DenseTensor(real_t *d, int i, int j, int k)
|
||||
@@ -1144,6 +1155,33 @@ public:
|
||||
DenseTensor(int i, int j, int k, MemoryType mt)
|
||||
: tdata(i*j*k, mt), ni(i), nj(j), nk(k) { }
|
||||
|
||||
DenseTensor &operator=(const DenseTensor &other)
|
||||
{
|
||||
if (this == &other) { return *this; }
|
||||
Mk.ClearExternalData();
|
||||
tdata = other.tdata;
|
||||
ni = other.ni;
|
||||
nj = other.nj;
|
||||
nk = other.nk;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DenseTensor &operator=(DenseTensor &&other)
|
||||
{
|
||||
if (this == &other) { return *this; }
|
||||
Mk.ClearExternalData();
|
||||
tdata = std::move(other.tdata);
|
||||
ni = other.ni;
|
||||
nj = other.nj;
|
||||
nk = other.nk;
|
||||
|
||||
// Reset other; other.tdata is reset in Array<T> move assignment.
|
||||
other.Mk.ClearExternalData();
|
||||
other.ni = other.nj = other.nk = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int SizeI() const { return ni; }
|
||||
int SizeJ() const { return nj; }
|
||||
int SizeK() const { return nk; }
|
||||
|
||||
@@ -5842,6 +5842,10 @@ void HypreAMS::MakeGradientAndInterpolation(
|
||||
{
|
||||
grad->AddTraceFaceInterpolator(new GradientInterpolator);
|
||||
}
|
||||
else if (dynamic_cast<const RT_FECollection *>(edge_fec))
|
||||
{
|
||||
grad->AddDomainInterpolator(new CurlInterpolator);
|
||||
}
|
||||
else
|
||||
{
|
||||
grad->AddDomainInterpolator(new GradientInterpolator);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// Linear algebra header file
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "multivector.hpp"
|
||||
#include "operator.hpp"
|
||||
#include "matrix.hpp"
|
||||
#include "sparsemat.hpp"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
#include "multivector.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MultiVector::MultiVector(const Array<int> &vector_sizes)
|
||||
{
|
||||
SetSizes(vector_sizes);
|
||||
}
|
||||
|
||||
MultiVector::MultiVector(const Array<int> &vector_sizes, MemoryType mt)
|
||||
{
|
||||
SetSizes(vector_sizes, mt);
|
||||
}
|
||||
|
||||
MultiVector::MultiVector(Vector &base, const Array<int> &vector_sizes)
|
||||
{
|
||||
MakeRef(base, vector_sizes);
|
||||
}
|
||||
|
||||
void MultiVector::SetSizes(const Array<int> &vector_sizes)
|
||||
{
|
||||
blocks.resize(vector_sizes.Size());
|
||||
for (int i = 0; i < vector_sizes.Size(); i++)
|
||||
{
|
||||
operator[](i).SetSize(vector_sizes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiVector::SetSizes(const Array<int> &vector_sizes, MemoryType mt)
|
||||
{
|
||||
blocks.resize(vector_sizes.Size());
|
||||
for (int i = 0; i < vector_sizes.Size(); i++)
|
||||
{
|
||||
operator[](i).SetSize(vector_sizes[i], mt);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiVector::MakeRef(Vector &base, const Array<int> &vector_sizes)
|
||||
{
|
||||
blocks.resize(vector_sizes.Size());
|
||||
for (int offset = 0, i = 0; i < vector_sizes.Size(); i++)
|
||||
{
|
||||
blocks[i].emplace<0>(base, offset, vector_sizes[i]);
|
||||
offset += vector_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,251 @@
|
||||
// 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_MULTIVECTOR_HPP
|
||||
#define MFEM_MULTIVECTOR_HPP
|
||||
|
||||
#include "../general/array.hpp"
|
||||
#include "vector.hpp"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <variant>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Class representing an array of Vectors with generally different sizes.
|
||||
/** This class is similar to BlockVector with the following two main
|
||||
differences:
|
||||
- the data for the individual Vector blocks does not need to be part of one
|
||||
big contiguous memory allocation;
|
||||
- this class does not inherit from class Vector (as a consequence of the
|
||||
first bullet).
|
||||
|
||||
Internally, each Vector block is represented as one of the following
|
||||
three options:
|
||||
- (default) a Vector object constructed and owned by this class; this
|
||||
object, in turn, as any Vector object, can own its Memory allocation or
|
||||
refer to a sub-Memory of another Memory object; or
|
||||
- a pointer to an externally allocated Vector or classes derived from
|
||||
Vector.
|
||||
- a pointer to an externally allocated const Vector or classes derived from
|
||||
Vector. This option is helpful for wrapping const Vector objects as a
|
||||
MultiVector that will be then used as a const MultiVector. */
|
||||
class MultiVector
|
||||
{
|
||||
private:
|
||||
std::vector<std::variant<Vector,Vector*,const Vector*>> blocks;
|
||||
|
||||
public:
|
||||
/// Create an empty MultiVector with zero blocks.
|
||||
MultiVector() = default;
|
||||
|
||||
/** @brief Create a MultiVector with @a num_blocks blocks. The individual
|
||||
Vector blocks are default initialized, i.e. they all have size zero. */
|
||||
MultiVector(int num_blocks)
|
||||
: blocks(num_blocks) { }
|
||||
|
||||
/** @brief Construct a MultiVector with number of blocks and individual block
|
||||
Vector sizes given by @a vector_sizes.
|
||||
|
||||
@note The memory of the individual Vector blocks is NOT initialized. */
|
||||
MultiVector(const Array<int> &vector_sizes);
|
||||
|
||||
/** @brief Construct a MultiVector with number of blocks and individual block
|
||||
Vector sizes given by @a vector_sizes. All Vector blocks use the
|
||||
MemoryType @a mt.
|
||||
|
||||
@note The memory of the individual Vector blocks is NOT initialized. */
|
||||
MultiVector(const Array<int> &vector_sizes, MemoryType mt);
|
||||
|
||||
/** @brief Construct a MultiVector referencing data within a given monolithic
|
||||
Vector @a base.
|
||||
|
||||
With this constructor, the Memory flags of @a base and of the individual
|
||||
Vector blocks may need to be explicitly synchronized when data is moved
|
||||
between host and device. */
|
||||
MultiVector(Vector &base, const Array<int> &vector_sizes);
|
||||
|
||||
/** @brief Construct a MultiVector referencing multiple Vectors given as
|
||||
arguments.
|
||||
|
||||
The VectorTypes reference arguments are expected to be static_cast-able
|
||||
to (Vector &) which is the case if the types are derived from Vector,
|
||||
e.g. HypreParVector, GridFunction, etc.
|
||||
|
||||
With this constructor, operations on individual Vector blocks are
|
||||
performed directly on the objects @a vs. In particular, there is no need
|
||||
to synchronize the Memory flags of @a vs and the ones of the individual
|
||||
Vector blocks when data is moved between host and device. */
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<VectorTypes&,Vector&>...>, bool> = true>
|
||||
MultiVector(VectorTypes &...vs) { MakeRef(vs...); }
|
||||
|
||||
/** @brief Construct a MultiVector referencing multiple const Vectors given
|
||||
as arguments. Individual blocks are read-only; non-const operator[]
|
||||
will generate an error. */
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<const VectorTypes&,const Vector&>...>,
|
||||
bool> = true>
|
||||
MultiVector(const VectorTypes &...vs) { MakeRef(vs...); }
|
||||
|
||||
/// Return the number of Vectors in the MultiVector.
|
||||
int NumBlocks() const { return blocks.size(); }
|
||||
|
||||
/** @brief Set the number of Vectors in the MultiVector. Existing Vector
|
||||
blocks will remain unmodified. New Vector blocks will be default
|
||||
initialized, i.e. they all have size zero. */
|
||||
void SetNumBlocks(int num_blocks) { blocks.resize(num_blocks); }
|
||||
|
||||
/** @brief Read-write access to the i-th Vector. Generates an error if the
|
||||
i-th block is read-only, i.e. it is a pointer to a const Vector. */
|
||||
inline Vector &operator[](int i);
|
||||
|
||||
/// Read-only access to the i-th Vector.
|
||||
inline const Vector &operator[](int i) const;
|
||||
|
||||
/** @brief Update the MultiVector according to the given @a vector_sizes.
|
||||
|
||||
This method can be used to add or remove blocks. The individual Vector
|
||||
sizes are updated using the method Vector::SetSize(int). */
|
||||
void SetSizes(const Array<int> &vector_sizes);
|
||||
|
||||
/** @brief Update the MultiVector according to the given @a vector_sizes and
|
||||
MemoryType @a mt.
|
||||
|
||||
This method can be used to add or remove blocks. The individual Vector
|
||||
sizes and MemoryType are updated using the method
|
||||
Vector::SetSize(int, MemoryType). */
|
||||
void SetSizes(const Array<int> &vector_sizes, MemoryType mt);
|
||||
|
||||
/** @brief Update the MultiVector to reference data within a given monolithic
|
||||
Vector @a base.
|
||||
|
||||
After calling this method, the Memory flags of @a base and of the
|
||||
individual Vector blocks may need to be explicitly synchronized when data
|
||||
is moved between host and device.*/
|
||||
void MakeRef(Vector &base, const Array<int> &vector_sizes);
|
||||
|
||||
/** @brief Update the @a i-th MultiVector block to reference data within the
|
||||
given monolithic Vector @a base at the given @a offset and with the given
|
||||
@a size.
|
||||
|
||||
After calling this method, the Memory flags of @a base and of the @a i-th
|
||||
Vector block may need to be explicitly synchronized when data is moved
|
||||
between host and device.*/
|
||||
inline void MakeRef(int i, Vector &base, int offset, int size)
|
||||
{
|
||||
blocks[i].emplace<0>(base, offset, size);
|
||||
}
|
||||
|
||||
/** @brief Update the MultiVector to reference multiple Vectors given as
|
||||
arguments.
|
||||
|
||||
The VectorTypes reference arguments are expected to be static_cast-able
|
||||
to (Vector &) which is the case if the types are derived from Vector,
|
||||
e.g. HypreParVector, GridFunction, etc.
|
||||
|
||||
After calling this method, operations on individual Vector blocks are
|
||||
performed directly on the objects @a vs. In particular, there is no need
|
||||
to synchronize the Memory flags of @a vs and the ones of the individual
|
||||
Vector blocks when data is moved between host and device. */
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<VectorTypes&,Vector&>...>, bool> = true>
|
||||
inline void MakeRef(VectorTypes &...vs);
|
||||
|
||||
/** @brief Update the MultiVector to reference multiple const Vectors given
|
||||
as arguments. Individual blocks are read-only; non-const operator[]
|
||||
will generate an error. */
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<const VectorTypes&,const Vector&>...>,
|
||||
bool> = true>
|
||||
inline void MakeRef(const VectorTypes &...vs);
|
||||
|
||||
/** @brief Update the @a i-th MultiVector block to reference the given
|
||||
Vector @a v.
|
||||
|
||||
After calling this method, operations on the @a i-th Vector block are
|
||||
performed directly on the Vector @a v. In particular, there is no need
|
||||
to synchronize the Memory flags of @a v and the ones of the @a i-th
|
||||
Vector blocks when data is moved between host and device. */
|
||||
inline void MakeRef(int i, Vector &v) { blocks[i] = &v; }
|
||||
|
||||
/** @brief Update the @a i-th MultiVector block to reference the given
|
||||
const Vector @a v. The block becomes read-only. */
|
||||
inline void MakeRef(int i, const Vector &v) { blocks[i] = &v; }
|
||||
};
|
||||
|
||||
// Inline and template methods
|
||||
|
||||
inline Vector &MultiVector::operator[](int i)
|
||||
{
|
||||
auto &bi = blocks[i];
|
||||
const auto idx = bi.index();
|
||||
if (idx == 0) { return std::get<0>(bi); }
|
||||
if (idx == 1) { return *std::get<1>(bi); }
|
||||
MFEM_ABORT("Non-const access to a const Vector block!");
|
||||
}
|
||||
|
||||
inline const Vector &MultiVector::operator[](int i) const
|
||||
{
|
||||
auto &bi = blocks[i];
|
||||
const auto idx = bi.index();
|
||||
return (idx == 0) ? std::get<0>(bi) :
|
||||
(idx == 1) ? *std::get<1>(bi) :
|
||||
/**/ *std::get<2>(bi);
|
||||
}
|
||||
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<VectorTypes&,Vector&>...>, bool>>
|
||||
inline void MultiVector::MakeRef(VectorTypes &...vs)
|
||||
{
|
||||
blocks.resize(sizeof...(vs));
|
||||
if constexpr (sizeof...(vs) > 0)
|
||||
{
|
||||
const std::array vs_p{&static_cast<Vector&>(vs)...};
|
||||
for (std::size_t i = 0; i < sizeof...(vs); i++)
|
||||
{
|
||||
blocks[i] = vs_p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... VectorTypes,
|
||||
std::enable_if_t<
|
||||
std::conjunction_v<
|
||||
std::is_convertible<const VectorTypes&,const Vector&>...>,
|
||||
bool>>
|
||||
inline void MultiVector::MakeRef(const VectorTypes &...vs)
|
||||
{
|
||||
blocks.resize(sizeof...(vs));
|
||||
if constexpr (sizeof...(vs) > 0)
|
||||
{
|
||||
const std::array vs_p{&static_cast<const Vector&>(vs)...};
|
||||
for (std::size_t i = 0; i < sizeof...(vs); i++)
|
||||
{
|
||||
blocks[i] = vs_p[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_MULTIVECTOR_HPP
|
||||
@@ -111,6 +111,21 @@ void Operator::ArrayAddMultTranspose(const Array<const Vector *> &X,
|
||||
}
|
||||
}
|
||||
|
||||
void Operator::MultMV(const MultiVector &, MultiVector &) const
|
||||
{
|
||||
MFEM_ABORT("this method is not overridden for this class!");
|
||||
}
|
||||
|
||||
void Operator::MultTransposeMV(const MultiVector &x, MultiVector &y) const
|
||||
{
|
||||
MFEM_ABORT("this method is not overridden for this class!");
|
||||
}
|
||||
|
||||
Operator &Operator::GetGradientMV(const MultiVector &) const
|
||||
{
|
||||
MFEM_ABORT("this method is not overridden for this class!");
|
||||
}
|
||||
|
||||
void Operator::FormLinearSystem(const Array<int> &ess_tdof_list,
|
||||
Vector &x, Vector &b,
|
||||
Operator* &Aout, Vector &X, Vector &B,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define MFEM_OPERATOR
|
||||
|
||||
#include "vector.hpp"
|
||||
#include "multivector.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -129,6 +130,20 @@ public:
|
||||
virtual void ArrayAddMultTranspose(const Array<const Vector *> &X,
|
||||
Array<Vector *> &Y, const real_t a = 1.0) const;
|
||||
|
||||
/** @brief Operator application, y = A(x), where the input @a x and the
|
||||
output @a y are MultiVector objects, i.e. they generally use
|
||||
non-contiguous memory representation.
|
||||
|
||||
The base class implementation for the method is to generate an error. */
|
||||
virtual void MultMV(const MultiVector &x, MultiVector &y) const;
|
||||
|
||||
/** @brief Action of the transpose operator, y = A^t(x), where the input @a x
|
||||
and the output @a y are MultiVector objects, i.e. they generally use
|
||||
non-contiguous memory representation.
|
||||
|
||||
The base class implementation for this method is to generate an error. */
|
||||
virtual void MultTransposeMV(const MultiVector &x, MultiVector &y) const;
|
||||
|
||||
/** @brief Evaluate the gradient operator at the point @a x. The default
|
||||
behavior in class Operator is to generate an error. */
|
||||
virtual Operator &GetGradient(const Vector &x) const
|
||||
@@ -137,6 +152,13 @@ public:
|
||||
return const_cast<Operator &>(*this);
|
||||
}
|
||||
|
||||
/** @brief Evaluate the gradient operator at the point @a x. The input @a x
|
||||
is provided as a MultiVector, i.e. it generally uses non-contiguous
|
||||
memory representation.
|
||||
|
||||
The base class implementation for the method is to generate an error. */
|
||||
virtual Operator &GetGradientMV(const MultiVector &x) const;
|
||||
|
||||
/** @brief Computes the diagonal entries into @a diag. Typically, this
|
||||
operation only makes sense for linear Operator%s. In some cases, only an
|
||||
approximation of the diagonal is computed. */
|
||||
|
||||
+15
-7
@@ -2624,7 +2624,8 @@ void ParNCMesh::RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
for (int i = 0; i < rank_neighbors.Size(); i++)
|
||||
{
|
||||
int elem = rank_neighbors[i];
|
||||
msg.AddElementRank(elem, new_ranks[elements[elem].index]);
|
||||
const Element &el = elements[elem];
|
||||
msg.AddElement(elem, new_ranks[el.index], el.attribute);
|
||||
}
|
||||
|
||||
msg.Isend(rank, MyComm);
|
||||
@@ -2647,7 +2648,9 @@ void ParNCMesh::RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
{
|
||||
int ghost_index = elements[msg.elements[i]].index;
|
||||
MFEM_ASSERT(element_type[ghost_index] == 2, "");
|
||||
new_ranks[ghost_index] = msg.values[i];
|
||||
const ElementRankAndAttribute &value = msg.values[i];
|
||||
new_ranks[ghost_index] = value.rank;
|
||||
elements[msg.elements[i]].attribute = value.attribute;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2718,7 +2721,7 @@ void ParNCMesh::RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
|
||||
if ((element_type[el.index] & 1) || el.rank != rank)
|
||||
{
|
||||
msg.AddElementRank(elem, el.rank);
|
||||
msg.AddElement(elem, el.rank, el.attribute);
|
||||
}
|
||||
// NOTE: we skip 'ghosts' that are of the receiver's rank because
|
||||
// they are not really ghosts and would get sent multiple times,
|
||||
@@ -2770,10 +2773,12 @@ void ParNCMesh::RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
|
||||
for (int i = 0; i < msg.Size(); i++)
|
||||
{
|
||||
int elem_rank = msg.values[i];
|
||||
elements[msg.elements[i]].rank = elem_rank;
|
||||
const ElementRankAndAttribute &value = msg.values[i];
|
||||
Element &el = elements[msg.elements[i]];
|
||||
el.rank = value.rank;
|
||||
el.attribute = value.attribute;
|
||||
|
||||
if (elem_rank == MyRank) { received_elements++; }
|
||||
if (value.rank == MyRank) { received_elements++; }
|
||||
}
|
||||
|
||||
// save the ranks we received from, for later use in RecvRebalanceDofs
|
||||
@@ -2809,7 +2814,10 @@ void ParNCMesh::RedistributeElements(Array<int> &new_ranks, int target_elements,
|
||||
|
||||
for (int i = 0; i < msg.Size(); i++)
|
||||
{
|
||||
elements[msg.elements[i]].rank = msg.values[i];
|
||||
const ElementRankAndAttribute &value = msg.values[i];
|
||||
Element &el = elements[msg.elements[i]];
|
||||
el.rank = value.rank;
|
||||
el.attribute = value.attribute;
|
||||
}
|
||||
|
||||
// save the ranks we received from, for later use in RecvRebalanceDofs
|
||||
|
||||
+17
-7
@@ -531,26 +531,36 @@ protected: // implementation
|
||||
typedef std::map<int, NeighborDerefinementMessage> Map;
|
||||
};
|
||||
|
||||
/** Used in Step 2 of Rebalance() to synchronize new rank assignments in
|
||||
* the ghost layer.
|
||||
struct ElementRankAndAttribute
|
||||
{
|
||||
int rank;
|
||||
int attribute;
|
||||
};
|
||||
|
||||
/** Used in RedistributeElements() to synchronize new rank assignments and
|
||||
* element attributes in the ghost layer.
|
||||
*/
|
||||
class NeighborElementRankMessage : public ElementValueMessage<int, false,
|
||||
class NeighborElementRankMessage :
|
||||
public ElementValueMessage<ElementRankAndAttribute, false,
|
||||
VarMessageTag::NEIGHBOR_ELEMENT_RANK_VM>
|
||||
{
|
||||
public:
|
||||
void AddElementRank(int elem, int rank) { Add(elem, rank); }
|
||||
void AddElement(int elem, int rank, int attribute)
|
||||
{ Add(elem, {rank, attribute}); }
|
||||
typedef std::map<int, NeighborElementRankMessage> Map;
|
||||
};
|
||||
|
||||
/** Used by Rebalance() to send elements and their ranks. Note that
|
||||
/** Used by Rebalance() to send elements, ranks, and attributes. Note that
|
||||
* RefTypes == true which means the refinement hierarchy will be recreated
|
||||
* on the receiving side.
|
||||
*/
|
||||
class RebalanceMessage : public ElementValueMessage<int, true,
|
||||
class RebalanceMessage :
|
||||
public ElementValueMessage<ElementRankAndAttribute, true,
|
||||
VarMessageTag::REBALANCE_VM>
|
||||
{
|
||||
public:
|
||||
void AddElementRank(int elem, int rank) { Add(elem, rank); }
|
||||
void AddElement(int elem, int rank, int attribute)
|
||||
{ Add(elem, {rank, attribute}); }
|
||||
typedef std::map<int, RebalanceMessage> Map;
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ endif
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
# Keeping the *.o files fixes an issue with the MacOS version of 'make'.
|
||||
.PRECIOUS: %.o
|
||||
|
||||
# Remove built-in rules
|
||||
%: %.cpp
|
||||
|
||||
@@ -68,7 +68,7 @@ multidomain-test-par: multidomain
|
||||
multidomain_nd-test-par: multidomain_nd
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Multidomain ND miniapp,-tf 0.001)
|
||||
multidomain_rt-test-par: multidomain_rt
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Multidomain RT iniapp,-tf 0.001)
|
||||
@$(call mfem-test,$<, $(RUN_MPI), Multidomain RT miniapp,-tf 0.001)
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
|
||||
@@ -761,7 +761,7 @@ int main(int argc, char *argv[])
|
||||
if (visualize)
|
||||
{
|
||||
hcurlhdiv_dofTrueDof.Distribute(X, x);
|
||||
MultiVector tmp(x.GetData(), 1, x.Size());
|
||||
parelag::MultiVector tmp(x.GetData(), 1, x.Size());
|
||||
sequence[0]->show(jform, tmp);
|
||||
}
|
||||
post_timer.Stop();
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
add_mfem_miniapp(g_eqdsk_viewer
|
||||
MAIN g_eqdsk_viewer.cpp
|
||||
EXTRA_SOURCES g_eqdsk_data.cpp
|
||||
EXTRA_HEADERS g_eqdsk_data.hpp plasma.hpp ${MFEM_MINIAPPS_COMMON_HEADERS}
|
||||
LIBRARIES mfem mfem-common)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
list(APPEND PLASMA_COMMON_SOURCES)
|
||||
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
SGRRATEI 01/01/2025 #1 0ms 3 20 40
|
||||
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
|
||||
1.104715063E+00 5.225686728E-06-9.087992965E+00 0.000000000E+00 1.000000000E+00
|
||||
3.335115355E+05-9.087992965E+00 0.000000000E+00 1.104715063E+00 0.000000000E+00
|
||||
5.225686728E-06 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
|
||||
9.784708692E-01 9.806991943E-01 9.828024193E-01 9.847813458E-01 9.866367217E-01
|
||||
9.883692428E-01 9.899795542E-01 9.914682512E-01 9.928358810E-01 9.940829432E-01
|
||||
9.952098911E-01 9.962171323E-01 9.971050296E-01 9.978739015E-01 9.985240230E-01
|
||||
9.990556259E-01 9.994688994E-01 9.997639901E-01 9.999410027E-01 1.000000000E+00
|
||||
4.707754379E+04 4.225242157E+04 3.768811677E+04 3.338462939E+04 2.934195942E+04
|
||||
2.556010688E+04 2.203907174E+04 1.877885403E+04 1.577945373E+04 1.304087085E+04
|
||||
1.056310539E+04 8.346157347E+03 6.390026719E+03 4.694713508E+03 3.260217714E+03
|
||||
2.086539337E+03 1.173678377E+03 5.216348342E+02 1.304087085E+02 0.000000000E+00
|
||||
-4.353196346E-02-4.114710095E-02-3.877798694E-02-3.642358799E-02-3.408289990E-02
|
||||
-3.175494531E-02-2.943877149E-02-2.713344826E-02-2.483806598E-02-2.255173364E-02
|
||||
-2.027357702E-02-1.800273697E-02-1.573836773E-02-1.347963528E-02-1.122571577E-02
|
||||
-8.975794007E-03-6.729061934E-03-4.484717187E-03-2.241961644E-03-0.000000000E+00
|
||||
9.415508757E+04 8.919955665E+04 8.424402572E+04 7.928849480E+04 7.433296387E+04
|
||||
6.937743295E+04 6.442190202E+04 5.946637110E+04 5.451084017E+04 4.955530925E+04
|
||||
4.459977832E+04 3.964424740E+04 3.468871647E+04 2.973318555E+04 2.477765462E+04
|
||||
1.982212370E+04 1.486659277E+04 9.911061850E+03 4.955530925E+03 0.000000000E+00
|
||||
-3.910241380E-01-3.370349374E-01-3.032206099E-01-2.833941950E-01-2.709124845E-01
|
||||
-2.589045274E-01-2.408148723E-01-2.113596788E-01-1.679192587E-01-1.122605207E-01
|
||||
-5.229150156E-02-3.313845027E-03 1.199143413E-02-3.426047302E-02-1.700331905E-01
|
||||
-4.150011731E-01-7.696358166E-01-1.203902834E+00-1.649387010E+00-1.999925152E+00
|
||||
-1.925695622E-01-1.748346049E-01-1.691266514E-01-1.701675452E-01-1.715397928E-01
|
||||
-1.659119623E-01-1.456077592E-01-1.036478534E-01-3.533092381E-02 5.970389126E-02
|
||||
1.751878198E-01 2.962216198E-01 3.983584318E-01 4.487753542E-01 4.105383363E-01
|
||||
2.505857725E-01-4.884633508E-02-4.770899859E-01-9.837399355E-01-1.474339619E+00
|
||||
2.166315348E-02-1.102851387E-03-2.831065458E-02-5.546599960E-02-7.618766318E-02
|
||||
-8.237925771E-02-6.477862541E-02-1.405299099E-02 7.743811746E-02 2.132045638E-01
|
||||
3.897048312E-01 5.934227400E-01 7.987616348E-01 9.678852363E-01 1.053770529E+00
|
||||
1.007512540E+00 7.901446298E-01 3.878102911E-01-1.728443713E-01-8.142430666E-01
|
||||
2.411392375E-01 1.747358186E-01 1.103546220E-01 5.181206754E-02 5.588785514E-03
|
||||
-1.923578803E-02-1.146084602E-02 4.113304468E-02 1.498681805E-01 3.223534496E-01
|
||||
5.588811278E-01 8.484640691E-01 1.165346084E+00 1.467240961E+00 1.696851978E+00
|
||||
1.788184124E+00 1.678546763E+00 1.325771819E+00 7.280476985E-01-5.875813012E-02
|
||||
4.562990380E-01 3.439881454E-01 2.385637023E-01 1.432261283E-01 6.461505077E-02
|
||||
1.290331417E-02 1.448926330E-03 4.574285831E-02 1.613919171E-01 3.609574823E-01
|
||||
6.496681822E-01 1.020362387E+00 1.448488467E+00 1.888534307E+00 2.273730093E+00
|
||||
2.521039729E+00 2.543035410E+00 2.266964141E+00 1.659051976E+00 7.490835809E-01
|
||||
6.589958226E-01 4.991505383E-01 3.490864277E-01 2.113878302E-01 9.282362412E-02
|
||||
4.651701261E-03-3.753931076E-02-1.476326317E-02 9.331703089E-02 3.049501109E-01
|
||||
6.313711445E-01 1.070656937E+00 1.601160717E+00 2.175992078E+00 2.720663983E+00
|
||||
3.136428575E+00 3.311623934E+00 3.142190847E+00 2.560153749E+00 1.565395650E+00
|
||||
8.427963399E-01 6.342571609E-01 4.361842129E-01 2.504754676E-01 8.390705039E-02
|
||||
-5.130487543E-02-1.374118370E-01-1.518716892E-01-6.933566292E-02 1.347294416E-01
|
||||
4.785698497E-01 9.669780041E-01 1.583175086E+00 2.281269353E+00 2.981657583E+00
|
||||
3.572374734E+00 3.919441608E+00 3.888257701E+00 3.375670467E+00 2.348486607E+00
|
||||
1.003140271E+00 7.451051663E-01 4.959126068E-01 2.566355010E-01 3.385060138E-02
|
||||
-1.595013481E-01-3.037145085E-01-3.727832712E-01-3.362296400E-01-1.627893604E-01
|
||||
1.736969869E-01 6.862115526E-01 1.364964594E+00 2.167824224E+00 3.013335205E+00
|
||||
3.779769521E+00 4.313957864E+00 4.452847541E+00 4.058327204E+00 3.061671981E+00
|
||||
1.137365128E+00 8.293536487E-01 5.262966190E-01 2.282463102E-01-5.869372598E-02
|
||||
-3.211771932E-01-5.378523046E-01-6.794765186E-01-7.104791334E-01-5.925787521E-01
|
||||
-2.909412188E-01 2.169977855E-01 9.305878226E-01 1.814416755E+00 2.788864587E+00
|
||||
3.726574504E+00 4.459237386E+00 4.798518474E+00 4.572628903E+00 3.675635708E+00
|
||||
1.244611695E+00 8.865011676E-01 5.273739090E-01 1.660289873E-01-1.922188349E-01
|
||||
-5.339924512E-01-8.366835819E-01-1.068145986E+00-1.187890541E+00-1.150497326E+00
|
||||
-9.118739899E-01-4.386474144E-01 2.797067814E-01 1.217442845E+00 2.300606858E+00
|
||||
3.400695883E+00 4.338887158E+00 4.905511692E+00 4.897269966E+00 4.170164958E+00
|
||||
1.325631269E+00 9.177537088E-01 5.011092625E-01 7.300028320E-02-3.623736298E-01
|
||||
-7.920000920E-01-1.192445606E+00-1.529067475E+00-1.756748529E+00-1.822973413E+00
|
||||
-1.674020591E+00-1.264731297E+00-5.716334778E-01 3.919046896E-01 1.561272647E+00
|
||||
2.811295637E+00 3.957459998E+00 4.773149919E+00 5.026398786E+00 4.535133275E+00
|
||||
1.382519568E+00 9.258003322E-01 4.511913373E-01-4.572686077E-02-5.621735094E-01
|
||||
-1.085880267E+00-1.593023216E+00-2.046909304E+00-2.398174860E+00-2.587412144E+00
|
||||
-2.551140860E+00-2.231766925E+00-1.591501157E+00-6.290735117E-01 6.034811432E-01
|
||||
1.988428128E+00 3.340201296E+00 4.419719356E+00 4.969646189E+00 4.770667398E+00
|
||||
1.418403250E+00 9.145173783E-01 3.827290445E-01-1.832800729E-01-7.823963566E-01
|
||||
-1.403422928E+00-2.022546791E+00-2.601474899E+00-3.087043844E+00-3.413308233E+00
|
||||
-3.507162143E+00-3.298318507E+00-2.733827400E+00-1.796161496E+00-5.222552154E-01
|
||||
9.810231774E-01 2.531156764E+00 3.880848348E+00 4.750925106E+00 4.886498468E+00
|
||||
1.437103919E+00 8.886239873E-01 3.018699076E-01-3.314779846E-01-1.012137361E+00
|
||||
-1.730227221E+00-2.462280919E+00-3.168828947E+00-3.793395216E+00-4.263991651E+00
|
||||
-4.498294398E+00-4.413504634E+00-3.941288135E+00-3.047034463E+00-1.750973347E+00
|
||||
-1.466326055E-01 1.589788832E+00 3.206515141E+00 4.406106379E+00 4.900563280E+00
|
||||
1.442801674E+00 8.533119757E-01 2.153661342E-01-4.813638998E-01-1.239485158E+00
|
||||
-2.050570243E+00-2.891743239E+00-3.722729788E+00-4.484246464E+00-5.098883769E+00
|
||||
-5.475783196E+00-5.520279043E+00-5.149107296E+00-4.310641572E+00-3.007869332E+00
|
||||
-1.319645546E+00 5.863673938E-01 2.456925688E+00 3.979764627E+00 4.836980711E+00
|
||||
1.439716341E+00 8.138721012E-01 1.301159276E-01-6.237874768E-01-1.452273520E+00
|
||||
-2.348385346E+00-3.289975383E+00-4.236266930E+00-5.125675247E+00-5.876101086E+00
|
||||
-6.389099647E+00-6.559246706E+00-6.289497376E+00-5.512208788E+00-4.213722607E+00
|
||||
-2.458127258E+00-4.035022091E-01 1.697591881E+00 3.521261516E+00 4.723577581E+00
|
||||
1.431820151E+00 7.753367344E-01 5.270779132E-02-7.499966727E-01-1.638857755E+00
|
||||
-2.608282055E+00-3.636876158E+00-4.683586303E+00-5.685020856E+00-6.555215726E+00
|
||||
-7.189331085E+00-7.472729897E+00-7.296402003E+00-6.578594532E+00-5.290716634E+00
|
||||
-3.483232525E+00-1.304782694E+00 9.940036866E-01 3.080485788E+00 4.589173208E+00
|
||||
1.422591282E+00 7.421562942E-01-1.100563552E-02-8.522020247E-01-1.788863321E+00
|
||||
-2.816536419E+00-3.914501953E+00-5.041578424E+00-6.133043547E+00-7.099968471E+00
|
||||
-7.832519316E+00-8.208777881E+00-8.110180067E+00-7.443587519E+00-6.168205808E+00
|
||||
-4.323151304E+00-2.048874175E+00 4.063205511E-01 2.703595819E+00 4.460849974E+00
|
||||
1.414813950E+00 7.179237979E-01-5.628015260E-02-9.240774770E-01-1.893856117E+00
|
||||
-2.961982431E+00-4.108241194E+00-5.291406587E+00-6.445882623E+00-7.480732414E+00
|
||||
-8.282695715E+00-8.724816600E+00-8.681873871E+00-8.052739203E+00-6.787981369E+00
|
||||
-4.918586303E+00-2.578986186E+00-1.549450246E-02 2.429109334E+00 4.361436888E+00
|
||||
1.410427849E+00 7.051587764E-01-7.977847127E-02-9.611662324E-01-1.947889219E+00
|
||||
-3.036741970E+00-4.207778410E+00-5.419763372E+00-6.606668398E+00-7.676543111E+00
|
||||
-8.514384415E+00-8.990661063E+00-8.976734576E+00-8.367358201E+00-7.108627276E+00
|
||||
-5.227287344E+00-2.854588356E+00-2.357101966E-01 2.284656177E+00 4.307414559E+00
|
||||
1.410427849E+00 7.051587764E-01-7.977847127E-02-9.611662324E-01-1.947889219E+00
|
||||
-3.036741970E+00-4.207778410E+00-5.419763372E+00-6.606668398E+00-7.676543111E+00
|
||||
-8.514384415E+00-8.990661063E+00-8.976734576E+00-8.367358201E+00-7.108627276E+00
|
||||
-5.227287344E+00-2.854588356E+00-2.357101966E-01 2.284656177E+00 4.307414559E+00
|
||||
1.414813950E+00 7.179237979E-01-5.628015260E-02-9.240774770E-01-1.893856117E+00
|
||||
-2.961982431E+00-4.108241194E+00-5.291406587E+00-6.445882623E+00-7.480732414E+00
|
||||
-8.282695715E+00-8.724816600E+00-8.681873871E+00-8.052739203E+00-6.787981369E+00
|
||||
-4.918586303E+00-2.578986186E+00-1.549450246E-02 2.429109334E+00 4.361436888E+00
|
||||
1.422591282E+00 7.421562942E-01-1.100563552E-02-8.522020247E-01-1.788863321E+00
|
||||
-2.816536419E+00-3.914501953E+00-5.041578424E+00-6.133043547E+00-7.099968471E+00
|
||||
-7.832519316E+00-8.208777881E+00-8.110180067E+00-7.443587519E+00-6.168205808E+00
|
||||
-4.323151304E+00-2.048874175E+00 4.063205511E-01 2.703595819E+00 4.460849974E+00
|
||||
1.431820151E+00 7.753367344E-01 5.270779132E-02-7.499966727E-01-1.638857755E+00
|
||||
-2.608282055E+00-3.636876158E+00-4.683586303E+00-5.685020856E+00-6.555215726E+00
|
||||
-7.189331085E+00-7.472729897E+00-7.296402003E+00-6.578594532E+00-5.290716634E+00
|
||||
-3.483232525E+00-1.304782694E+00 9.940036866E-01 3.080485788E+00 4.589173208E+00
|
||||
1.439716341E+00 8.138721012E-01 1.301159276E-01-6.237874768E-01-1.452273520E+00
|
||||
-2.348385346E+00-3.289975383E+00-4.236266930E+00-5.125675247E+00-5.876101086E+00
|
||||
-6.389099647E+00-6.559246706E+00-6.289497376E+00-5.512208788E+00-4.213722607E+00
|
||||
-2.458127258E+00-4.035022091E-01 1.697591881E+00 3.521261516E+00 4.723577581E+00
|
||||
1.442801674E+00 8.533119757E-01 2.153661342E-01-4.813638998E-01-1.239485158E+00
|
||||
-2.050570243E+00-2.891743239E+00-3.722729788E+00-4.484246464E+00-5.098883769E+00
|
||||
-5.475783196E+00-5.520279043E+00-5.149107296E+00-4.310641572E+00-3.007869332E+00
|
||||
-1.319645546E+00 5.863673938E-01 2.456925688E+00 3.979764627E+00 4.836980711E+00
|
||||
1.437103919E+00 8.886239873E-01 3.018699076E-01-3.314779846E-01-1.012137361E+00
|
||||
-1.730227221E+00-2.462280919E+00-3.168828947E+00-3.793395216E+00-4.263991651E+00
|
||||
-4.498294398E+00-4.413504634E+00-3.941288135E+00-3.047034463E+00-1.750973347E+00
|
||||
-1.466326055E-01 1.589788832E+00 3.206515141E+00 4.406106379E+00 4.900563280E+00
|
||||
1.418403250E+00 9.145173783E-01 3.827290445E-01-1.832800729E-01-7.823963566E-01
|
||||
-1.403422928E+00-2.022546791E+00-2.601474899E+00-3.087043844E+00-3.413308233E+00
|
||||
-3.507162143E+00-3.298318507E+00-2.733827400E+00-1.796161496E+00-5.222552154E-01
|
||||
9.810231774E-01 2.531156764E+00 3.880848348E+00 4.750925106E+00 4.886498468E+00
|
||||
1.382519568E+00 9.258003322E-01 4.511913373E-01-4.572686077E-02-5.621735094E-01
|
||||
-1.085880267E+00-1.593023216E+00-2.046909304E+00-2.398174860E+00-2.587412144E+00
|
||||
-2.551140860E+00-2.231766925E+00-1.591501157E+00-6.290735117E-01 6.034811432E-01
|
||||
1.988428128E+00 3.340201296E+00 4.419719356E+00 4.969646189E+00 4.770667398E+00
|
||||
1.325631269E+00 9.177537088E-01 5.011092625E-01 7.300028320E-02-3.623736298E-01
|
||||
-7.920000920E-01-1.192445606E+00-1.529067475E+00-1.756748529E+00-1.822973413E+00
|
||||
-1.674020591E+00-1.264731297E+00-5.716334778E-01 3.919046896E-01 1.561272647E+00
|
||||
2.811295637E+00 3.957459998E+00 4.773149919E+00 5.026398786E+00 4.535133275E+00
|
||||
1.244611695E+00 8.865011676E-01 5.273739090E-01 1.660289873E-01-1.922188349E-01
|
||||
-5.339924512E-01-8.366835819E-01-1.068145986E+00-1.187890541E+00-1.150497326E+00
|
||||
-9.118739899E-01-4.386474144E-01 2.797067814E-01 1.217442845E+00 2.300606858E+00
|
||||
3.400695883E+00 4.338887158E+00 4.905511692E+00 4.897269966E+00 4.170164958E+00
|
||||
1.137365128E+00 8.293536487E-01 5.262966190E-01 2.282463102E-01-5.869372598E-02
|
||||
-3.211771932E-01-5.378523046E-01-6.794765186E-01-7.104791334E-01-5.925787521E-01
|
||||
-2.909412188E-01 2.169977855E-01 9.305878226E-01 1.814416755E+00 2.788864587E+00
|
||||
3.726574504E+00 4.459237386E+00 4.798518474E+00 4.572628903E+00 3.675635708E+00
|
||||
1.003140271E+00 7.451051663E-01 4.959126068E-01 2.566355010E-01 3.385060138E-02
|
||||
-1.595013481E-01-3.037145085E-01-3.727832712E-01-3.362296400E-01-1.627893604E-01
|
||||
1.736969869E-01 6.862115526E-01 1.364964594E+00 2.167824224E+00 3.013335205E+00
|
||||
3.779769521E+00 4.313957864E+00 4.452847541E+00 4.058327204E+00 3.061671981E+00
|
||||
8.427963399E-01 6.342571609E-01 4.361842129E-01 2.504754676E-01 8.390705039E-02
|
||||
-5.130487543E-02-1.374118370E-01-1.518716892E-01-6.933566292E-02 1.347294416E-01
|
||||
4.785698497E-01 9.669780041E-01 1.583175086E+00 2.281269353E+00 2.981657583E+00
|
||||
3.572374734E+00 3.919441608E+00 3.888257701E+00 3.375670467E+00 2.348486607E+00
|
||||
6.589958226E-01 4.991505383E-01 3.490864277E-01 2.113878302E-01 9.282362412E-02
|
||||
4.651701261E-03-3.753931076E-02-1.476326317E-02 9.331703089E-02 3.049501109E-01
|
||||
6.313711445E-01 1.070656937E+00 1.601160717E+00 2.175992078E+00 2.720663983E+00
|
||||
3.136428575E+00 3.311623934E+00 3.142190847E+00 2.560153749E+00 1.565395650E+00
|
||||
4.562990380E-01 3.439881454E-01 2.385637023E-01 1.432261283E-01 6.461505077E-02
|
||||
1.290331417E-02 1.448926330E-03 4.574285831E-02 1.613919171E-01 3.609574823E-01
|
||||
6.496681822E-01 1.020362387E+00 1.448488467E+00 1.888534307E+00 2.273730093E+00
|
||||
2.521039729E+00 2.543035410E+00 2.266964141E+00 1.659051976E+00 7.490835809E-01
|
||||
2.411392375E-01 1.747358186E-01 1.103546220E-01 5.181206754E-02 5.588785514E-03
|
||||
-1.923578803E-02-1.146084602E-02 4.113304468E-02 1.498681805E-01 3.223534496E-01
|
||||
5.588811278E-01 8.484640691E-01 1.165346084E+00 1.467240961E+00 1.696851978E+00
|
||||
1.788184124E+00 1.678546763E+00 1.325771819E+00 7.280476985E-01-5.875813012E-02
|
||||
2.166315348E-02-1.102851387E-03-2.831065458E-02-5.546599960E-02-7.618766318E-02
|
||||
-8.237925771E-02-6.477862541E-02-1.405299099E-02 7.743811746E-02 2.132045638E-01
|
||||
3.897048312E-01 5.934227400E-01 7.987616348E-01 9.678852363E-01 1.053770529E+00
|
||||
1.007512540E+00 7.901446298E-01 3.878102911E-01-1.728443713E-01-8.142430666E-01
|
||||
-1.925695622E-01-1.748346049E-01-1.691266514E-01-1.701675452E-01-1.715397928E-01
|
||||
-1.659119623E-01-1.456077592E-01-1.036478534E-01-3.533092381E-02 5.970389126E-02
|
||||
1.751878198E-01 2.962216198E-01 3.983584318E-01 4.487753542E-01 4.105383363E-01
|
||||
2.505857725E-01-4.884633508E-02-4.770899859E-01-9.837399355E-01-1.474339619E+00
|
||||
-3.910241380E-01-3.370349374E-01-3.032206099E-01-2.833941950E-01-2.709124845E-01
|
||||
-2.589045274E-01-2.408148723E-01-2.113596788E-01-1.679192587E-01-1.122605207E-01
|
||||
-5.229150156E-02-3.313845027E-03 1.199143413E-02-3.426047302E-02-1.700331905E-01
|
||||
-4.150011731E-01-7.696358166E-01-1.203902834E+00-1.649387010E+00-1.999925152E+00
|
||||
1.000000000E+00 1.050395383E+00 1.108778414E+00 1.174574361E+00 1.246881957E+00
|
||||
1.327322223E+00 1.420854260E+00 1.523601296E+00 1.644396040E+00 1.782867911E+00
|
||||
1.944699895E+00 2.137823164E+00 2.371490866E+00 2.660870810E+00 3.022189358E+00
|
||||
3.498374954E+00 4.155225142E+00 5.164243345E+00 7.000356534E+00 9.663564712E+00
|
||||
60 11
|
||||
8.000000000E-01 8.000000000E-01 7.743225129E-01 7.532775834E-01 7.502189395E-01
|
||||
7.047911204E-01 7.277457261E-01 6.546541578E-01 7.069555012E-01 6.029841077E-01
|
||||
6.878969518E-01 5.499019727E-01 6.706147099E-01 4.955320618E-01 6.551492475E-01
|
||||
4.400017001E-01 6.415367820E-01 3.834409301E-01 6.298091915E-01 3.259822075E-01
|
||||
6.199939400E-01 2.677600906E-01 6.121140130E-01 2.089109256E-01 6.061878641E-01
|
||||
1.495725272E-01 6.022293713E-01 8.988385560E-02 6.002478046E-01 2.998469153E-02
|
||||
6.002478046E-01-2.998469153E-02 6.022293713E-01-8.988385560E-02 6.061878641E-01
|
||||
-1.495725272E-01 6.121140130E-01-2.089109256E-01 6.199939400E-01-2.677600906E-01
|
||||
6.298091915E-01-3.259822075E-01 6.415367820E-01-3.834409301E-01 6.551492475E-01
|
||||
-4.400017001E-01 6.706147099E-01-4.955320618E-01 6.878969518E-01-5.499019727E-01
|
||||
7.069555012E-01-6.029841077E-01 7.277457261E-01-6.546541578E-01 7.502189395E-01
|
||||
-7.047911204E-01 7.743225129E-01-7.532775834E-01 8.000000000E-01-8.000000000E-01
|
||||
8.000000000E-01-8.000000000E-01 8.770324613E-01-7.532775834E-01 9.493431816E-01
|
||||
-7.047911204E-01 1.016762822E+00-6.546541578E-01 1.079133497E+00-6.029841077E-01
|
||||
1.136309145E+00-5.499019727E-01 1.188155870E+00-4.955320618E-01 1.234552257E+00
|
||||
-4.400017001E-01 1.275389654E+00-3.834409301E-01 1.310572426E+00-3.259822075E-01
|
||||
1.340018180E+00-2.677600906E-01 1.363657961E+00-2.089109256E-01 1.381436408E+00
|
||||
-1.495725272E-01 1.393311886E+00-8.988385560E-02 1.399256586E+00-2.998469153E-02
|
||||
1.399256586E+00 2.998469153E-02 1.393311886E+00 8.988385560E-02 1.381436408E+00
|
||||
1.495725272E-01 1.363657961E+00 2.089109256E-01 1.340018180E+00 2.677600906E-01
|
||||
1.310572426E+00 3.259822075E-01 1.275389654E+00 3.834409301E-01 1.234552257E+00
|
||||
4.400017001E-01 1.188155870E+00 4.955320618E-01 1.136309145E+00 5.499019727E-01
|
||||
1.079133497E+00 6.029841077E-01 1.016762822E+00 6.546541578E-01 9.493431816E-01
|
||||
7.047911204E-01 8.770324613E-01 7.532775834E-01 8.000000000E-01 8.000000000E-01
|
||||
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
|
||||
@@ -1,211 +0,0 @@
|
||||
SGRRATEI 01/01/2025 #1 0ms 3 20 40
|
||||
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
|
||||
1.109022415E+00-9.616366848E-06-3.831437870E+00 0.000000000E+00 1.000000000E+00
|
||||
4.810231190E+05-3.831437870E+00 0.000000000E+00 1.109022415E+00 0.000000000E+00
|
||||
-9.616366848E-06 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
|
||||
9.695197187E-01 9.726876680E-01 9.756749097E-01 9.784830989E-01 9.811137731E-01
|
||||
9.835683566E-01 9.858481646E-01 9.879544073E-01 9.898881924E-01 9.916505289E-01
|
||||
9.932423294E-01 9.946644126E-01 9.959175056E-01 9.970022456E-01 9.979191815E-01
|
||||
9.986687756E-01 9.992514045E-01 9.996673601E-01 9.999168504E-01 1.000000000E+00
|
||||
6.634939148E+04 5.954903834E+04 5.311627185E+04 4.705109202E+04 4.135349885E+04
|
||||
3.602349233E+04 3.106107247E+04 2.646623926E+04 2.223899271E+04 1.837933282E+04
|
||||
1.488725959E+04 1.176277301E+04 9.005873082E+03 6.616559816E+03 4.594833205E+03
|
||||
2.940693251E+03 1.654139954E+03 7.351733128E+02 1.837933282E+02 0.000000000E+00
|
||||
-6.191881812E-02-5.846888325E-02-5.505154200E-02-5.166451510E-02-4.830561217E-02
|
||||
-4.497272375E-02-4.166381400E-02-3.837691381E-02-3.511011443E-02-3.186156146E-02
|
||||
-2.862944924E-02-2.541201545E-02-2.220753614E-02-1.901432083E-02-1.583070797E-02
|
||||
-1.265506044E-02-9.485761281E-03-6.321209542E-03-3.159816165E-03-0.000000000E+00
|
||||
1.326987830E+05 1.257146365E+05 1.187304900E+05 1.117463436E+05 1.047621971E+05
|
||||
9.777805061E+04 9.079390414E+04 8.380975766E+04 7.682561119E+04 6.984146472E+04
|
||||
6.285731825E+04 5.587317178E+04 4.888902530E+04 4.190487883E+04 3.492073236E+04
|
||||
2.793658589E+04 2.095243942E+04 1.396829294E+04 6.984146472E+03 0.000000000E+00
|
||||
6.027880359E-01 5.444336242E-01 4.929843721E-01 4.468606903E-01 4.053015659E-01
|
||||
3.683453893E-01 3.367530737E-01 3.118362535E-01 2.951519289E-01 2.880365841E-01
|
||||
2.909818720E-01 3.029033791E-01 3.204224066E-01 3.373590566E-01 3.447032023E-01
|
||||
3.313561860E-01 2.858795818E-01 1.993086623E-01 6.876738196E-02-9.881690647E-02
|
||||
6.744595449E-01 5.996140461E-01 5.328634336E-01 4.723627302E-01 4.172570594E-01
|
||||
3.677070698E-01 3.248508780E-01 2.906574776E-01 2.676201889E-01 2.582462461E-01
|
||||
2.643256985E-01 2.860143822E-01 3.208428141E-01 3.628585676E-01 4.022050156E-01
|
||||
4.255007017E-01 4.173644838E-01 3.632813892E-01 2.536864244E-01 8.866344730E-02
|
||||
7.343619131E-01 6.436962062E-01 5.614219261E-01 4.855364655E-01 4.151880501E-01
|
||||
3.507641660E-01 2.939113975E-01 2.474323310E-01 2.149930564E-01 2.005771397E-01
|
||||
2.076460507E-01 2.380192080E-01 2.905729286E-01 3.599724996E-01 4.357778205E-01
|
||||
5.023656375E-01 5.401375751E-01 5.283698530E-01 4.497523801E-01 2.961440598E-01
|
||||
7.809349798E-01 6.751996950E-01 5.772531276E-01 4.850226141E-01 3.977360480E-01
|
||||
3.160900969E-01 2.423462144E-01 1.802896324E-01 1.349679043E-01 1.121217192E-01
|
||||
1.172407810E-01 1.542315062E-01 2.237783488E-01 3.216158548E-01 4.370886419E-01
|
||||
5.525253624E-01 6.440313440E-01 6.842364433E-01 6.472434068E-01 5.154640263E-01
|
||||
8.135690035E-01 6.934582174E-01 5.796763578E-01 4.701407046E-01 3.642092103E-01
|
||||
2.629430672E-01 1.692957439E-01 8.815231453E-02 2.611713847E-02-9.063055012E-03
|
||||
-9.538719707E-03 3.109598996E-02 1.158088422E-01 2.419024963E-01 3.989659604E-01
|
||||
5.676148854E-01 7.197683473E-01 8.211947470E-01 8.367934603E-01 7.384898454E-01
|
||||
8.325216321E-01 6.985747478E-01 5.687238375E-01 4.409043702E-01 3.146255305E-01
|
||||
1.913389993E-01 7.473585748E-02-2.911651568E-02-1.119191647E-01-1.637085739E-01
|
||||
-1.739780585E-01-1.334333429E-01-3.635127414E-02 1.166660483E-01 3.159822862E-01
|
||||
5.409560343E-01 7.596023466E-01 9.308263465E-01 1.009936725E+00 9.575352010E-01
|
||||
8.387863256E-01 6.913340506E-01 5.450887024E-01 3.979996591E-01 2.497191168E-01
|
||||
1.020859215E-01-4.045731398E-02-1.706141808E-01-2.782935795E-01-3.511479324E-01
|
||||
-3.757593010E-01-3.395926987E-01-2.337188599E-01-5.611233175E-02 1.849391381E-01
|
||||
4.680854372E-01 7.578657830E-01 1.006514653E+00 1.159586428E+00 1.165738769E+00
|
||||
8.339278564E-01 6.730837162E-01 5.100416932E-01 3.427308098E-01 1.709112396E-01
|
||||
-3.221170684E-03-1.744881056E-01-3.343523364E-01-4.708744696E-01-5.692032028E-01
|
||||
-6.128066860E-01-5.856071769E-01-4.750595001E-01-2.759990290E-01 5.221341658E-03
|
||||
3.471489908E-01 7.113877498E-01 1.043861665E+00 1.280418325E+00 1.357377573E+00
|
||||
8.199015377E-01 6.455959983E-01 4.653253241E-01 2.769394057E-01 8.024954100E-02
|
||||
-1.222439302E-01-3.246688374E-01-5.172678502E-01-6.862382215E-01-8.141557599E-01
|
||||
-8.812308347E-01-8.676042109E-01-7.567658125E-01-5.399480748E-01-2.210043304E-01
|
||||
1.791358869E-01 6.197548661E-01 1.040961106E+00 1.369135452E+00 1.528097841E+00
|
||||
7.988723691E-01 6.109227609E-01 4.130347848E-01 2.029036972E-01-1.967987208E-02
|
||||
-2.519798567E-01-4.874929551E-01-7.152912061E-01-9.197329238E-01-1.080803941E+00
|
||||
-1.175377832E+00-1.179650378E+00-1.072877456E+00-8.422994956E-01-4.887614330E-01
|
||||
-3.206461911E-02 4.853974608E-01 9.985106689E-01 1.424598500E+00 1.675050854E+00
|
||||
7.730484943E-01 5.712548386E-01 3.554945030E-01 1.232251820E-01-1.258618115E-01
|
||||
-3.888726160E-01-6.587503270E-01-9.234698604E-01-1.165611778E+00-1.362607208E+00
|
||||
-1.487983287E+00-1.513912701E+00-1.415245061E+00-1.174939292E+00-7.904115839E-01
|
||||
-2.797893042E-01 3.134946132E-01 9.197564239E-01 1.447814952E+00 1.796927636E+00
|
||||
7.445404658E-01 5.287952464E-01 2.951382949E-01 4.070929804E-02-2.349767287E-01
|
||||
-5.289477637E-01-8.336791693E-01-1.136141025E+00-1.417230568E+00-1.651910893E+00
|
||||
-1.810425157E+00-1.860937968E+00-1.773831419E+00-1.527614344E+00-1.115971166E+00
|
||||
-5.549039664E-01 1.117031538E-01 8.102732738E-01 1.441789269E+00 1.893892967E+00
|
||||
7.152541434E-01 4.856531808E-01 2.343995042E-01-4.175359515E-02-3.435345212E-01
|
||||
-6.679672634E-01-1.007147349E+00-1.347145717E+00-1.667299880E+00-1.940240855E+00
|
||||
-2.133063162E+00-2.210036310E+00-2.137134706E+00-1.888385838E+00-1.453579841E+00
|
||||
-8.462660998E-01-1.102730351E-01 6.775958354E-01 1.411245424E+00 1.967425855E+00
|
||||
6.868209862E-01 4.437629001E-01 1.756156706E-01-1.213017723E-01-4.480113960E-01
|
||||
-8.015956403E-01-1.173854475E+00-1.550073727E+00-1.908179626E+00-2.218653210E+00
|
||||
-2.445647332E+00-2.549748880E+00-2.492710924E+00-2.244196046E+00-1.790094098E+00
|
||||
-1.141319885E+00-3.412468720E-01 5.307237428E-01 1.362241297E+00 2.020079621E+00
|
||||
6.605654332E-01 4.048286553E-01 1.209502842E-01-1.952062579E-01-5.449842404E-01
|
||||
-9.255704167E-01-1.328545300E+00-1.738527527E+00-2.132201008E+00-2.478121003E+00
|
||||
-2.737773949E+00-2.868374135E+00-2.827766422E+00-2.581516128E+00-2.111771066E+00
|
||||
-1.426787661E+00-5.692100125E-01 3.795334026E-01 1.301701384E+00 2.055179962E+00
|
||||
6.375053763E-01 3.702941358E-01 7.233227099E-02-2.609627702E-01-6.312576177E-01
|
||||
-1.035869585E+00-1.466224516E+00-1.906392149E+00-2.331999433E+00-2.709937370E+00
|
||||
-2.999364174E+00-3.154523523E+00-3.129786863E+00-2.887037341E+00-2.405002017E+00
|
||||
-1.689415837E+00-7.820514975E-01 2.341342187E-01 1.236899458E+00 2.076483242E+00
|
||||
6.183787457E-01 3.413326511E-01 3.141219456E-02-3.163699380E-01-7.039792622E-01
|
||||
-1.128869268E+00-1.582363062E+00-2.048097697E+00-2.500841167E+00-2.906113655E+00
|
||||
-3.221139041E+00-3.397675320E+00-3.387166510E+00-3.148365134E+00-2.657051631E+00
|
||||
-1.916729591E+00-9.682880687E-01 1.042108382E-01 1.174925970E+00 2.087819678E+00
|
||||
6.036871942E-01 3.188526756E-01-4.670925182E-04-3.595932281E-01-7.607407379E-01
|
||||
-1.201485317E+00-1.673086529E+00-2.158861549E+00-2.632926762E+00-3.059751018E+00
|
||||
-3.395064527E+00-3.588695197E+00-3.589801388E+00-3.354675138E+00-2.856758537E+00
|
||||
-2.097750017E+00-1.117760284E+00-1.606164268E-03 1.122175768E+00 2.092746840E+00
|
||||
5.937469493E-01 3.035125582E-01-2.228838311E-02-3.892147630E-01-7.996606775E-01
|
||||
-1.251293437E+00-1.735337138E+00-2.234898256E+00-2.723655399E+00-3.165365399E+00
|
||||
-3.514741855E+00-3.720293832E+00-3.729611788E+00-3.497292139E+00-2.995154781E+00
|
||||
-2.223629545E+00-1.222250664E+00-7.630060271E-02 1.083890305E+00 2.094237915E+00
|
||||
5.887371279E-01 2.957381914E-01-3.336989801E-02-4.042696576E-01-8.194487014E-01
|
||||
-1.276623310E+00-1.767002017E+00-2.273586775E+00-2.769836332E+00-3.219148153E+00
|
||||
-3.575721206E+00-3.787395338E+00-3.800963568E+00-3.570157560E+00-3.065966683E+00
|
||||
-2.288166411E+00-1.275984954E+00-1.149259009E-01 1.063784750E+00 2.094426631E+00
|
||||
5.887371279E-01 2.957381914E-01-3.336989801E-02-4.042696576E-01-8.194487014E-01
|
||||
-1.276623310E+00-1.767002017E+00-2.273586775E+00-2.769836332E+00-3.219148153E+00
|
||||
-3.575721206E+00-3.787395338E+00-3.800963568E+00-3.570157560E+00-3.065966683E+00
|
||||
-2.288166411E+00-1.275984954E+00-1.149259009E-01 1.063784750E+00 2.094426631E+00
|
||||
5.937469493E-01 3.035125582E-01-2.228838311E-02-3.892147630E-01-7.996606775E-01
|
||||
-1.251293437E+00-1.735337138E+00-2.234898256E+00-2.723655399E+00-3.165365399E+00
|
||||
-3.514741855E+00-3.720293832E+00-3.729611788E+00-3.497292139E+00-2.995154781E+00
|
||||
-2.223629545E+00-1.222250664E+00-7.630060271E-02 1.083890305E+00 2.094237915E+00
|
||||
6.036871942E-01 3.188526756E-01-4.670925182E-04-3.595932281E-01-7.607407379E-01
|
||||
-1.201485317E+00-1.673086529E+00-2.158861549E+00-2.632926762E+00-3.059751018E+00
|
||||
-3.395064527E+00-3.588695197E+00-3.589801388E+00-3.354675138E+00-2.856758537E+00
|
||||
-2.097750017E+00-1.117760284E+00-1.606164268E-03 1.122175768E+00 2.092746840E+00
|
||||
6.183787457E-01 3.413326511E-01 3.141219456E-02-3.163699380E-01-7.039792622E-01
|
||||
-1.128869268E+00-1.582363062E+00-2.048097697E+00-2.500841167E+00-2.906113655E+00
|
||||
-3.221139041E+00-3.397675320E+00-3.387166510E+00-3.148365134E+00-2.657051631E+00
|
||||
-1.916729591E+00-9.682880687E-01 1.042108382E-01 1.174925970E+00 2.087819678E+00
|
||||
6.375053763E-01 3.702941358E-01 7.233227099E-02-2.609627702E-01-6.312576177E-01
|
||||
-1.035869585E+00-1.466224516E+00-1.906392149E+00-2.331999433E+00-2.709937370E+00
|
||||
-2.999364174E+00-3.154523523E+00-3.129786863E+00-2.887037341E+00-2.405002017E+00
|
||||
-1.689415837E+00-7.820514975E-01 2.341342187E-01 1.236899458E+00 2.076483242E+00
|
||||
6.605654332E-01 4.048286553E-01 1.209502842E-01-1.952062579E-01-5.449842404E-01
|
||||
-9.255704167E-01-1.328545300E+00-1.738527527E+00-2.132201008E+00-2.478121003E+00
|
||||
-2.737773949E+00-2.868374135E+00-2.827766422E+00-2.581516128E+00-2.111771066E+00
|
||||
-1.426787661E+00-5.692100125E-01 3.795334026E-01 1.301701384E+00 2.055179962E+00
|
||||
6.868209862E-01 4.437629001E-01 1.756156706E-01-1.213017723E-01-4.480113960E-01
|
||||
-8.015956403E-01-1.173854475E+00-1.550073727E+00-1.908179626E+00-2.218653210E+00
|
||||
-2.445647332E+00-2.549748880E+00-2.492710924E+00-2.244196046E+00-1.790094098E+00
|
||||
-1.141319885E+00-3.412468720E-01 5.307237428E-01 1.362241297E+00 2.020079621E+00
|
||||
7.152541434E-01 4.856531808E-01 2.343995042E-01-4.175359515E-02-3.435345212E-01
|
||||
-6.679672634E-01-1.007147349E+00-1.347145717E+00-1.667299880E+00-1.940240855E+00
|
||||
-2.133063162E+00-2.210036310E+00-2.137134706E+00-1.888385838E+00-1.453579841E+00
|
||||
-8.462660998E-01-1.102730351E-01 6.775958354E-01 1.411245424E+00 1.967425855E+00
|
||||
7.445404658E-01 5.287952464E-01 2.951382949E-01 4.070929804E-02-2.349767287E-01
|
||||
-5.289477637E-01-8.336791693E-01-1.136141025E+00-1.417230568E+00-1.651910893E+00
|
||||
-1.810425157E+00-1.860937968E+00-1.773831419E+00-1.527614344E+00-1.115971166E+00
|
||||
-5.549039664E-01 1.117031538E-01 8.102732738E-01 1.441789269E+00 1.893892967E+00
|
||||
7.730484943E-01 5.712548386E-01 3.554945030E-01 1.232251820E-01-1.258618115E-01
|
||||
-3.888726160E-01-6.587503270E-01-9.234698604E-01-1.165611778E+00-1.362607208E+00
|
||||
-1.487983287E+00-1.513912701E+00-1.415245061E+00-1.174939292E+00-7.904115839E-01
|
||||
-2.797893042E-01 3.134946132E-01 9.197564239E-01 1.447814952E+00 1.796927636E+00
|
||||
7.988723691E-01 6.109227609E-01 4.130347848E-01 2.029036972E-01-1.967987208E-02
|
||||
-2.519798567E-01-4.874929551E-01-7.152912061E-01-9.197329238E-01-1.080803941E+00
|
||||
-1.175377832E+00-1.179650378E+00-1.072877456E+00-8.422994956E-01-4.887614330E-01
|
||||
-3.206461911E-02 4.853974608E-01 9.985106689E-01 1.424598500E+00 1.675050854E+00
|
||||
8.199015377E-01 6.455959983E-01 4.653253241E-01 2.769394057E-01 8.024954100E-02
|
||||
-1.222439302E-01-3.246688374E-01-5.172678502E-01-6.862382215E-01-8.141557599E-01
|
||||
-8.812308347E-01-8.676042109E-01-7.567658125E-01-5.399480748E-01-2.210043304E-01
|
||||
1.791358869E-01 6.197548661E-01 1.040961106E+00 1.369135452E+00 1.528097841E+00
|
||||
8.339278564E-01 6.730837162E-01 5.100416932E-01 3.427308098E-01 1.709112396E-01
|
||||
-3.221170684E-03-1.744881056E-01-3.343523364E-01-4.708744696E-01-5.692032028E-01
|
||||
-6.128066860E-01-5.856071769E-01-4.750595001E-01-2.759990290E-01 5.221341658E-03
|
||||
3.471489908E-01 7.113877498E-01 1.043861665E+00 1.280418325E+00 1.357377573E+00
|
||||
8.387863256E-01 6.913340506E-01 5.450887024E-01 3.979996591E-01 2.497191168E-01
|
||||
1.020859215E-01-4.045731398E-02-1.706141808E-01-2.782935795E-01-3.511479324E-01
|
||||
-3.757593010E-01-3.395926987E-01-2.337188599E-01-5.611233175E-02 1.849391381E-01
|
||||
4.680854372E-01 7.578657830E-01 1.006514653E+00 1.159586428E+00 1.165738769E+00
|
||||
8.325216321E-01 6.985747478E-01 5.687238375E-01 4.409043702E-01 3.146255305E-01
|
||||
1.913389993E-01 7.473585748E-02-2.911651568E-02-1.119191647E-01-1.637085739E-01
|
||||
-1.739780585E-01-1.334333429E-01-3.635127414E-02 1.166660483E-01 3.159822862E-01
|
||||
5.409560343E-01 7.596023466E-01 9.308263465E-01 1.009936725E+00 9.575352010E-01
|
||||
8.135690035E-01 6.934582174E-01 5.796763578E-01 4.701407046E-01 3.642092103E-01
|
||||
2.629430672E-01 1.692957439E-01 8.815231453E-02 2.611713847E-02-9.063055012E-03
|
||||
-9.538719707E-03 3.109598996E-02 1.158088422E-01 2.419024963E-01 3.989659604E-01
|
||||
5.676148854E-01 7.197683473E-01 8.211947470E-01 8.367934603E-01 7.384898454E-01
|
||||
7.809349798E-01 6.751996950E-01 5.772531276E-01 4.850226141E-01 3.977360480E-01
|
||||
3.160900969E-01 2.423462144E-01 1.802896324E-01 1.349679043E-01 1.121217192E-01
|
||||
1.172407810E-01 1.542315062E-01 2.237783488E-01 3.216158548E-01 4.370886419E-01
|
||||
5.525253624E-01 6.440313440E-01 6.842364433E-01 6.472434068E-01 5.154640263E-01
|
||||
7.343619131E-01 6.436962062E-01 5.614219261E-01 4.855364655E-01 4.151880501E-01
|
||||
3.507641660E-01 2.939113975E-01 2.474323310E-01 2.149930564E-01 2.005771397E-01
|
||||
2.076460507E-01 2.380192080E-01 2.905729286E-01 3.599724996E-01 4.357778205E-01
|
||||
5.023656375E-01 5.401375751E-01 5.283698530E-01 4.497523801E-01 2.961440598E-01
|
||||
6.744595449E-01 5.996140461E-01 5.328634336E-01 4.723627302E-01 4.172570594E-01
|
||||
3.677070698E-01 3.248508780E-01 2.906574776E-01 2.676201889E-01 2.582462461E-01
|
||||
2.643256985E-01 2.860143822E-01 3.208428141E-01 3.628585676E-01 4.022050156E-01
|
||||
4.255007017E-01 4.173644838E-01 3.632813892E-01 2.536864244E-01 8.866344730E-02
|
||||
6.027880359E-01 5.444336242E-01 4.929843721E-01 4.468606903E-01 4.053015659E-01
|
||||
3.683453893E-01 3.367530737E-01 3.118362535E-01 2.951519289E-01 2.880365841E-01
|
||||
2.909818720E-01 3.029033791E-01 3.204224066E-01 3.373590566E-01 3.447032023E-01
|
||||
3.313561860E-01 2.858795818E-01 1.993086623E-01 6.876738196E-02-9.881690647E-02
|
||||
1.000000000E+00 1.050035307E+00 1.107285429E+00 1.171072127E+00 1.241305586E+00
|
||||
1.318263580E+00 1.405184527E+00 1.505114754E+00 1.616506900E+00 1.730427615E+00
|
||||
1.891151823E+00 2.065212169E+00 2.268460038E+00 2.512075631E+00 2.811055433E+00
|
||||
3.186196537E+00 3.671181078E+00 4.326097962E+00 5.264420087E+00 6.784828742E+00
|
||||
60 11
|
||||
1.400000000E+00 0.000000000E+00 1.397733920E+00 8.503478852E-02 1.390961356E+00
|
||||
1.691060989E-01 1.379759043E+00 2.512613696E-01 1.364253909E+00 3.305697486E-01
|
||||
1.344621633E+00 4.061326403E-01 1.321084655E+00 4.770938868E-01 1.293909660E+00
|
||||
5.426494690E-01 1.263404552E+00 6.020566159E-01 1.229914964E+00 6.546422207E-01
|
||||
1.193820348E+00 6.998104676E-01 1.155529670E+00 7.370495823E-01 1.115476779E+00
|
||||
7.659376307E-01 1.074115490E+00 7.861472997E-01 1.031914442E+00 7.974496056E-01
|
||||
9.893517914E-01 7.997164889E-01 9.469097891E-01 7.929222648E-01 9.050693201E-01
|
||||
7.771439146E-01 8.643044536E-01 7.525602133E-01 8.250770718E-01 7.194497041E-01
|
||||
7.878316368E-01 6.781875423E-01 7.529901540E-01 6.292412446E-01 7.209473915E-01
|
||||
5.731653922E-01 6.920664066E-01 5.105953469E-01 6.666744324E-01 4.422400523E-01
|
||||
6.450591700E-01 3.688740012E-01 6.274655290E-01 2.913284602E-01 6.140928525E-01
|
||||
2.104820514E-01 6.050926581E-01 1.272507968E-01 6.005669217E-01 4.257773987E-02
|
||||
6.005669217E-01-4.257773987E-02 6.050926581E-01-1.272507968E-01 6.140928525E-01
|
||||
-2.104820514E-01 6.274655290E-01-2.913284602E-01 6.450591700E-01-3.688740012E-01
|
||||
6.666744324E-01-4.422400523E-01 6.920664066E-01-5.105953469E-01 7.209473915E-01
|
||||
-5.731653922E-01 7.529901540E-01-6.292412446E-01 7.878316368E-01-6.781875423E-01
|
||||
8.250770718E-01-7.194497041E-01 8.643044536E-01-7.525602133E-01 9.050693201E-01
|
||||
-7.771439146E-01 9.469097891E-01-7.929222648E-01 9.893517914E-01-7.997164889E-01
|
||||
1.031914442E+00-7.974496056E-01 1.074115490E+00-7.861472997E-01 1.115476779E+00
|
||||
-7.659376307E-01 1.155529670E+00-7.370495823E-01 1.193820348E+00-6.998104676E-01
|
||||
1.229914964E+00-6.546422207E-01 1.263404552E+00-6.020566159E-01 1.293909660E+00
|
||||
-5.426494690E-01 1.321084655E+00-4.770938868E-01 1.344621633E+00-4.061326403E-01
|
||||
1.364253909E+00-3.305697486E-01 1.379759043E+00-2.512613696E-01 1.390961356E+00
|
||||
-1.691060989E-01 1.397733920E+00-8.503478852E-02 1.400000000E+00-1.959434879E-16
|
||||
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
|
||||
@@ -1,826 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include <limits>
|
||||
#include "plasma.hpp"
|
||||
#include "g_eqdsk_data.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace plasma
|
||||
{
|
||||
|
||||
G_EQDSK_Data::G_EQDSK_Data(istream &is, int logging)
|
||||
: logging_(logging), init_flag_(0)
|
||||
{
|
||||
/// The following file format is taken from the C-Mod Wiki at
|
||||
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
|
||||
real_t XDUM = 0.0;
|
||||
|
||||
const int buflen = 1024;
|
||||
char buf[buflen];
|
||||
is.getline(buf, buflen);
|
||||
istringstream iss(buf);
|
||||
string word;
|
||||
iss >> std::ws;
|
||||
while (!iss.eof())
|
||||
{
|
||||
iss >> word;
|
||||
CASE_.push_back(word);
|
||||
iss >> std::ws;
|
||||
}
|
||||
|
||||
NW_ = to_int(CASE_[CASE_.size()-2]);
|
||||
NH_ = to_int(CASE_[CASE_.size()-1]);
|
||||
|
||||
is >> RDIM_ >> ZDIM_ >> RCENTR_ >> RLEFT_ >> ZMID_;
|
||||
is >> RMAXIS_ >> ZMAXIS_ >> SIMAG_ >> SIBRY_ >> BCENTR_;
|
||||
is >> CURRENT_ >> SIMAG_ >> XDUM >> RMAXIS_ >> XDUM;
|
||||
is >> ZMAXIS_ >> XDUM >> SIBRY_ >> XDUM >> XDUM;
|
||||
|
||||
FPOL_.resize(NW_);
|
||||
PRES_.resize(NW_);
|
||||
FFPRIM_.resize(NW_);
|
||||
PPRIME_.resize(NW_);
|
||||
PSIRZ_.resize(NW_ * NH_);
|
||||
QPSI_.resize(NW_);
|
||||
|
||||
for (int i=0; i<NW_; i++) { is >> FPOL_[i]; }
|
||||
for (int i=0; i<NW_; i++) { is >> PRES_[i]; }
|
||||
for (int i=0; i<NW_; i++) { is >> FFPRIM_[i]; }
|
||||
for (int i=0; i<NW_; i++) { is >> PPRIME_[i]; }
|
||||
for (int j=0; j<NH_; j++)
|
||||
{
|
||||
for (int i=0; i<NW_; i++)
|
||||
{
|
||||
is >> PSIRZ_[NH_ * i + j];
|
||||
}
|
||||
}
|
||||
for (int i=0; i<NW_; i++) { is >> QPSI_[i]; }
|
||||
|
||||
is >> NBBBS_ >> LIMITR_;
|
||||
|
||||
RBBBS_.resize(NBBBS_);
|
||||
ZBBBS_.resize(NBBBS_);
|
||||
RLIM_.resize(LIMITR_);
|
||||
ZLIM_.resize(LIMITR_);
|
||||
|
||||
for (int i=0; i<NBBBS_; i++) { is >> RBBBS_[i] >> ZBBBS_[i]; }
|
||||
for (int i=0; i<LIMITR_; i++) { is >> RLIM_[i] >> ZLIM_[i]; }
|
||||
|
||||
if (logging_ > 0) { checkPsiBoundary(); }
|
||||
|
||||
dr_ = RDIM_ / (NW_ - 1);
|
||||
dz_ = ZDIM_ / (NH_ - 1);
|
||||
|
||||
dpsi_ = (SIBRY_ - SIMAG_) / (NW_ - 1);
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::PrintInfo(ostream & out) const
|
||||
{
|
||||
out << endl << "G EQDSK File Info:" << endl;
|
||||
out << "Size of grid: " << NW_ << " x " << NH_ << endl;
|
||||
out << "Number of boundary points: " << NBBBS_ << endl;
|
||||
out << "Number of limiter points: " << LIMITR_ << endl;
|
||||
out << endl;
|
||||
out << "Range of R: " << RLEFT_ << " -> " << RLEFT_ + RDIM_ << endl;
|
||||
out << "Range of Z: " << ZMID_ - 0.5 * ZDIM_
|
||||
<< " -> " << ZMID_ + 0.5 * ZDIM_ << endl;
|
||||
out << "Location of magnetic axis: "
|
||||
<< "(" << RMAXIS_ << "," << ZMAXIS_ << ")" << endl;
|
||||
out << "Poloidal flux at magnetic axis: " << SIMAG_ << endl;
|
||||
out << "Poloidal flux at plasma boundary: " << SIBRY_ << endl;
|
||||
out << "R in meter of vacuum toroidal magnetic field BCENTR: "
|
||||
<< RCENTR_ << endl;
|
||||
out << "Vacuum toroidal magnetic field in Tesla at RCENTR: "
|
||||
<< BCENTR_ << endl;
|
||||
out << "Plasma current in Ampere: " << CURRENT_ << endl << endl;
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::DumpGnuPlotData(const string &file) const
|
||||
{
|
||||
real_t fmin = std::numeric_limits<real_t>::max();
|
||||
real_t fmax = -std::numeric_limits<real_t>::max();
|
||||
real_t pmin = std::numeric_limits<real_t>::max();
|
||||
real_t pmax = -std::numeric_limits<real_t>::max();
|
||||
real_t ffmin = std::numeric_limits<real_t>::max();
|
||||
real_t ffmax = -std::numeric_limits<real_t>::max();
|
||||
real_t ppmin = std::numeric_limits<real_t>::max();
|
||||
real_t ppmax = -std::numeric_limits<real_t>::max();
|
||||
real_t qmin = std::numeric_limits<real_t>::max();
|
||||
real_t qmax = -std::numeric_limits<real_t>::max();
|
||||
|
||||
ostringstream oss_dat, oss_inp;
|
||||
oss_inp << file << ".inp";
|
||||
oss_dat << file << ".dat";
|
||||
ofstream ofs_inp(oss_inp.str().c_str());
|
||||
ofstream ofs_dat(oss_dat.str().c_str());
|
||||
|
||||
for (int i=0; i<NW_; i++)
|
||||
{
|
||||
ofs_dat << real_t(i) / (NW_ - 1)
|
||||
<< '\t' << FPOL_[i]
|
||||
<< '\t' << PRES_[i]
|
||||
<< '\t' << FFPRIM_[i]
|
||||
<< '\t' << PPRIME_[i]
|
||||
<< '\t' << QPSI_[i]
|
||||
<< '\n';
|
||||
fmin = min(FPOL_[i], fmin);
|
||||
fmax = max(FPOL_[i], fmax);
|
||||
pmin = min(PRES_[i], pmin);
|
||||
pmax = max(PRES_[i], pmax);
|
||||
ffmin = min(FFPRIM_[i], ffmin);
|
||||
ffmax = max(FFPRIM_[i], ffmax);
|
||||
ppmin = min(PPRIME_[i], ppmin);
|
||||
ppmax = max(PPRIME_[i], ppmax);
|
||||
qmin = min(QPSI_[i], qmin);
|
||||
qmax = max(QPSI_[i], qmax);
|
||||
}
|
||||
|
||||
ofs_dat << "\n\n";
|
||||
for (int i=0; i<NW_; i++)
|
||||
{
|
||||
for (int j=0; j<NH_; j++)
|
||||
{
|
||||
ofs_dat << RLEFT_ + RDIM_ * i / (NW_ - 1)
|
||||
<< '\t' << ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1)
|
||||
<< '\t' << PSIRZ_[NH_ * i + j]
|
||||
<< '\n';
|
||||
}
|
||||
ofs_dat << '\n';
|
||||
}
|
||||
ofs_dat << "\n\n";
|
||||
for (int i=0; i<NBBBS_; i++)
|
||||
{
|
||||
ofs_dat << RBBBS_[i] << '\t' << ZBBBS_[i] << '\n';
|
||||
}
|
||||
ofs_dat << "\n\n";
|
||||
for (int i=0; i<LIMITR_; i++)
|
||||
{
|
||||
ofs_dat << RLIM_[i] << '\t' << ZLIM_[i] << '\n';
|
||||
}
|
||||
ofs_dat.close();
|
||||
|
||||
ofs_inp << "set xrange [0:1];\n";
|
||||
ofs_inp << "set yrange [" << fmin << ":" << fmax << "];\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 0 using 1:2 w l t 'FPOL';\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
ofs_inp << "set yrange [" << pmin << ":" << pmax << "];\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 0 using 1:3 w l t 'PRES';\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
ofs_inp << "set yrange [" << ffmin << ":" << ffmax << "];\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 0 using 1:4 w l t 'FFPRIME';\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
ofs_inp << "set yrange [" << ppmin << ":" << ppmax << "];\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 0 using 1:5 w l t 'PPRIME';\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
ofs_inp << "set yrange [" << qmin << ":" << qmax << "];\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 0 using 1:6 w l t 'QPSI';\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
|
||||
ofs_inp << "unset xrange\n";
|
||||
ofs_inp << "unset yrange\n";
|
||||
ofs_inp << "set view map;\n";
|
||||
ofs_inp << "unset surface;\n";
|
||||
ofs_inp << "set contour base;\n";
|
||||
ofs_inp << "set cntrparam levels 20;\n";
|
||||
ofs_inp << "set size ratio -1;\n";
|
||||
ofs_inp << "set nokey;\n";
|
||||
ofs_inp << "splot '" << oss_dat.str()
|
||||
<< "' index 1 with lines pal t 'PSIRZ';\n";
|
||||
ofs_inp << "set key;\n";
|
||||
ofs_inp << "pause -1;\n";
|
||||
ofs_inp << "set size ratio -1;\n";
|
||||
ofs_inp << "plot '" << oss_dat.str()
|
||||
<< "' index 2 using 1:2 w l t 'BOUNDARY',";
|
||||
ofs_inp << " '" << oss_dat.str()
|
||||
<< "' index 3 using 1:2 w l t 'LIMITER';\n";
|
||||
|
||||
ofs_inp.close();
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::checkPsiBoundary()
|
||||
{
|
||||
real_t psi_avg = 0.0;
|
||||
real_t psi_dif = 0.0;
|
||||
real_t psi_min = std::numeric_limits<real_t>::max();
|
||||
real_t psi_max = std::numeric_limits<real_t>::min();
|
||||
|
||||
Vector rz(2);
|
||||
real_t psi = 0.0;
|
||||
for (int i=0; i<NBBBS_; i++)
|
||||
{
|
||||
rz[0] = RBBBS_[i];
|
||||
rz[1] = ZBBBS_[i];
|
||||
psi = this->InterpPsiRZ(rz);
|
||||
|
||||
psi_min = std::min(psi, psi_min);
|
||||
psi_max = std::max(psi, psi_max);
|
||||
|
||||
psi_avg += psi;
|
||||
psi_dif += abs(psi - SIBRY_);
|
||||
}
|
||||
psi_avg /= NBBBS_;
|
||||
psi_dif /= NBBBS_;
|
||||
|
||||
if (logging_ > 1)
|
||||
{
|
||||
mfem::out << psi_min << " <= (Psi on plasma boundary) <= "
|
||||
<< psi_max << endl;
|
||||
mfem::out << "Average of Psi on plasma boundary: " << psi_avg << endl;
|
||||
mfem::out << "Average of |Psi - SIBRY| on plasma boundary: "
|
||||
<< psi_dif << endl;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(psi_dif < 1e-2 * abs(SIMAG_), "Psi differs from its imposed "
|
||||
"boundary value more than expected.");
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpFPolRZ(const Vector &rz)
|
||||
{
|
||||
real_t psi = InterpPsiRZ(rz);
|
||||
|
||||
if (!checkFlag(FPOL))
|
||||
{
|
||||
initInterpPsi(FPOL_, FPOL_t_);
|
||||
setFlag(FPOL);
|
||||
}
|
||||
|
||||
return interpPsi(psi, FPOL_, FPOL_t_);
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpPresRZ(const Vector &rz)
|
||||
{
|
||||
real_t psi = InterpPsiRZ(rz);
|
||||
|
||||
if (!checkFlag(PRES))
|
||||
{
|
||||
initInterpPsi(PRES_, PRES_t_);
|
||||
setFlag(PRES);
|
||||
}
|
||||
|
||||
return interpPsi(psi, PRES_, PRES_t_);
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpFFPrimeRZ(const Vector &rz)
|
||||
{
|
||||
real_t psi = InterpPsiRZ(rz);
|
||||
|
||||
if (!checkFlag(FFPRIM))
|
||||
{
|
||||
initInterpPsi(FFPRIM_, FFPRIM_t_);
|
||||
setFlag(FFPRIM);
|
||||
}
|
||||
return interpPsi(psi, FFPRIM_, FFPRIM_t_);
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpPPrimeRZ(const Vector &rz)
|
||||
{
|
||||
real_t psi = InterpPsiRZ(rz);
|
||||
|
||||
if (!checkFlag(PPRIME))
|
||||
{
|
||||
initInterpPsi(PPRIME_, PPRIME_t_);
|
||||
setFlag(PPRIME);
|
||||
}
|
||||
return interpPsi(psi, PPRIME_, PPRIME_t_);
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpPsiRZ(const Vector &rz)
|
||||
{
|
||||
if (!checkFlag(PSIRZ))
|
||||
{
|
||||
initInterpRZ(PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
|
||||
setFlag(PSIRZ);
|
||||
}
|
||||
return interpRZ(rz, PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpQRZ(const Vector &rz)
|
||||
{
|
||||
real_t psi = InterpPsiRZ(rz);
|
||||
|
||||
if (!checkFlag(QPSI))
|
||||
{
|
||||
initInterpPsi(QPSI_, QPSI_t_);
|
||||
setFlag(QPSI);
|
||||
}
|
||||
|
||||
return interpPsi(psi, QPSI_, QPSI_t_);
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::InterpNxGradPsiRZ(const Vector &rz, Vector &nxdp)
|
||||
{
|
||||
if (!checkFlag(PSIRZ))
|
||||
{
|
||||
initInterpRZ(PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_);
|
||||
setFlag(PSIRZ);
|
||||
}
|
||||
interpNxGradRZ(rz, PSIRZ_, PSIRZ_c_, PSIRZ_d_, PSIRZ_e_, nxdp);
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::InterpBPolRZ(const Vector &rz, Vector &bpol)
|
||||
{
|
||||
InterpNxGradPsiRZ(rz, bpol);
|
||||
if (rz[0] > 1e-6 * RDIM_) { bpol /= rz[0]; }
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpBTorRZ(const Vector &rz)
|
||||
{
|
||||
if (rz[0] > 1e-6 * RDIM_)
|
||||
{
|
||||
return InterpFPolRZ(rz) / rz[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::InterpJTorRZ(const Vector &rz)
|
||||
{
|
||||
if (rz[0] > 1e-6 * RDIM_)
|
||||
{
|
||||
return InterpPPrimeRZ(rz) * rz[0] +
|
||||
InterpFFPrimeRZ(rz) / rz[0] / mu0_;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::initInterpRZ(const std::vector<real_t> &v,
|
||||
ShiftedDenseMatrix &c,
|
||||
ShiftedDenseMatrix &d,
|
||||
ShiftedDenseMatrix &e)
|
||||
{
|
||||
ExtendedDenseMatrix ve(&v[0], NW_, NH_);
|
||||
|
||||
c.SetSize(NW_ + 3, NH_ + 2); c.SetShifts(2, 1); c = 0.0;
|
||||
d.SetSize(NW_ + 2, NH_ + 3); d.SetShifts(1, 2); d = 0.0;
|
||||
e.SetSize(NW_ + 1, NH_ + 1); e.SetShifts(1, 1); e = 0.0;
|
||||
|
||||
// x-directed divided differences
|
||||
for (int i=-1; i<NW_; i++)
|
||||
{
|
||||
c(i,-1) = (ve(i+1,-1) - ve(i,-1)) / dr_;
|
||||
}
|
||||
for (int j=0; j<NH_; j++)
|
||||
{
|
||||
for (int i=-2; i<=NW_; i++)
|
||||
{
|
||||
c(i,j) = (ve(i+1,j) - ve(i,j)) / dr_;
|
||||
}
|
||||
}
|
||||
for (int i=-1; i<NW_; i++)
|
||||
{
|
||||
c(i,NH_) = (ve(i+1,NH_) - ve(i,NH_)) / dr_;
|
||||
}
|
||||
|
||||
// y-directed divided differences
|
||||
for (int j=-1; j<NH_; j++)
|
||||
{
|
||||
d(-1,j) = (ve(-1,j+1) - ve(-1,j)) / dz_;
|
||||
}
|
||||
for (int i=0; i<NW_; i++)
|
||||
{
|
||||
for (int j=-2; j<=NH_; j++)
|
||||
{
|
||||
d(i,j) = (ve(i,j+1) - ve(i,j)) / dz_;
|
||||
}
|
||||
}
|
||||
for (int j=-1; j<NH_; j++)
|
||||
{
|
||||
d(NW_,j) = (ve(NW_,j+1) - ve(NW_,j)) / dz_;
|
||||
}
|
||||
|
||||
// Second order divided differences
|
||||
for (int i=-1; i<NW_; i++)
|
||||
{
|
||||
for (int j=-1; j<NH_; j++)
|
||||
{
|
||||
e(i,j) = (c(i,j+1) - c(i,j)) / dz_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::interpRZ(const Vector &rz,
|
||||
const std::vector<real_t> &v,
|
||||
const ShiftedDenseMatrix &c,
|
||||
const ShiftedDenseMatrix &d,
|
||||
const ShiftedDenseMatrix &e)
|
||||
{
|
||||
real_t r = rz[0];
|
||||
real_t z = rz[1];
|
||||
|
||||
real_t rs = (r - RLEFT_) / RDIM_;
|
||||
real_t zs = (z - ZMID_ + 0.5 * ZDIM_) / ZDIM_;
|
||||
|
||||
int i = std::max(0, std::min((int)floor(real_t(NW_-1) * rs), NW_-2));
|
||||
int j = std::max(0, std::min((int)floor(real_t(NH_-1) * zs), NH_-2));
|
||||
|
||||
// Compute corners of local patch
|
||||
real_t r0 = RLEFT_ + RDIM_ * i / (NW_ - 1);
|
||||
real_t r1 = r0 + RDIM_ / (NW_ - 1);
|
||||
real_t z0 = ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1);
|
||||
real_t z1 = z0 + ZDIM_ / (NH_ - 1);
|
||||
|
||||
// Prepare position dependent factors
|
||||
real_t wra = (r1 - r) / dr_;
|
||||
real_t wrb = (r - r0) / dr_;
|
||||
real_t wrc = (1.0 + 2.0 * wra);
|
||||
real_t wrd = (1.0 + 2.0 * wrb);
|
||||
real_t wra2 = wra * wra;
|
||||
real_t wrb2 = wrb * wrb;
|
||||
|
||||
real_t wza = (z1 - z) / dz_;
|
||||
real_t wzb = (z - z0) / dz_;
|
||||
real_t wzc = (1.0 + 2.0 * wza);
|
||||
real_t wzd = (1.0 + 2.0 * wzb);
|
||||
real_t wza2 = wza * wza;
|
||||
real_t wzb2 = wzb * wzb;
|
||||
|
||||
// Extract variable values at corners of local patch
|
||||
real_t p00 = v[NH_ * i + j];
|
||||
real_t p10 = v[NH_ * (i + 1) + j];
|
||||
real_t p01 = v[NH_ * i + j + 1];
|
||||
real_t p11 = v[NH_ * (i + 1) + j + 1];
|
||||
|
||||
real_t var = p00 * wra2 * wrd * wza2 * wzd
|
||||
+ p10 * wrb2 * wrc * wza2 * wzd
|
||||
+ p01 * wra2 * wrd * wzb2 * wzc
|
||||
+ p11 * wrb2 * wrc * wzb2 * wzc;
|
||||
|
||||
// Compute dvar/dx at corners of local patch
|
||||
real_t wx00a = fabs(c(i-1,j) - c(i-2,j));
|
||||
real_t wx00b = fabs(c(i+1,j) - c(i,j));
|
||||
|
||||
real_t wx10a = fabs(c(i,j) - c(i-1,j));
|
||||
real_t wx10b = fabs(c(i+2,j) - c(i+1,j));
|
||||
|
||||
real_t wx01a = fabs(c(i-1,j+1) - c(i-2,j+1));
|
||||
real_t wx01b = fabs(c(i+1,j+1) - c(i,j+1));
|
||||
|
||||
real_t wx11a = fabs(c(i,j+1) - c(i-1,j+1));
|
||||
real_t wx11b = fabs(c(i+2,j+1) - c(i+1,j+1));
|
||||
|
||||
if (wx00a == 0.0 && wx00b == 0.0) { wx00a = 1.0; wx00b = 1.0; }
|
||||
if (wx10a == 0.0 && wx10b == 0.0) { wx10a = 1.0; wx10b = 1.0; }
|
||||
if (wx01a == 0.0 && wx01b == 0.0) { wx01a = 1.0; wx01b = 1.0; }
|
||||
if (wx11a == 0.0 && wx11b == 0.0) { wx11a = 1.0; wx11b = 1.0; }
|
||||
|
||||
real_t px00 = (wx00b * c(i-1,j) + wx00a * c(i,j)) / (wx00b + wx00a);
|
||||
real_t px10 = (wx10b * c(i,j) + wx10a * c(i+1,j)) / (wx10b + wx10a);
|
||||
real_t px01 = (wx01b * c(i-1,j+1) + wx01a * c(i,j+1)) / (wx01b + wx01a);
|
||||
real_t px11 = (wx11b * c(i,j+1) + wx11a * c(i+1,j+1)) / (wx11b + wx11a);
|
||||
|
||||
real_t varx = px00 * wra2 * wrb * wza2 * wzd
|
||||
- px10 * wrb2 * wra * wza2 * wzd
|
||||
+ px01 * wrb * wra2 * wzb2 * wzc
|
||||
- px11 * wra * wrb2 * wzb2 * wzc;
|
||||
var += varx * dr_;
|
||||
|
||||
// Compute dvar/dy at corners of local patch
|
||||
real_t wy00a = fabs(d(i,j-1) - d(i,j-2));
|
||||
real_t wy00b = fabs(d(i,j+1) - d(i,j));
|
||||
|
||||
real_t wy10a = fabs(d(i+1,j-1) - d(i+1,j-2));
|
||||
real_t wy10b = fabs(d(i+1,j+1) - d(i+1,j));
|
||||
|
||||
real_t wy01a = fabs(d(i,j) - d(i,j-1));
|
||||
real_t wy01b = fabs(d(i,j+2) - d(i,j+1));
|
||||
|
||||
real_t wy11a = fabs(d(i+1,j) - d(i+1,j-1));
|
||||
real_t wy11b = fabs(d(i+1,j+2) - d(i+1,j+1));
|
||||
|
||||
if (wy00a == 0.0 && wy00b == 0.0) { wy00a = 1.0; wy00b = 1.0; }
|
||||
if (wy10a == 0.0 && wy10b == 0.0) { wy10a = 1.0; wy10b = 1.0; }
|
||||
if (wy01a == 0.0 && wy01b == 0.0) { wy01a = 1.0; wy01b = 1.0; }
|
||||
if (wy11a == 0.0 && wy11b == 0.0) { wy11a = 1.0; wy11b = 1.0; }
|
||||
|
||||
real_t py00 = (wy00b * d(i,j-1) + wy00a * d(i,j)) / (wy00b + wy00a);
|
||||
real_t py10 = (wy10b * d(i+1,j-1) + wy10a * d(i+1,j)) / (wy10b + wy10a);
|
||||
real_t py01 = (wy01b * d(i,j) + wy01a * d(i,j+1)) / (wy01b + wy01a);
|
||||
real_t py11 = (wy11b * d(i+1,j) + wy11a * d(i+1,j)) / (wy11b + wy11a);
|
||||
|
||||
real_t vary = py00 * wra2 * wrd * wza2 * wzb
|
||||
+ py10 * wrb2 * wrc * wza2 * wzb
|
||||
- py01 * wra2 * wrd * wza * wzb2
|
||||
- py11 * wrb2 * wrc * wza * wzb2;
|
||||
var += vary * dz_;
|
||||
|
||||
// Compute d^2var/dxdy at corners of local patch
|
||||
real_t pxy00 = (wx00b * (wy00b * e(i-1,j-1) + wy00a * e(i-1,j)) +
|
||||
wx00a * (wy00b * e(i,j-1) + wy00a * e(i,j))) /
|
||||
((wx00b + wx00a) * (wy00b + wy00a));
|
||||
real_t pxy10 = (wx10b * (wy10b * e(i,j-1) + wy10a * e(i,j)) +
|
||||
wx10a * (wy10b * e(i+1,j-1) + wy10a * e(i+1,j))) /
|
||||
((wx10b + wx10a) * (wy10b + wy10a));
|
||||
real_t pxy01 = (wx01b * (wy01b * e(i-1,j) + wy01a * e(i-1,j+1)) +
|
||||
wx01a * (wy01b * e(i,j) + wy01a * e(i,j+1))) /
|
||||
((wx01b + wx01a) * (wy01b + wy01a));
|
||||
real_t pxy11 = (wx11b * (wy11b * e(i,j) + wy11a * e(i,j+1)) +
|
||||
wx11a * (wy11b * e(i+1,j) + wy11a * e(i+1,j+1))) /
|
||||
((wx11b + wx11a) * (wy11b + wy11a));
|
||||
|
||||
real_t varxy = pxy00 * wra2 * wrb * wza2 * wzb
|
||||
- pxy10 * wra * wrb2 * wza2 * wzb
|
||||
- pxy01 * wra2 * wrb * wza * wzb2
|
||||
+ pxy11 * wra * wrb2 * wza * wzb2;
|
||||
|
||||
var += dr_ * dz_ * varxy;
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::interpNxGradRZ(const Vector &rz,
|
||||
const std::vector<real_t> &v,
|
||||
const ShiftedDenseMatrix &c,
|
||||
const ShiftedDenseMatrix &d,
|
||||
const ShiftedDenseMatrix &e,
|
||||
Vector &b)
|
||||
{
|
||||
b.SetSize(2);
|
||||
b = 0.0;
|
||||
|
||||
real_t r = rz[0];
|
||||
real_t z = rz[1];
|
||||
|
||||
real_t rs = (r - RLEFT_) / RDIM_;
|
||||
real_t zs = (z - ZMID_ + 0.5 * ZDIM_) / ZDIM_;
|
||||
|
||||
int i = std::max(0, std::min((int)floor(real_t(NW_-1) * rs), NW_-2));
|
||||
int j = std::max(0, std::min((int)floor(real_t(NH_-1) * zs), NH_-2));
|
||||
|
||||
// Compute corners of local patch
|
||||
real_t r0 = RLEFT_ + RDIM_ * i / (NW_ - 1);
|
||||
real_t r1 = r0 + RDIM_ / (NW_ - 1);
|
||||
real_t z0 = ZMID_ - 0.5 * ZDIM_ + ZDIM_ * j / (NH_ - 1);
|
||||
real_t z1 = z0 + ZDIM_ / (NH_ - 1);
|
||||
|
||||
// Prepare position dependent factors
|
||||
real_t wra = (r1 - r) / dr_, dwra = -1.0 / dr_;
|
||||
real_t wrb = (r - r0) / dr_, dwrb = 1.0 / dr_;
|
||||
real_t wrc = (1.0 + 2.0 * wra), dwrc = 2.0 * dwra;
|
||||
real_t wrd = (1.0 + 2.0 * wrb), dwrd = 2.0 * dwrb;
|
||||
real_t wra2 = wra * wra, dwra2 = 2.0 * wra * dwra;
|
||||
real_t wrb2 = wrb * wrb, dwrb2 = 2.0 * wrb * dwrb;
|
||||
|
||||
real_t wza = (z1 - z) / dz_, dwza = -1.0 / dz_;
|
||||
real_t wzb = (z - z0) / dz_, dwzb = 1.0 / dz_;
|
||||
real_t wzc = (1.0 + 2.0 * wza), dwzc = 2.0 * dwza;
|
||||
real_t wzd = (1.0 + 2.0 * wzb), dwzd = 2.0 * dwzb;
|
||||
real_t wza2 = wza * wza, dwza2 = 2.0 * wza * dwza;
|
||||
real_t wzb2 = wzb * wzb, dwzb2 = 2.0 * wzb * dwzb;
|
||||
|
||||
// Extract var values at corners of local patch
|
||||
real_t p00 = v[NH_ * i + j];
|
||||
real_t p10 = v[NH_ * (i + 1) + j];
|
||||
real_t p01 = v[NH_ * i + j + 1];
|
||||
real_t p11 = v[NH_ * (i + 1) + j + 1];
|
||||
|
||||
b[0] -=
|
||||
(p00 * wra2 * wrd + p10 * wrb2 * wrc ) * (dwza2 * wzd + wza2 * dwzd)
|
||||
+ (p01 * wra2 * wrd + p11 * wrb2 * wrc) * (dwzb2 * wzc + wzb2 * dwzc);
|
||||
b[1] +=
|
||||
(p00 * wza2 * wzd + p01 * wzb2 * wzc) * (dwra2 * wrd + wra2 * dwrd)
|
||||
+ (p10 * wza2 * wzd + p11 * wzb2 * wzc) * (dwrb2 * wrc + wrb2 * dwrc);
|
||||
|
||||
// Compute dvar/dx at corners of local patch
|
||||
real_t wx00a = fabs(c(i-1,j) - c(i-2,j));
|
||||
real_t wx00b = fabs(c(i+1,j) - c(i,j));
|
||||
|
||||
real_t wx10a = fabs(c(i,j) - c(i-1,j));
|
||||
real_t wx10b = fabs(c(i+2,j) - c(i+1,j));
|
||||
|
||||
real_t wx01a = fabs(c(i-1,j+1) - c(i-2,j+1));
|
||||
real_t wx01b = fabs(c(i+1,j+1) - c(i,j+1));
|
||||
|
||||
real_t wx11a = fabs(c(i,j+1) - c(i-1,j+1));
|
||||
real_t wx11b = fabs(c(i+2,j+1) - c(i+1,j+1));
|
||||
|
||||
if (wx00a == 0.0 && wx00b == 0.0) { wx00a = 1.0; wx00b = 1.0; }
|
||||
if (wx10a == 0.0 && wx10b == 0.0) { wx10a = 1.0; wx10b = 1.0; }
|
||||
if (wx01a == 0.0 && wx01b == 0.0) { wx01a = 1.0; wx01b = 1.0; }
|
||||
if (wx11a == 0.0 && wx11b == 0.0) { wx11a = 1.0; wx11b = 1.0; }
|
||||
|
||||
real_t px00 = (wx00b * c(i-1,j) + wx00a * c(i,j)) / (wx00b + wx00a);
|
||||
real_t px10 = (wx10b * c(i,j) + wx10a * c(i+1,j)) / (wx10b + wx10a);
|
||||
real_t px01 = (wx01b * c(i-1,j+1) + wx01a * c(i,j+1)) / (wx01b + wx01a);
|
||||
real_t px11 = (wx11b * c(i,j+1) + wx11a * c(i+1,j+1)) / (wx11b + wx11a);
|
||||
|
||||
b[0] -= dr_ *
|
||||
((px00 * wra2 * wrb - px10 * wrb2 * wra) *
|
||||
(dwza2 * wzd + wza2 * dwzd) +
|
||||
(px01 * wrb * wra2 - px11 * wra * wrb2) *
|
||||
(dwzb2 * wzc + wzb2 * dwzc));
|
||||
|
||||
b[1] += dr_ *
|
||||
((px00 * wza2 * wzd + px01 * wzb2 * wzc) *
|
||||
(dwra2 * wrb + wra2 * dwrb ) -
|
||||
(px10 * wza2 * wzd + px11 * wzb2 * wzc) *
|
||||
(dwra * wrb2 + wra * dwrb2));
|
||||
|
||||
// Compute dvar/dy at corners of local patch
|
||||
real_t wy00a = fabs(d(i,j-1) - d(i,j-2));
|
||||
real_t wy00b = fabs(d(i,j+1) - d(i,j));
|
||||
|
||||
real_t wy10a = fabs(d(i+1,j-1) - d(i+1,j-2));
|
||||
real_t wy10b = fabs(d(i+1,j+1) - d(i+1,j));
|
||||
|
||||
real_t wy01a = fabs(d(i,j) - d(i,j-1));
|
||||
real_t wy01b = fabs(d(i,j+2) - d(i,j+1));
|
||||
|
||||
real_t wy11a = fabs(d(i+1,j) - d(i+1,j-1));
|
||||
real_t wy11b = fabs(d(i+1,j+2) - d(i+1,j+1));
|
||||
|
||||
if (wy00a == 0.0 && wy00b == 0.0) { wy00a = 1.0; wy00b = 1.0; }
|
||||
if (wy10a == 0.0 && wy10b == 0.0) { wy10a = 1.0; wy10b = 1.0; }
|
||||
if (wy01a == 0.0 && wy01b == 0.0) { wy01a = 1.0; wy01b = 1.0; }
|
||||
if (wy11a == 0.0 && wy11b == 0.0) { wy11a = 1.0; wy11b = 1.0; }
|
||||
|
||||
real_t py00 = (wy00b * d(i,j-1) + wy00a * d(i,j)) / (wy00b + wy00a);
|
||||
real_t py10 = (wy10b * d(i+1,j-1) + wy10a * d(i+1,j)) / (wy10b + wy10a);
|
||||
real_t py01 = (wy01b * d(i,j) + wy01a * d(i,j+1)) / (wy01b + wy01a);
|
||||
real_t py11 = (wy11b * d(i+1,j) + wy11a * d(i+1,j)) / (wy11b + wy11a);
|
||||
|
||||
b[0] -= dz_ *
|
||||
((py00 * wra2 * wrd + py10 * wrb2 * wrc) *
|
||||
(dwza2 * wzb + wza2 * dwzb) -
|
||||
(py01 * wra2 * wrd + py11 * wrb2 * wrc) *
|
||||
(dwza * wzb2 + wza * dwzb2));
|
||||
b[1] += dz_ *
|
||||
((py00 * wza2 * wzb - py01 * wza * wzb2) *
|
||||
(dwra2 * wrd + wra2 * dwrd) +
|
||||
(py10 * wza2 * wzb - py11 * wza * wzb2) *
|
||||
(dwrb2 * wrc + wrb2 * dwrc));
|
||||
|
||||
// Compute d^2var/dxdy at corners of local patch
|
||||
real_t pxy00 = (wx00b * (wy00b * e(i-1,j-1) + wy00a * e(i-1,j)) +
|
||||
wx00a * (wy00b * e(i,j-1) + wy00a * e(i,j))) /
|
||||
((wx00b + wx00a) * (wy00b + wy00a));
|
||||
real_t pxy10 = (wx10b * (wy10b * e(i,j-1) + wy10a * e(i,j)) +
|
||||
wx10a * (wy10b * e(i+1,j-1) + wy10a * e(i+1,j))) /
|
||||
((wx10b + wx10a) * (wy10b + wy10a));
|
||||
real_t pxy01 = (wx01b * (wy01b * e(i-1,j) + wy01a * e(i-1,j+1)) +
|
||||
wx01a * (wy01b * e(i,j) + wy01a * e(i,j+1))) /
|
||||
((wx01b + wx01a) * (wy01b + wy01a));
|
||||
real_t pxy11 = (wx11b * (wy11b * e(i,j) + wy11a * e(i,j+1)) +
|
||||
wx11a * (wy11b * e(i+1,j) + wy11a * e(i+1,j+1))) /
|
||||
((wx11b + wx11a) * (wy11b + wy11a));
|
||||
|
||||
b[0] -= dr_ * dz_ * ((pxy00 * wra2 * wrb - pxy10 * wra * wrb2)
|
||||
* (dwza2 * wzb + wza2 * dwzb) +
|
||||
(pxy11 * wra * wrb2 - pxy01 * wra2 * wrb)
|
||||
* (dwza * wzb2 + wza * dwzb2));
|
||||
b[1] += dr_ * dz_ * ((pxy00 * wza2 * wzb - pxy01 * wza * wzb2)
|
||||
* (dwra2 * wrb + wra2 * dwrb) +
|
||||
(pxy11 * wza * wzb2 - pxy10 * wza2 * wzb)
|
||||
* (dwra * wrb2 + wra * dwrb2));
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::initInterpPsi(const std::vector<real_t> &v,
|
||||
std::vector<real_t> &t)
|
||||
{
|
||||
// Initialize the divided differences
|
||||
ShiftedVector m(NW_-1, 2); m = 0.0;
|
||||
|
||||
m(-2) = -2.0 * v[2] + 5.0 * v[1] - 3.0 * v[0];
|
||||
m(-1) = -1.0 * v[2] + 3.0 * v[1] - 2.0 * v[0];
|
||||
for (int i=0; i<NW_-1; i++)
|
||||
{
|
||||
m(i) = v[i+1] - v[i];
|
||||
}
|
||||
m(NW_-1) = 2.0 * v[NW_-1] - 3.0 * v[NW_-2] + v[NW_-3];
|
||||
m(NW_) = 3.0 * v[NW_-1] - 5.0 * v[NW_-2] + 2.0 * v[NW_-3];
|
||||
|
||||
// Initialize the Slopes
|
||||
t.resize(NW_);
|
||||
|
||||
for (int i=0; i<NW_; i++)
|
||||
{
|
||||
if (m(i+1) == m(i) && m(i-1) == m(i-2))
|
||||
{
|
||||
if (m(i) == m(i-1))
|
||||
{
|
||||
t[i] = m(i) * dpsi_;
|
||||
}
|
||||
else
|
||||
{
|
||||
t[i] = 0.5 * (m(i-1) + m(i)) * dpsi_;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t[i] = (fabs(m(i+1) - m(i)) * m(i-1) +
|
||||
fabs(m(i-1) - m(i-2)) * m(i)) * dpsi_ /
|
||||
(fabs(m(i+1) - m(i)) + fabs(m(i-1) - m(i-2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t G_EQDSK_Data::interpPsi(real_t psi, const vector<real_t> &v,
|
||||
const vector<real_t> &t)
|
||||
{
|
||||
real_t psimin = std::min(SIMAG_, SIBRY_);
|
||||
real_t psimax = std::max(SIMAG_, SIBRY_);
|
||||
|
||||
// Psi constrained to be between psimin and psimax
|
||||
real_t psic = std::max(psimin, std::min(psi, psimax));
|
||||
|
||||
// Psi scaled to the range 0 -> 1
|
||||
real_t psis = (psic - SIMAG_) / (SIBRY_ - SIMAG_);
|
||||
|
||||
// Located the bin containing psis counting from 0
|
||||
int i0 = std::max(0, std::min((int)floor(real_t(NW_-1) * psis), NW_-2));
|
||||
int i1 = i0 + 1;
|
||||
|
||||
// Compute ends of local patch
|
||||
real_t psi0 = SIMAG_ + (SIBRY_ - SIMAG_) * i0 / (NW_ - 1);
|
||||
real_t psi1 = psi0 + (SIBRY_ - SIMAG_) / (NW_ - 1);
|
||||
|
||||
// Prepare position dependent factors
|
||||
real_t wra = (psi1 - psic) / dpsi_;
|
||||
real_t wrb = (psic - psi0) / dpsi_;
|
||||
real_t wrc = (1.0 + 2.0 * wra);
|
||||
real_t wrd = (1.0 + 2.0 * wrb);
|
||||
real_t wra2 = wra * wra;
|
||||
real_t wrb2 = wrb * wrb;
|
||||
|
||||
// Extract variable values at ends of local patch
|
||||
const real_t &p0 = v[i0];
|
||||
const real_t &p1 = v[i1];
|
||||
|
||||
real_t var = p0 * wra2 * wrd + p1 * wrb2 * wrc;
|
||||
|
||||
// Extract dvar/dx at ends of local patch
|
||||
const real_t &px0 = t[i0];
|
||||
const real_t &px1 = t[i1];
|
||||
|
||||
real_t varx = px0 * wra2 * wrb - px1 * wrb2 * wra;
|
||||
|
||||
var += varx * dpsi_;
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
void G_EQDSK_Data::ExtendedDenseMatrix::init()
|
||||
{
|
||||
// Populate four corners
|
||||
SW_ = 3.0 * ((*this)(0,0) - (*this)(1,1)) + (*this)(2,2);
|
||||
SE_ = 3.0 * ((*this)(m_-1,0) - (*this)(m_-2,1)) + (*this)(m_-3,2);
|
||||
NW_ = 3.0 * ((*this)(0,n_-1) - (*this)(1,n_-2)) + (*this)(2,n_-3);
|
||||
NE_ = 3.0 * ((*this)(m_-1,n_-1) - (*this)(m_-2,n_-2))
|
||||
+ (*this)(m_-3,n_-3);
|
||||
|
||||
// Populate lowest rows
|
||||
for (int j=0; j<n_; j++)
|
||||
{
|
||||
S_(1,j) = 3.0 * ((*this)(0,j) - (*this)(1,j)) + (*this)(2,j);
|
||||
S_(0,j) = 3.0 * (2.0 * (*this)(0,j) + (*this)(2,j)) - 8.0 * (*this)(1,j);
|
||||
}
|
||||
|
||||
// Populate highest rows
|
||||
for (int j=0; j<n_; j++)
|
||||
{
|
||||
N_(1,j) = 3.0 * (2.0 * (*this)(m_-1,j) + (*this)(m_-3,j))
|
||||
- 8.0 * (*this)(m_-2,j);
|
||||
N_(0,j) = 3.0 * ((*this)(m_-1,j) - (*this)(m_-2,j)) + (*this)(m_-3,j);
|
||||
}
|
||||
|
||||
// Populate lowest columns
|
||||
for (int i=0; i<m_; i++)
|
||||
{
|
||||
W_(i,0) = 3.0 * (2.0 * (*this)(i,0) + (*this)(i,2)) - 8.0 * (*this)(i,1);
|
||||
W_(i,1) = 3.0 * ((*this)(i,0) - (*this)(i,1)) + (*this)(i,2);
|
||||
}
|
||||
|
||||
// Populate highest columns
|
||||
for (int i=0; i<m_; i++)
|
||||
{
|
||||
E_(i,0) = 3.0 * ((*this)(i,n_-1) - (*this)(i,n_-2)) + (*this)(i,n_-3);
|
||||
E_(i,1) = 3.0 * (2.0 * (*this)(i,n_-1) + (*this)(i,n_-3))
|
||||
- 8.0 * (*this)(i,n_-2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace plasma
|
||||
|
||||
} // namespace mfem
|
||||
@@ -1,587 +0,0 @@
|
||||
// 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_G_EQDSK_DATA_HPP
|
||||
#define MFEM_G_EQDSK_DATA_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "../../general/text.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
namespace plasma
|
||||
{
|
||||
|
||||
/// Class for reading and interpolating data stored in ASCII files
|
||||
/// following the G_EQDSK format as described in the C-Mod Wiki at
|
||||
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
|
||||
///
|
||||
/// G_EQDSK files contain four types of data:
|
||||
///
|
||||
/// 1) A poloidal flux function, Psi, stored as a uniform 2D grid
|
||||
/// of data values along with information describing the grid
|
||||
/// and values of the flux at the magnetic axis (SIMAG) and the
|
||||
/// plasma boundary (SIBRY).
|
||||
///
|
||||
/// 2) Five 1D fields which are functions of Psi. These fields are
|
||||
/// defined on a uniform grid of points ranging from Psi = 0 to
|
||||
/// Psi = SIMAG.
|
||||
///
|
||||
/// 3) Curve data describing the location of the plasma boundary
|
||||
/// and location of the limiter.
|
||||
///
|
||||
/// 4) A handful of individual data values specifiying things like
|
||||
/// the total plasma current and the location of the magnetic
|
||||
/// axis.
|
||||
///
|
||||
/// The interpolation scheme is described in "A Method of Bivariate
|
||||
/// Interpolation and Smooth Surface Fitting Based on Local
|
||||
/// Procedures" by Hiroshi Akima and published in the Communications
|
||||
/// of the ACM, Numerical Mathematics, Volume 17, Number 1, January
|
||||
/// 1974.
|
||||
class G_EQDSK_Data
|
||||
{
|
||||
public:
|
||||
G_EQDSK_Data(std::istream &is, int logging = 0);
|
||||
|
||||
// Number of points in radial direction
|
||||
int GetNumPtsR() const { return NW_; }
|
||||
|
||||
// Number of points in z direction
|
||||
int GetNumPtsZ() const { return NH_; }
|
||||
|
||||
// Width of domain in radial dimension (in meters)
|
||||
real_t GetRExtent() const { return RDIM_; }
|
||||
|
||||
// Height of domain in z dimension (in meters)
|
||||
real_t GetZExtent() const { return ZDIM_; }
|
||||
|
||||
// Radial coordinate at innermost edge of domain (in meters)
|
||||
real_t GetRMin() const { return RLEFT_; }
|
||||
|
||||
// Z coordinate of the middle of the domain (in meters)
|
||||
real_t GetZMid() const { return ZMID_; }
|
||||
|
||||
// R coordinate of the magnetic axis (in meters)
|
||||
real_t GetRMagAxis() const { return RMAXIS_; }
|
||||
|
||||
// Z coordinate of the magnetic axis (in meters)
|
||||
real_t GetZMagAxis() const { return ZMAXIS_; }
|
||||
|
||||
// Value of poloidal flux at the magnetic axis (in Weber / rad)
|
||||
real_t GetPsiMagAxis() const {return SIMAG_; }
|
||||
|
||||
// Value of poloidal flux at the plasma boundary (in Weber / rad)
|
||||
real_t GetPsiBdry() const {return SIBRY_; }
|
||||
|
||||
// Value of plasma current (in Ampere)
|
||||
real_t GetPlasmaCurrent() const {return CURRENT_; }
|
||||
|
||||
// Values of poloidal flux (in Weber / rad) on the full grid in a
|
||||
// flattened array with z-direction cycling the fastest
|
||||
std::vector<real_t> & GetPsi() { return PSIRZ_ ;}
|
||||
|
||||
// Print a text block to the output stream containing basic
|
||||
// information about the domain and the fields defined in the eqdsk
|
||||
// file.
|
||||
void PrintInfo(std::ostream &out = std::cout) const;
|
||||
|
||||
// Create a GnuPlot input file and associated data file for
|
||||
// visualizing the fields stored in the eqdsk file.
|
||||
void DumpGnuPlotData(const std::string &file) const;
|
||||
|
||||
// In the following interpolation functions the Vector argument rz
|
||||
// is a two component vector containing first the radial coordinate
|
||||
// and nex the z coordinate both expressed in meters.
|
||||
|
||||
// Interpolate the toroidal field function, F(Psi(rz) / SIMAG)
|
||||
// (in Tesla meters), at the point rz
|
||||
real_t InterpFPolRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the pressure, P(Psi(rz) / SIMAG) (in N / m^2), at the
|
||||
// point rz
|
||||
real_t InterpPresRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the function, F(Psi(rz) / SIMAG) * F'(Psi / SIMAG)
|
||||
// (in (m T)^2 / (Weber / rad)), at the point rz
|
||||
real_t InterpFFPrimeRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the function, P'(Psi(rz) / SIMAG)
|
||||
// (in (N / m^2) / (Weber / rad)), at the point rz
|
||||
real_t InterpPPrimeRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the poloidal flux function, Psi(rz) (in Weber / rad), at
|
||||
// the point rz
|
||||
real_t InterpPsiRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the safety factor, q(Psi(rz) / SIMAG), at the point rz
|
||||
real_t InterpQRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the toroidal magnetic fleid (in Tesla) at the
|
||||
// point rz
|
||||
// B_T = F(Psi(rz) / SIMAG) / r
|
||||
real_t InterpBTorRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the toroidal current density (in Ampere / m^2) at
|
||||
// the point rz
|
||||
// J_T = r P'((Psi(rz) / SIMAG) + FF'(Psi(rz) / SIMAG) / (r mu0)
|
||||
real_t InterpJTorRZ(const Vector &rz);
|
||||
|
||||
// Interpolate the rotated gradient of Psi (in Tesla) at the
|
||||
// point rz
|
||||
// nxdp = (n x Grad Psi(rz))
|
||||
// where n is the unit vector in the toroidal direction
|
||||
void InterpNxGradPsiRZ(const Vector &rz, Vector &nxdp);
|
||||
|
||||
// Interpolate the poloidal magnetic field (in Tesla) at the
|
||||
// point rz
|
||||
// B_P = (n x Grad Psi(rz)) / r
|
||||
// where n is the unit vector in the toroidal direction
|
||||
void InterpBPolRZ(const Vector &rz, Vector &b);
|
||||
|
||||
int GetNumBoundaryPts() const { return NBBBS_; }
|
||||
const std::vector<real_t> & GetBoundaryRVals() const { return RBBBS_; }
|
||||
const std::vector<real_t> & GetBoundaryZVals() const { return ZBBBS_; }
|
||||
|
||||
int GetNumLimiterPts() const { return LIMITR_; }
|
||||
const std::vector<real_t> & GetLimiterRVals() const { return RLIM_; }
|
||||
const std::vector<real_t> & GetLimiterZVals() const { return ZLIM_; }
|
||||
|
||||
private:
|
||||
class ShiftedVector;
|
||||
class ShiftedDenseMatrix;
|
||||
class ExtendedDenseMatrix;
|
||||
|
||||
enum FieldType {FPOL, PRES, FFPRIM, PPRIME, PSIRZ, QPSI/*, BTOR*/};
|
||||
|
||||
int logging_;
|
||||
int init_flag_;
|
||||
inline bool checkFlag(int flag) { return (init_flag_ >> flag) & 1; }
|
||||
inline void setFlag(int flag) { init_flag_ |= (1 << flag); }
|
||||
inline void clearFlag(int flag) { init_flag_ &= ~(1 << flag); }
|
||||
|
||||
void checkPsiBoundary();
|
||||
|
||||
void initInterpPsi(const std::vector<real_t> &v,
|
||||
std::vector<real_t> &t);
|
||||
void initInterpRZ(const std::vector<real_t> &v,
|
||||
ShiftedDenseMatrix &c,
|
||||
ShiftedDenseMatrix &d,
|
||||
ShiftedDenseMatrix &e);
|
||||
|
||||
real_t interpRZ(const Vector &rz,
|
||||
const std::vector<real_t> &v,
|
||||
const ShiftedDenseMatrix &c,
|
||||
const ShiftedDenseMatrix &d,
|
||||
const ShiftedDenseMatrix &e);
|
||||
void interpNxGradRZ(const Vector &rz,
|
||||
const std::vector<real_t> &v,
|
||||
const ShiftedDenseMatrix &c,
|
||||
const ShiftedDenseMatrix &d,
|
||||
const ShiftedDenseMatrix &e,
|
||||
Vector &b);
|
||||
real_t interpPsi(real_t psi, const std::vector<real_t> &v,
|
||||
const std::vector<real_t> &t);
|
||||
|
||||
/// The following variable names are taken from the C-Mod Wiki at
|
||||
/// https://cmodwiki.psfc.mit.edu/index.php/G_EQDSK
|
||||
|
||||
std::vector<std::string> CASE_; // Identification character string
|
||||
|
||||
int NW_; // Number of horizontal R grid points
|
||||
int NH_; // Number of vertical Z grid points
|
||||
|
||||
real_t RDIM_; // Horizontal dimension in meter of computational box
|
||||
real_t ZDIM_; // Vertical dimension in meter of computational box
|
||||
real_t RLEFT_; // Minimum R in meter of rectangular computational box
|
||||
real_t ZMID_; // Z of center of computational box in meter
|
||||
real_t RMAXIS_; // R of magnetic axis in meter
|
||||
real_t ZMAXIS_; // Z of magnetic axis in meter
|
||||
real_t SIMAG_; // poloidal flux at magnetic axis in Weber /rad
|
||||
real_t SIBRY_; // poloidal flux at the plasma boundary in Weber /rad
|
||||
real_t RCENTR_; // R in meter of vacuum toroidal magnetic field BCENTR
|
||||
real_t BCENTR_; // Vacuum toroidal magnetic field in Tesla at RCENTR
|
||||
real_t CURRENT_; // Plasma current in Ampere
|
||||
|
||||
// Poloidal current function in m-T, F = RBT on flux grid
|
||||
std::vector<real_t> FPOL_;
|
||||
|
||||
// Plasma pressure in nt / m^2 on uniform flux grid
|
||||
std::vector<real_t> PRES_;
|
||||
|
||||
// FF’(ψ) in (mT)^2 / (Weber /rad) on uniform flux grid
|
||||
std::vector<real_t> FFPRIM_;
|
||||
|
||||
// P’(ψ) in (nt /m^2) / (Weber /rad) on uniform flux grid
|
||||
std::vector<real_t> PPRIME_;
|
||||
|
||||
// Poloidal flux in Weber / rad on the rectangular grid points
|
||||
std::vector<real_t> PSIRZ_;
|
||||
|
||||
// q values on uniform flux grid from axis to boundary
|
||||
std::vector<real_t> QPSI_;
|
||||
|
||||
int NBBBS_; // Number of boundary points
|
||||
std::vector<real_t> RBBBS_; // R of boundary points in meter
|
||||
std::vector<real_t> ZBBBS_; // Z of boundary points in meter
|
||||
|
||||
int LIMITR_; // Number of limiter points
|
||||
std::vector<real_t> RLIM_; // R of surrounding limiter contour in meter
|
||||
std::vector<real_t> ZLIM_; // Z of surrounding limiter contour in meter
|
||||
|
||||
class ShiftedVector : public Vector
|
||||
{
|
||||
private:
|
||||
int si_;
|
||||
public:
|
||||
ShiftedVector()
|
||||
: si_(0) {}
|
||||
|
||||
ShiftedVector(int s, int si)
|
||||
: Vector(s+2*si), si_(si) {}
|
||||
|
||||
void SetShift(int si) { si_ = si; }
|
||||
|
||||
ShiftedVector &operator=(real_t c)
|
||||
{ Vector::operator=(c); return *this; }
|
||||
|
||||
inline real_t &operator()(int i)
|
||||
{ return Vector::operator()(i + si_); }
|
||||
|
||||
inline const real_t &operator()(int i) const
|
||||
{ return Vector::operator()(i + si_); }
|
||||
};
|
||||
|
||||
class ShiftedDenseMatrix : public DenseMatrix
|
||||
{
|
||||
private:
|
||||
int si_, sj_;
|
||||
public:
|
||||
ShiftedDenseMatrix()
|
||||
: si_(0), sj_(0) {}
|
||||
|
||||
ShiftedDenseMatrix(int m, int n, int si, int sj)
|
||||
: DenseMatrix(m+2*si, n+2*sj), si_(si), sj_(sj) {}
|
||||
|
||||
void SetShifts(int si, int sj) { si_ = si; sj_ = sj; }
|
||||
|
||||
ShiftedDenseMatrix &operator=(real_t c)
|
||||
{ DenseMatrix::operator=(c); return *this; }
|
||||
|
||||
inline real_t &operator()(int i, int j)
|
||||
{ return DenseMatrix::operator()(i + si_, j + sj_); }
|
||||
|
||||
inline const real_t &operator()(int i, int j) const
|
||||
{ return DenseMatrix::operator()(i + si_, j + sj_); }
|
||||
};
|
||||
|
||||
class ExtendedDenseMatrix
|
||||
{
|
||||
private:
|
||||
int m_, n_;
|
||||
const real_t *C_;
|
||||
DenseMatrix N_;
|
||||
DenseMatrix S_;
|
||||
DenseMatrix E_;
|
||||
DenseMatrix W_;
|
||||
real_t SW_, SE_, NW_, NE_, DUMMY_;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
ExtendedDenseMatrix(const real_t *C, int m, int n)
|
||||
: m_(m), n_(n), C_(C),
|
||||
N_(2, n), S_(2, n),
|
||||
E_(m, 2), W_(m, 2),
|
||||
SW_(0.0), SE_(0.0), NW_(0.0), NE_(0.0), DUMMY_(0.0)
|
||||
{ N_ = 0.0; S_ = 0.0; E_ = 0.0; W_ = 0.0; init(); }
|
||||
|
||||
const real_t &operator()(int i, int j) const
|
||||
{
|
||||
if (i >= 0 && i < m_ && j >= 0 && j < n_)
|
||||
{
|
||||
return C_[n_ * i + j];
|
||||
}
|
||||
else if (i >= 0 && i < m_)
|
||||
{
|
||||
if (j < 0)
|
||||
{
|
||||
return W_(i, j + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_(i, j - n_);
|
||||
}
|
||||
}
|
||||
else if (j >= 0 && j < n_)
|
||||
{
|
||||
if (i < 0)
|
||||
{
|
||||
return S_(i + 2, j);
|
||||
}
|
||||
else
|
||||
{
|
||||
return N_(i - m_, j);
|
||||
}
|
||||
}
|
||||
else if (i == -1 && j == -1)
|
||||
{
|
||||
return SW_;
|
||||
}
|
||||
else if (i == -1 && j == n_)
|
||||
{
|
||||
return SE_;
|
||||
}
|
||||
else if (i == m_ && j == -1)
|
||||
{
|
||||
return NW_;
|
||||
}
|
||||
else if (i == m_ && j == n_)
|
||||
{
|
||||
return NE_;
|
||||
}
|
||||
return DUMMY_;
|
||||
}
|
||||
};
|
||||
|
||||
// Divided differences for Akima's interpolation method
|
||||
real_t dr_, dz_, dpsi_;
|
||||
|
||||
std::vector<real_t> FPOL_t_;
|
||||
std::vector<real_t> PRES_t_;
|
||||
std::vector<real_t> FFPRIM_t_;
|
||||
std::vector<real_t> PPRIME_t_;
|
||||
ShiftedDenseMatrix PSIRZ_c_;
|
||||
ShiftedDenseMatrix PSIRZ_d_;
|
||||
ShiftedDenseMatrix PSIRZ_e_;
|
||||
std::vector<real_t> QPSI_t_;
|
||||
};
|
||||
|
||||
class G_EQDSK_Psi_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_Psi_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpPsiRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_FPol_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_FPol_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpFPolRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_Pres_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_Pres_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpPresRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_Q_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_Q_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpQRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_BTor_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_BTor_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpBTorRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_JTor_Coefficient : public Coefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_JTor_Coefficient(G_EQDSK_Data &g_eqdsk) : eqdsk(g_eqdsk) {}
|
||||
|
||||
real_t Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
return eqdsk.InterpJTorRZ(transip);
|
||||
}
|
||||
};
|
||||
|
||||
class G_EQDSK_NxGradPsi_Coefficient : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_NxGradPsi_Coefficient(G_EQDSK_Data &g_eqdsk)
|
||||
: VectorCoefficient(2), eqdsk(g_eqdsk) {}
|
||||
|
||||
void Eval(Vector &b, ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
eqdsk.InterpNxGradPsiRZ(transip, b);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class G_EQDSK_BPol_Coefficient : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_BPol_Coefficient(G_EQDSK_Data &g_eqdsk)
|
||||
: VectorCoefficient(2), eqdsk(g_eqdsk) {}
|
||||
|
||||
void Eval(Vector &b, ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
eqdsk.InterpBPolRZ(transip, b);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class G_EQDSK_BField_VecCoefficient : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
G_EQDSK_Data &eqdsk;
|
||||
bool unit_;
|
||||
|
||||
public:
|
||||
|
||||
G_EQDSK_BField_VecCoefficient(G_EQDSK_Data &g_eqdsk, bool unit)
|
||||
: VectorCoefficient(3), eqdsk(g_eqdsk), unit_(unit) {}
|
||||
|
||||
void Eval(Vector &V, ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
V.SetSize(3);
|
||||
Vector b;
|
||||
b.SetSize(2);
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
eqdsk.InterpBPolRZ(transip, b);
|
||||
real_t btor = eqdsk.InterpBTorRZ(transip);
|
||||
|
||||
V[0] = b[0];
|
||||
V[1] = b[1];
|
||||
V[2] = btor;
|
||||
|
||||
if ( unit_ )
|
||||
{
|
||||
real_t bmag = sqrt(V * V);
|
||||
V /= bmag;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace plasma
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_G_EQDSK_DATA_HPP
|
||||
@@ -1,361 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "../common/fem_extras.hpp"
|
||||
#include "g_eqdsk_data.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
using namespace mfem::common;
|
||||
using namespace mfem::plasma;
|
||||
|
||||
void ShiftMesh(real_t x0, real_t y0, Mesh &mesh);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *eqdsk_file = "";
|
||||
const char *mesh_file = "";
|
||||
|
||||
int order = 1;
|
||||
bool visualization = true;
|
||||
bool visit = false;
|
||||
bool paraview = false;
|
||||
bool binary = false;
|
||||
|
||||
int precision = 8;
|
||||
cout.precision(precision);
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&eqdsk_file, "-eqdsk", "--eqdsk-file",
|
||||
"G EQDSK input file.");
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&visit, "-visit", "--visit-datafiles", "-no-visit",
|
||||
"--no-visit-datafiles",
|
||||
"Save data files for VisIt (visit.llnl.gov) visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview-datafiles", "-no-paraview",
|
||||
"--no-paraview-datafiles",
|
||||
"Save data files for ParaView (paraview.org) visualization.");
|
||||
args.AddOption(&binary, "-binary", "--binary-datafiles", "-ascii",
|
||||
"--ascii-datafiles",
|
||||
"Use binary (Sidre) or ascii format for VisIt data files.");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
args.PrintOptions(cout);
|
||||
|
||||
named_ifgzstream ieqdsk(eqdsk_file);
|
||||
if (!ieqdsk)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
G_EQDSK_Data eqdsk(ieqdsk);
|
||||
eqdsk.PrintInfo();
|
||||
eqdsk.DumpGnuPlotData("gnuplot_eqdsk");
|
||||
|
||||
G_EQDSK_Psi_Coefficient psiCoef(eqdsk);
|
||||
G_EQDSK_FPol_Coefficient fPolCoef(eqdsk);
|
||||
G_EQDSK_Pres_Coefficient presCoef(eqdsk);
|
||||
G_EQDSK_Q_Coefficient qCoef(eqdsk);
|
||||
G_EQDSK_NxGradPsi_Coefficient nxGradPsiCoef(eqdsk);
|
||||
G_EQDSK_BPol_Coefficient BPolCoef(eqdsk);
|
||||
G_EQDSK_BTor_Coefficient BTorCoef(eqdsk);
|
||||
G_EQDSK_JTor_Coefficient JTorCoef(eqdsk);
|
||||
|
||||
Mesh mesh;
|
||||
if (strcmp(mesh_file, "") == 0)
|
||||
{
|
||||
mesh = Mesh::MakeCartesian2D(eqdsk.GetNumPtsR(),
|
||||
eqdsk.GetNumPtsZ(),
|
||||
Element::QUADRILATERAL,
|
||||
false,
|
||||
eqdsk.GetRExtent(),
|
||||
eqdsk.GetZExtent());
|
||||
|
||||
real_t zmin = eqdsk.GetZMid() - eqdsk.GetZExtent()/2.0;
|
||||
ShiftMesh(eqdsk.GetRMin(), zmin, mesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
mesh = Mesh(mesh_file);
|
||||
}
|
||||
|
||||
H1_FECollection fec_h1(order, 2);
|
||||
FiniteElementSpace fes_h1(&mesh, &fec_h1);
|
||||
FiniteElementSpace fes_h1v(&mesh, &fec_h1, 2);
|
||||
|
||||
GridFunction psi(&fes_h1);
|
||||
psi.ProjectCoefficient(psiCoef);
|
||||
|
||||
GridFunction nxGradPsi(&fes_h1v);
|
||||
nxGradPsi.ProjectCoefficient(nxGradPsiCoef);
|
||||
|
||||
GridFunction fPol(&fes_h1);
|
||||
fPol.ProjectCoefficient(fPolCoef);
|
||||
|
||||
GridFunction pres(&fes_h1);
|
||||
pres.ProjectCoefficient(presCoef);
|
||||
|
||||
GridFunction q(&fes_h1);
|
||||
q.ProjectCoefficient(qCoef);
|
||||
|
||||
GridFunction BPol(&fes_h1v);
|
||||
BPol.ProjectCoefficient(BPolCoef);
|
||||
|
||||
GridFunction BTor(&fes_h1);
|
||||
BTor.ProjectCoefficient(BTorCoef);
|
||||
|
||||
GridFunction JTor(&fes_h1);
|
||||
JTor.ProjectCoefficient(JTorCoef);
|
||||
|
||||
int xPos = 0, yPos = 0, w = 400, h = 300, b = 30, m = 65;
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
|
||||
char skeys[] = "mmaaAcjR";
|
||||
char vkeys[] = "vvvmmaaAcjR";
|
||||
|
||||
socketstream sock_fpol;
|
||||
VisualizeField(sock_fpol, vishost, visport, fPol, "Current Flux",
|
||||
xPos, yPos, w, h, skeys);
|
||||
xPos += w;
|
||||
|
||||
socketstream sock_pres;
|
||||
VisualizeField(sock_pres, vishost, visport, pres, "Pressure",
|
||||
xPos, yPos, w, h, "mmaaAcjR");
|
||||
xPos += w;
|
||||
|
||||
socketstream sock_psi;
|
||||
VisualizeField(sock_psi, vishost, visport, psi, "Poloidal Flux",
|
||||
xPos, yPos, w, h, "mmaaAcjR");
|
||||
xPos += w;
|
||||
|
||||
socketstream sock_q;
|
||||
VisualizeField(sock_q, vishost, visport, q, "Safety Factor (q)",
|
||||
xPos, yPos, w, h, "mmaaAcjR");
|
||||
xPos = 0; yPos += h + b + m;
|
||||
|
||||
socketstream sock_bpol;
|
||||
VisualizeField(sock_bpol, vishost, visport, BPol, "Poloidal B",
|
||||
xPos, yPos, w, h, vkeys, true);
|
||||
xPos += w;
|
||||
|
||||
socketstream sock_btor;
|
||||
VisualizeField(sock_btor, vishost, visport, BTor, "Toroidal B",
|
||||
xPos, yPos, w, h, "mmaaAcjR");
|
||||
xPos += w;
|
||||
|
||||
socketstream sock_jtor;
|
||||
VisualizeField(sock_jtor, vishost, visport, JTor, "Toroidal J",
|
||||
xPos, yPos, w, h, "mmaaAcjR");
|
||||
xPos = 0; yPos += h + b;
|
||||
}
|
||||
|
||||
Array<DataCollection*> dc(2); dc = NULL;
|
||||
|
||||
if (visit)
|
||||
{
|
||||
#ifdef MFEM_USE_SIDRE
|
||||
if (binary)
|
||||
{
|
||||
dc[0] = new SidreDataCollection("G_EQDSK_Viewer", &mesh);
|
||||
}
|
||||
else
|
||||
#else
|
||||
{
|
||||
dc[0] = new VisItDataCollection("G_EQDSK_Viewer", &mesh);
|
||||
dc[0]->SetPrecision(precision);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (paraview)
|
||||
{
|
||||
ParaViewDataCollection *pd =
|
||||
new ParaViewDataCollection("G_EQDSK_Viewer", &mesh);
|
||||
pd->SetPrefixPath("ParaView");
|
||||
pd->SetHighOrderOutput(true);
|
||||
if (binary) { pd->SetDataFormat(VTKFormat::BINARY); }
|
||||
dc[1] = pd;
|
||||
}
|
||||
|
||||
for (int i=0; i<2; i++)
|
||||
{
|
||||
if (dc[i] == NULL) { continue; }
|
||||
|
||||
dc[i]->SetCycle(0);
|
||||
dc[i]->SetTime(0.0);
|
||||
|
||||
dc[i]->RegisterField("Psi", &psi);
|
||||
dc[i]->RegisterField("FPol", &fPol);
|
||||
dc[i]->RegisterField("Pres", &pres);
|
||||
dc[i]->RegisterField("Q", &q);
|
||||
dc[i]->RegisterField("nxGradPsi", &nxGradPsi);
|
||||
dc[i]->RegisterField("BPol", &BPol);
|
||||
dc[i]->RegisterField("BTor", &BTor);
|
||||
dc[i]->RegisterField("JTor", &JTor);
|
||||
|
||||
dc[i]->Save();
|
||||
}
|
||||
delete dc[0];
|
||||
delete dc[1];
|
||||
|
||||
{
|
||||
int nbdr = eqdsk.GetNumBoundaryPts();
|
||||
const vector<real_t> &r = eqdsk.GetBoundaryRVals();
|
||||
const vector<real_t> &z = eqdsk.GetBoundaryZVals();
|
||||
|
||||
Mesh bdr(1, nbdr, nbdr-1, 2, 2);
|
||||
|
||||
for (int i=0; i<nbdr; i++)
|
||||
{
|
||||
bdr.AddVertex(r[i], z[i]);
|
||||
}
|
||||
|
||||
for (int i=1; i<nbdr; i++)
|
||||
{
|
||||
bdr.AddSegment(i-1, i);
|
||||
}
|
||||
|
||||
bdr.AddBdrPoint(0);
|
||||
bdr.AddBdrPoint(nbdr-1);
|
||||
|
||||
bdr.FinalizeMesh();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
socketstream sock;
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
VisualizeMesh(sock, vishost, visport, bdr, "Plasma Boundary",
|
||||
xPos, yPos, w, h, "aaA");
|
||||
xPos += w;
|
||||
}
|
||||
if (visit)
|
||||
{
|
||||
#ifdef MFEM_USE_SIDRE
|
||||
if (binary)
|
||||
{
|
||||
SidreDataCollection sd("G_EQDSK_Viewer_Boundary", &bdr);
|
||||
sd.Save();
|
||||
}
|
||||
else
|
||||
#else
|
||||
{
|
||||
VisItDataCollection vd("G_EQDSK_Viewer_Boundary", &bdr);
|
||||
vd.SetPrecision(precision);
|
||||
vd.Save();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (paraview)
|
||||
{
|
||||
ParaViewDataCollection pd("G_EQDSK_Viewer_Boundary", &bdr);
|
||||
pd.SetPrefixPath("ParaView");
|
||||
pd.SetHighOrderOutput(true);
|
||||
if (binary) { pd.SetDataFormat(VTKFormat::BINARY); }
|
||||
pd.Save();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int nlim = eqdsk.GetNumLimiterPts();
|
||||
const vector<real_t> &r = eqdsk.GetLimiterRVals();
|
||||
const vector<real_t> &z = eqdsk.GetLimiterZVals();
|
||||
|
||||
Mesh lim(1, nlim, nlim-1, 2, 2);
|
||||
|
||||
for (int i=0; i<nlim; i++)
|
||||
{
|
||||
lim.AddVertex(r[i], z[i]);
|
||||
}
|
||||
|
||||
for (int i=1; i<nlim; i++)
|
||||
{
|
||||
lim.AddSegment(i-1, i);
|
||||
}
|
||||
|
||||
lim.AddBdrPoint(0);
|
||||
lim.AddBdrPoint(nlim-1);
|
||||
|
||||
lim.FinalizeMesh();
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
socketstream sock;
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
VisualizeMesh(sock, vishost, visport, lim, "Limiter",
|
||||
xPos, yPos, w, h, "aaA");
|
||||
xPos += w;
|
||||
}
|
||||
if (visit)
|
||||
{
|
||||
#ifdef MFEM_USE_SIDRE
|
||||
if (binary)
|
||||
{
|
||||
SidreDataCollection sd("G_EQDSK_Viewer_Limiter", &lim);
|
||||
sd.Save();
|
||||
}
|
||||
else
|
||||
#else
|
||||
{
|
||||
VisItDataCollection vd("G_EQDSK_Viewer_Limiter", &lim);
|
||||
vd.SetPrecision(precision);
|
||||
vd.Save();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (paraview)
|
||||
{
|
||||
ParaViewDataCollection pd("G_EQDSK_Viewer_Limiter", &lim);
|
||||
pd.SetPrefixPath("ParaView");
|
||||
pd.SetHighOrderOutput(true);
|
||||
if (binary) { pd.SetDataFormat(VTKFormat::BINARY); }
|
||||
pd.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShiftMesh(real_t x0, real_t y0, Mesh &mesh)
|
||||
{
|
||||
class ShiftCoef : public VectorCoefficient
|
||||
{
|
||||
private:
|
||||
real_t xs_, ys_;
|
||||
|
||||
public:
|
||||
ShiftCoef(real_t xs, real_t ys) : VectorCoefficient(2), xs_(xs), ys_(ys) {}
|
||||
|
||||
void Eval(Vector &v, ElementTransformation &T, const IntegrationPoint &ip)
|
||||
{
|
||||
T.Transform(ip, v);
|
||||
v[0] += xs_;
|
||||
v[1] += ys_;
|
||||
}
|
||||
};
|
||||
|
||||
ShiftCoef shift(x0, y0);
|
||||
mesh.Transform(shift);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
SEQ_MINIAPPS = g_eqdsk_viewer
|
||||
SEQ_MINIAPPS =
|
||||
PAR_MINIAPPS =
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
@@ -39,14 +39,11 @@ SUBDIRS_TPRINT = $(addsuffix /test-print,$(PLASMA_SUBDIRS))
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
.PRECIOUS: %.o
|
||||
|
||||
COMMON_O = g_eqdsk_data.o
|
||||
|
||||
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
|
||||
|
||||
# If MFEM_SHARED is set, add the ../common rpath
|
||||
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
|
||||
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
|
||||
$(MFEM_BUILD_DIR)/miniapps/common))
|
||||
$(MFEM_XLINKER)-rpath,$(abspath $(MFEM_BUILD_DIR)/miniapps/common))
|
||||
|
||||
# Remove built-in rules
|
||||
%: %.cpp
|
||||
@@ -56,22 +53,15 @@ all: $(MINIAPPS) $(SUBDIRS_ALL)
|
||||
|
||||
.PHONY: $(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_TEST_NOCLEAN) \
|
||||
$(SUBDIRS_CLEAN) $(SUBDIRS_TPRINT)
|
||||
|
||||
# Rules for building the miniapps
|
||||
%: $(SRC)%.cpp $(COMMON_O) $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(COMMON_O) $(COMMON_LIB) \
|
||||
$(MFEM_LIBS)
|
||||
|
||||
# Rules for compiling miniapp dependencies
|
||||
$(COMMON_O) $(addsuffix _solver.o,$(MINIAPPS)): \
|
||||
%.o: $(SRC)%.cpp $(SRC)%.hpp $(CONFIG_MK)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $(<) -o $(@)
|
||||
|
||||
$(SUBDIRS_ALL) $(SUBDIRS_TEST) $(SUBDIRS_TEST_NOCLEAN) $(SUBDIRS_CLEAN):
|
||||
$(MAKE) -C $(@D) $(@F)
|
||||
$(SUBDIRS_TPRINT):
|
||||
@$(MAKE) -C $(@D) $(@F)
|
||||
|
||||
# Rules for building the miniapps
|
||||
%: $(SRC)%.cpp $(MFEM_LIB_FILE) $(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) $< -o $@ $(COMMON_LIB) $(MFEM_LIBS)
|
||||
|
||||
# Rule for building lib-common
|
||||
lib-common:
|
||||
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
|
||||
@@ -98,4 +88,3 @@ clean-build:
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf G_EQDSK_Viewer_* gnuplot_eqdsk.*
|
||||
|
||||
@@ -59,3 +59,4 @@ typedef std::complex<real_t> complex_t;
|
||||
} // namespace mfem
|
||||
|
||||
#endif // MFEM_PLASMA_HPP
|
||||
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
SGRRATEI 01/01/2025 #1 0ms 3 20 40
|
||||
1.000000000E+00 2.000000000E+00 1.000000000E+00 5.000000000E-01 0.000000000E+00
|
||||
1.105630563E+00 3.500092352E-02 2.347299201E+01 0.000000000E+00 1.000000000E+00
|
||||
4.093014437E+05 2.347299201E+01 0.000000000E+00 1.105630563E+00 0.000000000E+00
|
||||
3.500092352E-02 0.000000000E+00 0.000000000E+00 0.000000000E+00 0.000000000E+00
|
||||
9.738254114E-01 9.765403940E-01 9.791016917E-01 9.815105078E-01 9.837679622E-01
|
||||
9.858750948E-01 9.878328675E-01 9.896421668E-01 9.913038055E-01 9.928185251E-01
|
||||
9.941869971E-01 9.954098248E-01 9.964875442E-01 9.974206257E-01 9.982094750E-01
|
||||
9.988544337E-01 9.993557806E-01 9.997137315E-01 9.999284406E-01 1.000000000E+00
|
||||
5.710133214E+04 5.124884104E+04 4.571270080E+04 4.049291144E+04 3.558947294E+04
|
||||
3.100238532E+04 2.673164857E+04 2.277726268E+04 1.913922767E+04 1.581754353E+04
|
||||
1.281221026E+04 1.012322786E+04 7.750596330E+03 5.694315671E+03 3.954385882E+03
|
||||
2.530806965E+03 1.423578918E+03 6.327017412E+02 1.581754353E+02 0.000000000E+00
|
||||
-5.305270078E-02-5.012071900E-02-4.721240459E-02-4.432615176E-02-4.146040916E-02
|
||||
-3.861367525E-02-3.578449395E-02-3.297145057E-02-3.017316804E-02-2.738830324E-02
|
||||
-2.461554357E-02-2.185360373E-02-1.910122258E-02-1.635716013E-02-1.362019471E-02
|
||||
-1.088912014E-02-8.162743045E-03-5.439880231E-03-2.719356078E-03-0.000000000E+00
|
||||
1.142026643E+05 1.081919977E+05 1.021813312E+05 9.617066466E+04 9.015999812E+04
|
||||
8.414933158E+04 7.813866504E+04 7.212799850E+04 6.611733196E+04 6.010666541E+04
|
||||
5.409599887E+04 4.808533233E+04 4.207466579E+04 3.606399925E+04 3.005333271E+04
|
||||
2.404266617E+04 1.803199962E+04 1.202133308E+04 6.010666541E+03 0.000000000E+00
|
||||
1.177939031E+00 7.114757766E-01 3.462248040E-01 5.354204611E-02-1.920202929E-01
|
||||
-4.129262653E-01-6.282055905E-01-8.521376374E-01-1.092012071E+00-1.345131509E+00
|
||||
-1.595544748E+00-1.811409078E+00-1.944310502E+00-1.932184779E+00-1.707470864E+00
|
||||
-1.211535856E+00-4.150082925E-01 6.586307082E-01 1.911775275E+00 3.162156344E+00
|
||||
1.061937089E+00 6.633173301E-01 3.492668082E-01 9.315032283E-02-1.304531101E-01
|
||||
-3.458479130E-01-5.756143723E-01-8.390126101E-01-1.149238113E+00-1.509585272E+00
|
||||
-1.908915919E+00-2.317294334E+00-2.683185289E+00-2.934087898E+00-2.982678795E+00
|
||||
-2.740175983E+00-2.137415484E+00-1.151880382E+00 1.642429581E-01 1.663372295E+00
|
||||
8.051939480E-01 5.069112372E-01 2.743284476E-01 8.370657885E-02-8.974129464E-02
|
||||
-2.719121972E-01-4.891295045E-01-7.663397670E-01-1.123909079E+00-1.572938455E+00
|
||||
-2.109368849E+00-2.707664515E+00-3.315512301E+00-3.851636238E+00-4.209280562E+00
|
||||
-4.267839746E+00-3.914144066E+00-3.072748961E+00-1.741194852E+00-2.206373816E-02
|
||||
4.386618733E-01 2.671699153E-01 1.423176570E-01 4.390607362E-02-5.171653318E-02
|
||||
-1.717821368E-01-3.464493081E-01-6.068989469E-01-9.817630445E-01-1.491645200E+00
|
||||
-2.141844861E+00-2.913964020E+00-3.757840297E+00-4.586112160E+00-5.274458926E+00
|
||||
-5.670818478E+00-5.616224816E+00-4.977901073E+00-3.691687034E+00-1.806058709E+00
|
||||
-4.298567177E-03-2.885908269E-02-2.408384075E-02-6.214900590E-03 2.635241343E-03
|
||||
-2.582736598E-02-1.255823084E-01-3.344252645E-01-6.901634068E-01-1.224454514E+00
|
||||
-1.954213674E+00-2.871118150E+00-3.930618618E+00-5.042932053E+00-6.069530696E+00
|
||||
-6.829272879E+00-7.118023483E+00-6.743823605E+00-5.575998604E+00-3.601125638E+00
|
||||
-4.904906367E-01-3.541583261E-01-2.023319275E-01-4.707332712E-02 9.136750994E-02
|
||||
1.839291606E-01 1.929332900E-01 7.375989635E-02-2.212853526E-01-7.362958772E-01
|
||||
-1.501990597E+00-2.523186013E+00-3.764838139E+00-5.139247280E+00-6.498368268E+00
|
||||
-7.636196547E+00-8.306311506E+00-8.258154862E+00-7.291916149E+00-5.325855281E+00
|
||||
-9.891517976E-01-6.836808359E-01-3.717549013E-01-6.118268240E-02 2.299116539E-01
|
||||
4.720201133E-01 6.239925947E-01 6.343426860E-01 4.449799758E-01-1.810539076E-03
|
||||
-7.526144758E-01-1.828479362E+00-3.208038614E+00-4.810814863E+00-6.485007525E+00
|
||||
-8.005508573E+00-9.088448866E+00-9.427424816E+00-8.752906042E+00-6.909813980E+00
|
||||
-1.473771796E+00-9.959343881E-01-5.149915677E-01-3.452799782E-02 4.296819687E-01
|
||||
8.480325882E-01 1.176224437E+00 1.356019748E+00 1.318626308E+00 9.917412651E-01
|
||||
3.110382488E-01-7.637621813E-01-2.229234570E+00-4.017630769E+00-5.979886299E+00
|
||||
-7.878690259E+00-9.399094337E+00-1.018339893E+01-9.893563051E+00-8.297535837E+00
|
||||
-1.923358234E+00-1.274118331E+00-6.190449342E-01 4.241617768E-02 6.970427222E-01
|
||||
1.315504578E+00 1.850755536E+00 2.238061887E+00 2.397821839E+00 2.242420073E+00
|
||||
1.688171532E+00 6.727868194E-01-8.223908342E-01-2.747908855E+00-4.964257479E+00
|
||||
-7.229487499E+00-9.204966355E+00-1.048758220E+01-1.067347645E+01-9.451344740E+00
|
||||
-2.323104633E+00-1.506765900E+00-6.759012096E-01 1.740804302E-01 1.032700577E+00
|
||||
1.871293443E+00 2.640527557E+00 3.269546701E+00 3.668019576E+00 3.732554236E+00
|
||||
3.358812466E+00 2.460076739E+00 9.918161564E-01-1.020108269E+00-3.452453075E+00
|
||||
-6.066340582E+00-8.507319402E+00-1.033357420E+01-1.107925638E+01-1.035282773E+01
|
||||
-2.664471122E+00-1.687890207E+00-6.827027259E-01 3.596274997E-01 1.431550261E+00
|
||||
2.505452940E+00 3.530213458E+00 4.429318046E+00 5.101959709E+00 5.428780921E+00
|
||||
5.283882595E+00 4.554194090E+00 3.166091448E+00 1.117147246E+00-1.491830392E+00
|
||||
-4.432367149E+00-7.341965785E+00-9.747121227E+00-1.112459668E+01-1.100287931E+01
|
||||
-2.944738080E+00-1.816674081E+00-6.415005103E-01 5.931963199E-01 1.882965615E+00
|
||||
3.201616345E+00 4.496734579E+00 5.686676598E+00 6.660570233E+00 7.283188581E+00
|
||||
7.406605934E+00 6.890087547E+00 5.628476275E+00 3.587263544E+00 8.396022394E-01
|
||||
-2.402899635E+00-5.776849067E+00-8.783877585E+00-1.084839190E+01-1.142033969E+01
|
||||
-3.166134203E+00-1.896779380E+00-5.586445387E-01 8.645161131E-01 2.371494866E+00
|
||||
3.937845874E+00 5.510336076E+00 7.002752880E+00 8.294707488E+00 9.235489503E+00
|
||||
9.655166287E+00 9.384741989E+00 8.286038706E+00 6.289838350E+00 3.437717133E+00
|
||||
-8.075321028E-02-3.907350460E+00-7.525051779E+00-1.031106577E+01-1.163935097E+01
|
||||
-3.334669430E+00-1.935377409E+00-4.438947453E-01 1.159817788E+00 2.877890628E+00
|
||||
4.687875792E+00 6.536138946E+00 8.332465883E+00 9.947618768E+00 1.121607806E+01
|
||||
1.194643788E+01 1.194163044E+01 1.103005146E+01 9.106506552E+00 6.178640076E+00
|
||||
2.410438564E+00-1.849670608E+00-6.071264098E+00-9.589395893E+00-1.170564693E+01
|
||||
-3.458817908E+00-1.942017179E+00-3.093519611E-01 1.462951722E+00 3.380383697E+00
|
||||
5.422650509E+00 7.536054524E+00 9.626930107E+00 1.155795906E+01 1.314976842E+01
|
||||
1.419053815E+01 1.445614268E+01 1.374230350E+01 1.190806493E+01 8.926518370E+00
|
||||
4.934346872E+00 2.672349659E-01-4.535068265E+00-8.770225658E+00-1.167206778E+01
|
||||
-3.548196371E+00-1.927451469E+00-1.683142698E-01 1.756611464E+00 3.856096505E+00
|
||||
6.112041329E+00 8.470924349E+00 1.083614428E+01 1.306315655E+01 1.495995902E+01
|
||||
1.629589474E+01 1.682162166E+01 1.630211309E+01 1.456238365E+01 1.154214088E+01
|
||||
7.350954429E+00 2.310587678E+00-3.032682981E+00-7.943532064E+00-1.159364507E+01
|
||||
-3.612369480E+00-1.902532645E+00-3.416086848E-02 2.023562298E+00 4.282487674E+00
|
||||
6.726617299E+00 9.302735925E+00 1.191177809E+01 1.440289942E+01 1.657294315E+01
|
||||
1.817448446E+01 1.893559777E+01 1.859356268E+01 1.694255836E+01 1.389180895E+01
|
||||
9.525810665E+00 4.152947024E+00-1.675532760E+00-7.195361659E+00-1.152263127E+01
|
||||
-3.659888135E+00-1.877272235E+00 8.064666376E-02 2.247781331E+00 4.638723390E+00
|
||||
7.239346930E+00 9.996763752E+00 1.280986971E+01 1.552251082E+01 1.792207710E+01
|
||||
1.974689233E+01 2.070579945E+01 2.051246236E+01 1.893474235E+01 1.585584220E+01
|
||||
1.133888571E+01 5.680950215E+00-5.622075887E-01-6.601153114E+00-1.150384995E+01
|
||||
-3.697632389E+00-1.860132684E+00 1.653751070E-01 2.415430773E+00 4.906883382E+00
|
||||
7.627118007E+00 1.052349470E+01 1.349325702E+01 1.637598974E+01 1.895153030E+01
|
||||
2.094685366E+01 2.205553690E+01 2.197257081E+01 2.044512383E+01 1.733613236E+01
|
||||
1.269240556E+01 6.803013202E+00 2.285826261E-01-6.219933983E+00-1.157071687E+01
|
||||
-3.730491265E+00-1.857589350E+00 2.115959967E-01 2.515606446E+00 5.072927797E+00
|
||||
7.871980905E+00 1.086021634E+01 1.393358738E+01 1.692852212E+01 1.961937366E+01
|
||||
2.172498135E+01 2.292810207E+01 2.291065737E+01 2.140557651E+01 1.826222886E+01
|
||||
1.351712669E+01 7.455453684E+00 6.435576415E-01-6.089813048E+00-1.174223127E+01
|
||||
-3.761371558E+00-1.873968915E+00 2.135078960E-01 2.540827286E+00 5.127374233E+00
|
||||
7.962045089E+00 1.099217427E+01 1.411278363E+01 1.715830588E+01 1.989981072E+01
|
||||
2.205143928E+01 2.328989944E+01 2.329007266E+01 2.177760782E+01 1.859554648E+01
|
||||
1.377662221E+01 7.606612427E+00 6.585296979E-01-6.225093469E+00-1.202116407E+01
|
||||
-3.791490666E+00-1.911540109E+00 1.680110330E-01 2.487256301E+00 5.065659571E+00
|
||||
7.891986670E+00 1.091323759E+01 1.402388427E+01 1.705758364E+01 1.978441808E+01
|
||||
2.191739820E+01 2.313211229E+01 2.310260165E+01 2.155435103E+01 1.833142069E+01
|
||||
1.346929542E+01 7.258694626E+00 2.799266470E-01-6.615212606E+00-1.239358030E+01
|
||||
-3.820878312E+00-1.970807023E+00 7.456425210E-02 2.354666889E+00 4.888186740E+00
|
||||
7.663154519E+00 1.062604784E+01 1.367122044E+01 1.663283261E+01 1.928233088E+01
|
||||
2.133519587E+01 2.247081246E+01 2.236849430E+01 2.076048600E+01 1.749888920E+01
|
||||
1.262799924E+01 6.447217361E+00-4.559222017E-01-7.225580581E+00-1.282973439E+01
|
||||
-3.848991491E+00-2.050936655E+00-6.512725250E-02 2.146188553E+00 4.600080065E+00
|
||||
7.283291332E+00 1.014166289E+01 1.306993852E+01 1.590411969E+01 1.841938220E+01
|
||||
2.033721296E+01 2.134552973E+01 2.113469622E+01 1.945011906E+01 1.615823925E+01
|
||||
1.131731051E+01 5.238120693E+00-1.485673552E+00-8.000251170E+00-1.328627499E+01
|
||||
-3.875338057E+00-2.150242329E+00-2.475329332E-01 1.867881232E+00 4.210692584E+00
|
||||
6.765911862E+00 9.478741185E+00 1.224492114E+01 1.490368573E+01 1.723627585E+01
|
||||
1.897356375E+01 1.981640216E+01 1.947142584E+01 1.770279405E+01 1.439651648E+01
|
||||
9.628673275E+00 3.722766155E+00-2.723810795E+00-8.866225270E+00-1.370959898E+01
|
||||
-3.900007644E+00-2.266644041E+00-4.677614828E-01 1.528196641E+00 3.732923227E+00
|
||||
6.129401538E+00 8.662340621E+00 1.122919771E+01 1.367387342E+01 1.578593608E+01
|
||||
1.730877932E+01 1.796012480E+01 1.746735709E+01 1.561793473E+01 1.232133201E+01
|
||||
7.673774441E+00 2.011195548E+00-4.069078223E+00-9.739068744E+00-1.404010861E+01
|
||||
-3.924023591E+00-2.398035334E+00-7.200067369E-01 1.137387716E+00 3.182410201E+00
|
||||
5.395913565E+00 7.722428677E+00 1.006196670E+01 1.226455371E+01 1.413022949E+01
|
||||
1.541772644E+01 1.586499240E+01 1.522375896E+01 1.330812440E+01 1.005342068E+01
|
||||
5.576636546E+00 2.241444128E-01-5.412036085E+00-1.052943124E+01-1.421705809E+01
|
||||
-3.949454495E+00-2.542502924E+00-9.979222946E-01 7.069235958E-01 2.576669018E+00
|
||||
4.590150437E+00 6.692214307E+00 8.786372669E+00 1.073023468E+01 1.233629223E+01
|
||||
1.338105163E+01 1.362538857E+01 1.284800990E+01 1.089170363E+01 7.718485117E+00
|
||||
3.464998876E+00-1.515610191E+00-6.643185284E+00-1.114998745E+01-1.418363094E+01
|
||||
-3.979256188E+00-2.698367977E+00-1.294887519E+00 2.489584160E-01 1.934239644E+00
|
||||
3.738116641E+00 5.606417678E+00 7.447191213E+00 9.127051556E+00 1.047271535E+01
|
||||
1.128046570E+01 1.133610480E+01 1.044694098E+01 8.485207794E+00 5.438904548E+00
|
||||
1.461602678E+00-3.091944768E+00-7.661071980E+00-1.152229191E+01-1.389187001E+01
|
||||
-4.016850914E+00-2.864044197E+00-1.604146536E+00-2.241112683E-01 1.273898011E+00
|
||||
2.865923368E+00 4.499590437E+00 6.088573689E+00 7.509837123E+00 8.605843241E+00
|
||||
9.194186653E+00 9.086875972E+00 8.120465300E+00 6.196168770E+00 3.325888584E+00
|
||||
-3.240034153E-01-4.403506209E+00-8.379786406E+00-1.158304470E+01-1.330709073E+01
|
||||
-4.065486440E+00-3.037734815E+00-1.918822347E+00-6.999816548E-01 6.139739607E-01
|
||||
1.998714410E+00 3.404587974E+00 4.751991854E+00 5.929458212E+00 6.796423679E+00
|
||||
7.192839193E+00 6.957494890E+00 5.955921640E+00 4.116771010E+00 1.472617199E+00
|
||||
-1.802565272E+00-5.370675409E+00-8.735316260E+00-1.128930792E+01-1.241144279E+01
|
||||
-4.127449814E+00-3.217015136E+00-2.231827841E+00-1.166667513E+00-2.819799411E-02
|
||||
1.159766364E+00 2.351277206E+00 3.474501101E+00 4.430577848E+00 5.096815722E+00
|
||||
5.336068777E+00 5.013819256E+00 4.023501957E+00 2.318783269E+00-5.116971402E-02
|
||||
-2.910644185E+00-5.940889782E+00-8.690299713E+00-1.062228866E+01-1.120634490E+01
|
||||
-4.203235039E+00-3.398366877E+00-2.535712222E+00-1.612632387E+00-6.366850978E-01
|
||||
3.697974838E-01 1.365540530E+00 2.287412293E+00 3.049966071E+00 3.548915381E+00
|
||||
3.670070593E+00 3.304913826E+00 2.373047603E+00 8.500896067E-01-1.202779494E+00
|
||||
-3.614186892E+00-6.091958209E+00-8.236839977E+00-9.589407101E+00-9.713596789E+00
|
||||
-4.290778163E+00-3.576742698E+00-2.822493099E+00-2.026849804E+00-1.197225471E+00
|
||||
-3.535002237E-01 4.686108471E-01 1.215428449E+00 1.815438588E+00 2.182902917E+00
|
||||
2.226163321E+00 1.861484244E+00 1.032396256E+00-2.669763141E-01-1.968150648E+00
|
||||
-3.909918455E+00-5.833148754E+00-7.397184068E+00-8.224491749E+00-7.975065939E+00
|
||||
-4.384875340E+00-3.745242651E+00-3.083530003E+00-2.398830761E+00-1.697378506E+00
|
||||
-9.957099940E-01-3.232539991E-01 2.762663994E-01 7.454546190E-01 1.016853765E+00
|
||||
1.020459654E+00 6.956632448E-01 7.347095482E-03-1.035422001E+00-2.361341617E+00
|
||||
-3.824490342E+00-5.203991097E+00-6.222222620E+00-6.586078401E+00-6.050948439E+00
|
||||
-4.476888583E+00-3.894978023E+00-3.309493489E+00-2.718656353E+00-2.126584605E+00
|
||||
-1.545741319E+00-9.987741727E-01-5.192520663E-01-1.506429331E-01 5.719217068E-02
|
||||
5.460577895E-02-1.978882146E-01-7.168054582E-01-1.481575987E+00-2.422003763E+00
|
||||
-3.411478000E+00-4.270900179E+00-4.787924263E+00-4.753925197E+00-4.016704838E+00
|
||||
-4.554820792E+00-4.015182505E+00-3.490475381E+00-2.977052429E+00-2.476167439E+00
|
||||
-1.995716824E+00-1.551366984E+00-1.166687615E+00-8.718068197E-01-7.000927896E-01
|
||||
-6.825136301E-01-8.396957198E-01-1.172330775E+00-1.651449890E+00-2.211061872E+00
|
||||
-2.746475866E+00-3.121883414E+00-3.189965874E+00-2.823984049E+00-1.958867057E+00
|
||||
-4.603807992E+00-4.093607026E+00-3.616270651E+00-3.165536031E+00-2.739312360E+00
|
||||
-2.340737292E+00-1.978638221E+00-1.667124626E+00-1.423984835E+00-1.267600894E+00
|
||||
-1.212274719E+00-1.262214897E+00-1.404973257E+00-1.605789134E+00-1.804951596E+00
|
||||
-1.920672159E+00-1.859729673E+00-1.536948455E+00-9.021790676E-01 3.000631406E-02
|
||||
-4.607035449E+00-4.117205045E+00-3.676841544E+00-3.276651652E+00-2.911050569E+00
|
||||
-2.578570662E+00-2.281713129E+00-2.026061651E+00-1.818469520E+00-1.664216751E+00
|
||||
-1.563240181E+00-1.505881440E+00-1.469052924E+00-1.414208492E+00-1.288862796E+00
|
||||
-1.033391503E+00-5.941846495E-01 5.731167636E-02 9.025721545E-01 1.856887103E+00
|
||||
-4.547039198E+00-4.073082299E+00-3.662951516E+00-3.304300534E+00-2.988270833E+00
|
||||
-2.709309505E+00-2.464479642E+00-2.252158241E+00-2.070047391E+00-1.912547284E+00
|
||||
-1.767768432E+00-1.614788936E+00-1.422144468E+00-1.148868356E+00-7.495037445E-01
|
||||
-1.841629701E-01 5.663134332E-01 1.481862283E+00 2.485604631E+00 3.433969848E+00
|
||||
1.000000000E+00 1.052063172E+00 1.110825146E+00 1.175313684E+00 1.246728314E+00
|
||||
1.329465325E+00 1.421360710E+00 1.524560763E+00 1.640637648E+00 1.780226739E+00
|
||||
1.940075364E+00 2.127842689E+00 2.354934271E+00 2.628982190E+00 2.978396113E+00
|
||||
3.421740456E+00 4.029874510E+00 4.918435235E+00 6.433511058E+00 8.575101979E+00
|
||||
60 11
|
||||
1.400000000E+00 0.000000000E+00 1.394544521E+00 1.316756722E-01 1.378326897E+00
|
||||
2.597595754E-01 1.351789500E+00 3.807579144E-01 1.315656204E+00 4.913701702E-01
|
||||
1.270912629E+00 5.885791285E-01 1.218779263E+00 6.697331826E-01 1.160678170E+00
|
||||
7.326186613E-01 1.098194195E+00 7.755202128E-01 1.033031738E+00 7.972675944E-01
|
||||
9.669682618E-01 7.972675944E-01 9.018058051E-01 7.755202128E-01 8.393218301E-01
|
||||
7.326186613E-01 7.812207368E-01 6.697331826E-01 7.290873713E-01 5.885791285E-01
|
||||
6.843437962E-01 4.913701702E-01 6.482104995E-01 3.807579144E-01 6.216731033E-01
|
||||
2.597595754E-01 6.054554786E-01 1.316756722E-01 6.000000000E-01 9.797174393E-17
|
||||
6.000000000E-01 1.084348500E-16 6.002466000E-01-5.253082994E-02 6.009855315E-01
|
||||
-1.048766012E-01 6.022141911E-01-1.568529072E-01 6.039282505E-01-2.082766426E-01
|
||||
6.061216714E-01-2.589666491E-01 6.087867266E-01-3.087443528E-01 6.119140275E-01
|
||||
-3.574343941E-01 6.154925571E-01-4.048652448E-01 6.195097087E-01-4.508698128E-01
|
||||
6.239513305E-01-4.952860305E-01 6.288017752E-01-5.379574260E-01 6.340439555E-01
|
||||
-5.787336739E-01 6.396594039E-01-6.174711254E-01 6.456283379E-01-6.540333138E-01
|
||||
6.519297299E-01-6.882914358E-01 6.585413809E-01-7.201248050E-01 6.654399990E-01
|
||||
-7.494212768E-01 6.726012815E-01-7.760776440E-01 6.800000000E-01-8.000000000E-01
|
||||
6.800000000E-01-8.000000000E-01 7.465884669E-01-7.760776440E-01 8.110400088E-01
|
||||
-7.494212768E-01 8.731275722E-01-7.201248050E-01 9.326324313E-01-6.882914358E-01
|
||||
9.893449591E-01-6.540333138E-01 1.043065365E+00-6.174711254E-01 1.093604401E+00
|
||||
-5.787336739E-01 1.140784023E+00-5.379574260E-01 1.184438026E+00-4.952860305E-01
|
||||
1.224412622E+00-4.508698128E-01 1.260566986E+00-4.048652448E-01 1.292773752E+00
|
||||
-3.574343941E-01 1.320919461E+00-3.087443528E-01 1.344904957E+00-2.589666491E-01
|
||||
1.364645745E+00-2.082766426E-01 1.380072280E+00-1.568529072E-01 1.391130217E+00
|
||||
-1.048766012E-01 1.397780600E+00-5.253082994E-02 1.400000000E+00-2.168697000E-16
|
||||
5.200000000E-01 0.000000000E+00 5.800000000E-01-6.000000000E-01 5.500000000E-01-9.000000000E-01 1.250000000E+00-9.000000000E-01 1.400000000E+00-6.000000000E-01 1.480000000E+00 0.000000000E+00 1.400000000E+00 6.000000000E-01 1.250000000E+00 9.000000000E-01 5.500000000E-01 9.000000000E-01 5.800000000E-01 6.000000000E-01 5.200000000E-01 0.000000000E+00
|
||||
@@ -32,7 +32,11 @@
|
||||
// Custom benchmark arguments generator
|
||||
static void CustomArguments(bm::Benchmark *b) noexcept
|
||||
{
|
||||
constexpr int MAX_NDOFS = 16 * 1024 * (mfem_use_gpu ? 1024 : 8);
|
||||
#if defined(MFEM_USE_CUDA_OR_HIP_LANG)
|
||||
constexpr int MAX_NDOFS = 16 * 1024 * 1024;
|
||||
#else
|
||||
constexpr int MAX_NDOFS = 16 * 1024 * 8;
|
||||
#endif
|
||||
|
||||
const auto orders = { 7, 6, 5, 4, 3, 2, 1 };
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ set(UNIT_TESTS_SRCS
|
||||
dfem/test_divergence.cpp
|
||||
dfem/test_lvector_interface.cpp
|
||||
dfem/test_mass.cpp
|
||||
dfem/test_tuple.cpp
|
||||
general/test_array.cpp
|
||||
general/test_scan.cpp
|
||||
general/test_arrays_by_name.cpp
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
// 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.
|
||||
|
||||
#include "../unit_tests.hpp"
|
||||
#include "mfem.hpp"
|
||||
#ifndef MFEM_USE_MPI
|
||||
#include "../../../fem/dfem/tuple.hpp"
|
||||
#endif
|
||||
|
||||
using namespace mfem;
|
||||
using namespace mfem::future;
|
||||
|
||||
namespace tuple_test
|
||||
{
|
||||
|
||||
// A payload that is not a scalar, mimicking what dFEM kernels actually store.
|
||||
using vec3 = tensor<real_t, 3>;
|
||||
using tuple3 = tuple<real_t, int, vec3>;
|
||||
|
||||
// mfem::future::tuple is no longer an aggregate: it derives from tuple_leaf
|
||||
// bases so that it can be defined for an arbitrary number of elements. These
|
||||
// checks pin down the properties that the aggregate used to provide for free
|
||||
// and that device kernels (which capture tuples by value) depend on.
|
||||
static_assert(std::is_trivially_copyable<tuple3>::value,
|
||||
"tuple must be trivially copyable to be captured by value in device kernels");
|
||||
static_assert(std::is_trivially_destructible<tuple3>::value,
|
||||
"tuple must be trivially destructible");
|
||||
static_assert(std::is_trivially_default_constructible<tuple3>::value,
|
||||
"tuple must be trivially default constructible");
|
||||
static_assert(std::is_trivially_copy_assignable<tuple3>::value,
|
||||
"tuple must be trivially copy assignable");
|
||||
static_assert(sizeof(tuple3) == sizeof(real_t) + sizeof(int) + sizeof(vec3) +
|
||||
(alignof(real_t) - sizeof(int)),
|
||||
"tuple must not be larger than the sum of its (padded) members");
|
||||
|
||||
// Size and element types, both through mfem::future and through the std
|
||||
// specializations that drive structured bindings.
|
||||
static_assert(tuple_size<tuple3>::value == 3, "");
|
||||
static_assert(std::tuple_size<tuple3>::value == 3, "");
|
||||
static_assert(std::is_same<tuple_element<0, tuple3>::type, real_t>::value, "");
|
||||
static_assert(std::is_same<tuple_element<1, tuple3>::type, int>::value, "");
|
||||
static_assert(std::is_same<tuple_element<2, tuple3>::type, vec3>::value, "");
|
||||
static_assert(std::is_same<std::tuple_element_t<0, tuple3>, real_t>::value, "");
|
||||
static_assert(std::is_same<std::tuple_element_t<2, tuple3>, vec3>::value, "");
|
||||
|
||||
// get must preserve the value category and constness of its argument.
|
||||
static_assert(std::is_same<decltype(get<1>(std::declval<tuple3&>())),
|
||||
int&>::value, "get on an lvalue must return an lvalue reference");
|
||||
static_assert(std::is_same<decltype(get<1>(std::declval<const tuple3&>())),
|
||||
const int&>::value,
|
||||
"get on a const lvalue must return a const lvalue reference");
|
||||
static_assert(std::is_same<decltype(get<1>(std::declval<tuple3&&>())),
|
||||
int&&>::value, "get on an rvalue must return an rvalue reference");
|
||||
static_assert(std::is_same<decltype(get<1>(std::declval<const tuple3&&>())),
|
||||
const int&&>::value,
|
||||
"get on a const rvalue must return a const rvalue reference");
|
||||
|
||||
// += and -= must return a reference, not a copy of the whole tuple.
|
||||
using tuple2 = tuple<real_t, vec3>;
|
||||
static_assert(std::is_same<decltype(std::declval<tuple2&>() +=
|
||||
std::declval<const tuple2&>()), tuple2&>::value,
|
||||
"operator+= must return a reference");
|
||||
static_assert(std::is_same<decltype(std::declval<tuple2&>() -=
|
||||
std::declval<const tuple2&>()), tuple2&>::value,
|
||||
"operator-= must return a reference");
|
||||
|
||||
// The element-wise constructor must stay implicit, so that the
|
||||
// copy-list-initialization forms that worked with the aggregate keep working.
|
||||
static_assert(std::is_convertible<int, tuple<int>>::value,
|
||||
"tuple's element-wise constructor must not be explicit");
|
||||
|
||||
// Constructing from an incompatible type must SFINAE out rather than hard-error,
|
||||
// so that the constructor does not poison type traits.
|
||||
struct not_a_number { };
|
||||
static_assert(!std::is_constructible<tuple<int, int>, int, not_a_number>::value,
|
||||
"");
|
||||
static_assert(!std::is_constructible<tuple<int, int>, int>::value,
|
||||
"arity mismatch must not be constructible");
|
||||
|
||||
// Usable at compile time.
|
||||
constexpr tuple<int, real_t> const_tuple {2, 3.0};
|
||||
static_assert(get<0>(const_tuple) == 2, "");
|
||||
|
||||
// Copy-list-initialization in a return statement (broken by an explicit ctor).
|
||||
tuple<int, real_t> returns_braced_init_list() { return {7, 8.0}; }
|
||||
|
||||
} // namespace tuple_test
|
||||
|
||||
using namespace tuple_test;
|
||||
|
||||
TEST_CASE("dFEM tuple structured bindings", "[dFEM]")
|
||||
{
|
||||
tuple3 t {1.0, 2, vec3{{3.0, 4.0, 5.0}}};
|
||||
|
||||
SECTION("binding by reference writes through")
|
||||
{
|
||||
auto &[a, b, c] = t;
|
||||
a = 10.0;
|
||||
b = 20;
|
||||
c(0) = 30.0;
|
||||
REQUIRE(get<0>(t) == 10.0_r);
|
||||
REQUIRE(get<1>(t) == 20);
|
||||
REQUIRE(get<2>(t)(0) == 30.0_r);
|
||||
}
|
||||
|
||||
SECTION("binding by value copies")
|
||||
{
|
||||
auto [a, b, c] = t;
|
||||
a = 10.0;
|
||||
b = 20;
|
||||
c(0) = 30.0;
|
||||
REQUIRE(get<0>(t) == 1.0_r);
|
||||
REQUIRE(get<1>(t) == 2);
|
||||
REQUIRE(get<2>(t)(0) == 3.0_r);
|
||||
}
|
||||
|
||||
SECTION("binding to const")
|
||||
{
|
||||
const auto &[a, b, c] = t;
|
||||
REQUIRE(a == 1.0_r);
|
||||
REQUIRE(b == 2);
|
||||
REQUIRE(c(2) == 5.0_r);
|
||||
static_assert(std::is_same<decltype(a), const real_t>::value, "");
|
||||
static_assert(std::is_same<decltype(c), const vec3>::value, "");
|
||||
}
|
||||
|
||||
SECTION("the bindings alias the tuple storage")
|
||||
{
|
||||
auto &[a, b, c] = t;
|
||||
REQUIRE(&a == &get<0>(t));
|
||||
REQUIRE(&b == &get<1>(t));
|
||||
REQUIRE(&c == &get<2>(t));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("dFEM tuple construction", "[dFEM]")
|
||||
{
|
||||
SECTION("copy-list-initialization")
|
||||
{
|
||||
tuple<int, real_t> a = {1, 2.0};
|
||||
REQUIRE(get<0>(a) == 1);
|
||||
REQUIRE(get<1>(a) == 2.0_r);
|
||||
|
||||
const auto b = returns_braced_init_list();
|
||||
REQUIRE(get<0>(b) == 7);
|
||||
REQUIRE(get<1>(b) == 8.0_r);
|
||||
}
|
||||
|
||||
SECTION("direct initialization and CTAD")
|
||||
{
|
||||
tuple c {1, 2.0_r, vec3{{1.0, 2.0, 3.0}}};
|
||||
static_assert(std::is_same<decltype(c), tuple<int, real_t, vec3>>::value,
|
||||
"CTAD must decay the arguments");
|
||||
REQUIRE(get<1>(c) == 2.0_r);
|
||||
}
|
||||
|
||||
SECTION("make_tuple")
|
||||
{
|
||||
const auto d = make_tuple(1, 2.0_r);
|
||||
static_assert(std::is_same<decltype(d), const tuple<int, real_t>>::value, "");
|
||||
REQUIRE(get<0>(d) == 1);
|
||||
}
|
||||
|
||||
SECTION("copy and move construction preserve values")
|
||||
{
|
||||
tuple3 t {1.0, 2, vec3{{3.0, 4.0, 5.0}}};
|
||||
tuple3 copy(t);
|
||||
tuple3 moved(std::move(t));
|
||||
REQUIRE(get<1>(copy) == 2);
|
||||
REQUIRE(get<2>(moved)(1) == 4.0_r);
|
||||
}
|
||||
|
||||
SECTION("value initialization zeroes trivial members")
|
||||
{
|
||||
tuple<int, real_t> z {};
|
||||
REQUIRE(get<0>(z) == 0);
|
||||
REQUIRE(get<1>(z) == 0.0_r);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("dFEM tuple arithmetic", "[dFEM]")
|
||||
{
|
||||
const tuple2 x {1.0, vec3{{1.0, 2.0, 3.0}}};
|
||||
const tuple2 y {2.0, vec3{{4.0, 5.0, 6.0}}};
|
||||
|
||||
SECTION("element-wise binary operators")
|
||||
{
|
||||
const auto sum = x + y;
|
||||
REQUIRE(get<0>(sum) == 3.0_r);
|
||||
REQUIRE(get<1>(sum)(2) == 9.0_r);
|
||||
|
||||
const auto diff = y - x;
|
||||
REQUIRE(get<0>(diff) == 1.0_r);
|
||||
REQUIRE(get<1>(diff)(0) == 3.0_r);
|
||||
}
|
||||
|
||||
SECTION("compound assignment mutates in place and returns a reference")
|
||||
{
|
||||
tuple2 z = x;
|
||||
auto &ref = (z += y);
|
||||
REQUIRE(&ref == &z);
|
||||
REQUIRE(get<0>(z) == 3.0_r);
|
||||
REQUIRE(get<1>(z)(1) == 7.0_r);
|
||||
|
||||
auto &ref2 = (z -= y);
|
||||
REQUIRE(&ref2 == &z);
|
||||
REQUIRE(get<0>(z) == 1.0_r);
|
||||
REQUIRE(get<1>(z)(1) == 2.0_r);
|
||||
}
|
||||
|
||||
SECTION("scalar operators and unary minus")
|
||||
{
|
||||
const auto scaled = 2.0_r * x;
|
||||
REQUIRE(get<0>(scaled) == 2.0_r);
|
||||
REQUIRE(get<1>(scaled)(2) == 6.0_r);
|
||||
|
||||
const auto halved = x / 2.0_r;
|
||||
REQUIRE(get<0>(halved) == 0.5_r);
|
||||
|
||||
const auto negated = -x;
|
||||
REQUIRE(get<0>(negated) == -1.0_r);
|
||||
REQUIRE(get<1>(negated)(0) == -1.0_r);
|
||||
}
|
||||
|
||||
SECTION("apply")
|
||||
{
|
||||
const auto s = apply([](const real_t &a, const vec3 &b) { return a + b(0); },
|
||||
x);
|
||||
REQUIRE(s == 2.0_r);
|
||||
}
|
||||
}
|
||||
|
||||
// The tuples are captured by value in device kernels, so exercise a round trip
|
||||
// through device memory: construct, mutate through structured bindings and read
|
||||
// back on the device.
|
||||
TEST_CASE("dFEM tuple on device", "[dFEM][GPU]")
|
||||
{
|
||||
Vector res(4);
|
||||
auto d_res = res.Write();
|
||||
|
||||
forall(1, [=] MFEM_HOST_DEVICE (int)
|
||||
{
|
||||
tuple3 t {1.0, 2, vec3{{3.0, 4.0, 5.0}}};
|
||||
auto &[a, b, c] = t;
|
||||
a += static_cast<real_t>(b);
|
||||
c(0) = a;
|
||||
|
||||
tuple2 u {get<0>(t), get<2>(t)};
|
||||
u += tuple2 {1.0, vec3{{1.0, 1.0, 1.0}}};
|
||||
|
||||
d_res[0] = get<0>(u);
|
||||
d_res[1] = get<1>(u)(0);
|
||||
d_res[2] = get<1>(u)(1);
|
||||
d_res[3] = static_cast<real_t>(get<1>(t));
|
||||
|
||||
tuple2 v1{0_r, vec3{0_r, 0_r, 0_r}};
|
||||
tuple2 v2{0_r, vec3{0_r, 0_r, 0_r}};
|
||||
[[maybe_unused]] auto v = v1 + v2;
|
||||
});
|
||||
|
||||
res.HostRead();
|
||||
REQUIRE(std::as_const(res)(0) == 4.0_r);
|
||||
REQUIRE(std::as_const(res)(1) == 4.0_r);
|
||||
REQUIRE(std::as_const(res)(2) == 5.0_r);
|
||||
REQUIRE(std::as_const(res)(3) == 2.0_r);
|
||||
}
|
||||
@@ -3451,4 +3451,81 @@ TEST_CASE("2D Bilinear Scalar Weak Curl Cross Integrators",
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("2D Bilinear Scalar Curl Integrator PartialAssembly",
|
||||
"[MixedScalarCurlIntegrator]"
|
||||
"[BilinearFormIntegrator]"
|
||||
"[NonlinearFormIntegrator]"
|
||||
"[GPU]")
|
||||
{
|
||||
int order = 2, n = 1, dim = 2;
|
||||
double tol = 1e-9;
|
||||
|
||||
Mesh mesh = Mesh::MakeCartesian2D(n, n, Element::QUADRILATERAL, 1, 2.0, 3.0);
|
||||
|
||||
VectorFunctionCoefficient F2_coef(dim, F2);
|
||||
FunctionCoefficient q2_coef(q2);
|
||||
|
||||
SECTION("Operators on ND")
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
|
||||
GridFunction f_nd(&fespace_nd); f_nd.ProjectCoefficient(F2_coef);
|
||||
|
||||
for (int map_type = (int)FiniteElement::VALUE;
|
||||
map_type <= (int)FiniteElement::INTEGRAL; map_type++)
|
||||
{
|
||||
SECTION("Mapping ND to L2 (" +
|
||||
MapTypeName((FiniteElement::MapType)map_type) + ")")
|
||||
{
|
||||
L2_FECollection fec_l2(order - 1, dim,
|
||||
BasisType::GaussLegendre,
|
||||
(FiniteElement::MapType)map_type);
|
||||
FiniteElementSpace fespace_l2(&mesh, &fec_l2);
|
||||
|
||||
Vector tmp_l2(fespace_l2.GetNDofs());
|
||||
Vector tmp_l2_pa(fespace_l2.GetNDofs());
|
||||
|
||||
SECTION("Without Coefficient")
|
||||
{
|
||||
MixedBilinearForm blf_fa(&fespace_nd, &fespace_l2);
|
||||
blf_fa.AddDomainIntegrator(new MixedScalarCurlIntegrator());
|
||||
blf_fa.Assemble();
|
||||
blf_fa.Finalize();
|
||||
|
||||
blf_fa.Mult(f_nd, tmp_l2);
|
||||
|
||||
MixedBilinearForm blf_pa(&fespace_nd, &fespace_l2);
|
||||
blf_pa.SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||
blf_pa.AddDomainIntegrator(new MixedScalarCurlIntegrator());
|
||||
blf_pa.Assemble();
|
||||
|
||||
blf_pa.Mult(f_nd, tmp_l2_pa);
|
||||
tmp_l2_pa -= tmp_l2;
|
||||
REQUIRE(tmp_l2_pa.Normlinf() < tol);
|
||||
}
|
||||
SECTION("With Scalar Coefficient")
|
||||
{
|
||||
MixedBilinearForm blf_fa(&fespace_nd, &fespace_l2);
|
||||
blf_fa.AddDomainIntegrator(
|
||||
new MixedScalarCurlIntegrator(q2_coef));
|
||||
blf_fa.Assemble();
|
||||
blf_fa.Finalize();
|
||||
|
||||
blf_fa.Mult(f_nd, tmp_l2);
|
||||
|
||||
MixedBilinearForm blf_pa(&fespace_nd, &fespace_l2);
|
||||
blf_pa.SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||
blf_pa.AddDomainIntegrator(new MixedScalarCurlIntegrator(q2_coef));
|
||||
blf_pa.Assemble();
|
||||
|
||||
blf_pa.Mult(f_nd, tmp_l2_pa);
|
||||
tmp_l2_pa -= tmp_l2;
|
||||
REQUIRE(tmp_l2_pa.Normlinf() < tol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bilininteg_2d
|
||||
|
||||
@@ -1069,4 +1069,238 @@ TEST_CASE("Exact Sequence Properties: d(df)=0",
|
||||
}
|
||||
}
|
||||
|
||||
template <class A, class B>
|
||||
static void TestCurl(FiniteElementSpace &dom_fes, FiniteElementSpace &ran_fes,
|
||||
A coeff, B dcoeff)
|
||||
{
|
||||
real_t tol = 1e-10;
|
||||
DiscreteLinearOperator CurlFA(&dom_fes, &ran_fes);
|
||||
CurlFA.AddDomainInterpolator(new CurlInterpolator());
|
||||
CurlFA.Assemble();
|
||||
CurlFA.Finalize();
|
||||
|
||||
SparseMatrix &Curl = CurlFA.SpMat();
|
||||
GridFunction x(&dom_fes), y_fa(&ran_fes), y(&ran_fes);
|
||||
x.ProjectCoefficient(coeff);
|
||||
y.ProjectCoefficient(dcoeff);
|
||||
REQUIRE(x.Size() == Curl.Width());
|
||||
REQUIRE(y_fa.Size() == Curl.Height());
|
||||
Curl.Mult(x, y_fa);
|
||||
y_fa -= y;
|
||||
REQUIRE(y_fa.Normlinf() < tol);
|
||||
}
|
||||
|
||||
template<class Coeff, class TCoeff>
|
||||
static void CompareCurlPA(FiniteElementSpace& dom_fes,
|
||||
FiniteElementSpace &ran_fes,
|
||||
Coeff coeff, TCoeff tcoeff)
|
||||
{
|
||||
real_t tol = 1e-10;
|
||||
DiscreteLinearOperator CurlFA(&dom_fes, &ran_fes);
|
||||
CurlFA.AddDomainInterpolator(new CurlInterpolator());
|
||||
CurlFA.Assemble();
|
||||
CurlFA.Finalize();
|
||||
DiscreteLinearOperator CurlPA(&dom_fes, &ran_fes);
|
||||
CurlPA.AddDomainInterpolator(new CurlInterpolator());
|
||||
CurlPA.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
CurlPA.Assemble();
|
||||
|
||||
SparseMatrix &Curl = CurlFA.SpMat();
|
||||
GridFunction x(&dom_fes), y_fa(&ran_fes), y_pa(&ran_fes);
|
||||
x.ProjectCoefficient(coeff);
|
||||
REQUIRE(x.Size() == Curl.Width());
|
||||
REQUIRE(y_fa.Size() == Curl.Height());
|
||||
REQUIRE(x.Size() == CurlPA.Width());
|
||||
REQUIRE(y_pa.Size() == CurlPA.Height());
|
||||
Curl.Mult(x, y_fa);
|
||||
CurlPA.Mult(x, y_pa);
|
||||
y_pa -= y_fa;
|
||||
REQUIRE(y_pa.Normlinf() < tol);
|
||||
// transpose
|
||||
y_fa.ProjectCoefficient(tcoeff);
|
||||
GridFunction x_fa(&dom_fes), x_pa(&dom_fes);
|
||||
Curl.MultTranspose(y_fa, x_fa);
|
||||
CurlPA.MultTranspose(y_fa, x_pa);
|
||||
x_pa -= x_fa;
|
||||
REQUIRE(x_pa.Normlinf() < tol);
|
||||
}
|
||||
|
||||
TEST_CASE("Partial Assemble Linear Interpolator",
|
||||
"[CurlInterpolator]"
|
||||
"[GPU]")
|
||||
{
|
||||
constexpr int maxOrder = 3;
|
||||
auto order = GENERATE_COPY(range(1, maxOrder + 1));
|
||||
CAPTURE(order);
|
||||
|
||||
auto dim = GENERATE(2, 3);
|
||||
CAPTURE(dim);
|
||||
|
||||
int n = 3;
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
switch (dim)
|
||||
{
|
||||
case 2:
|
||||
mesh =
|
||||
Mesh::MakeCartesian2D(n, n, Element::QUADRILATERAL, true, 2.0, 3.0);
|
||||
break;
|
||||
case 3:
|
||||
mesh = Mesh::MakeCartesian3D(n, n, n, Element::HEXAHEDRON, 2.0, 3.0, 5.0);
|
||||
break;
|
||||
}
|
||||
|
||||
// domain spaces
|
||||
H1_FECollection fec_h1(order, dim);
|
||||
FiniteElementSpace fespace_h1(&mesh, &fec_h1);
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
|
||||
// range spaces
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
|
||||
L2_FECollection fec_l2(order - 1, dim, BasisType::GaussLegendre,
|
||||
FiniteElement::INTEGRAL);
|
||||
FiniteElementSpace fespace_l2(&mesh, &fec_l2);
|
||||
|
||||
switch (dim)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
FunctionCoefficient coeff([](const Vector &x)
|
||||
{ return sin(2 * M_PI * x[1] / 3) - cos(2 * M_PI * x[0] / 2); });
|
||||
VectorFunctionCoefficient vcoeff(2, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(2);
|
||||
y[0] = -cos(2 * M_PI * x[1] / 3);
|
||||
y[1] = sin(2 * M_PI * x[0] / 2);
|
||||
});
|
||||
// out of plane H1 -> in-plane RT
|
||||
SECTION("H1 to RT")
|
||||
{
|
||||
CompareCurlPA(fespace_h1, fespace_rt, coeff, vcoeff);
|
||||
}
|
||||
// in-plane ND -> out of plane L2
|
||||
SECTION("ND to L2")
|
||||
{
|
||||
CompareCurlPA(fespace_nd, fespace_l2, vcoeff, coeff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
VectorFunctionCoefficient coeff(3, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(3);
|
||||
y[0] = sin(2 * M_PI * x[2] / 5) - cos(2 * M_PI * x[1] / 3);
|
||||
y[1] = sin(2 * M_PI * x[0] / 2) - cos(2 * M_PI * x[2] / 5);
|
||||
y[2] = sin(2 * M_PI * x[1] / 3) - cos(2 * M_PI * x[0] / 2);
|
||||
});
|
||||
CompareCurlPA(fespace_nd, fespace_rt, coeff, coeff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Curl Linear Interpolator",
|
||||
"[CurlInterpolator]"
|
||||
"[GPU]")
|
||||
{
|
||||
int order = 2;
|
||||
|
||||
auto type = (Element::Type)GENERATE(range((int)Element::TRIANGLE,
|
||||
(int)Element::PYRAMID + 1));
|
||||
CAPTURE(type);
|
||||
|
||||
int n = 3;
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
int dim;
|
||||
|
||||
if (type < (int)Element::TETRAHEDRON)
|
||||
{
|
||||
dim = 2;
|
||||
mesh = Mesh::MakeCartesian2D(n, n, (Element::Type)type, 1, 2.0, 3.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
dim = 3;
|
||||
mesh = Mesh::MakeCartesian3D(n, n, n, (Element::Type)type,
|
||||
2.0, 3.0, 5.0);
|
||||
}
|
||||
|
||||
// domain spaces
|
||||
H1_FECollection fec_h1(order, dim);
|
||||
FiniteElementSpace fespace_h1(&mesh, &fec_h1);
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
|
||||
// range spaces
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
|
||||
L2_FECollection fec_l2(order - 1, dim, BasisType::GaussLegendre,
|
||||
FiniteElement::INTEGRAL);
|
||||
FiniteElementSpace fespace_l2(&mesh, &fec_l2);
|
||||
|
||||
switch (dim)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
// out of plane H1 -> in-plane RT
|
||||
SECTION("H1 to RT")
|
||||
{
|
||||
FunctionCoefficient coeff([](const Vector &x)
|
||||
{
|
||||
return 1 - 2 * x[0] + 3 * x[1];
|
||||
});
|
||||
VectorFunctionCoefficient dcoeff(2, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(2);
|
||||
// d Ez/dy
|
||||
y[0] = 3;
|
||||
// -d Ez/dx
|
||||
y[1] = 2;
|
||||
});
|
||||
|
||||
TestCurl(fespace_h1, fespace_rt, coeff, dcoeff);
|
||||
}
|
||||
// in-plane ND -> out of plane L2
|
||||
SECTION("ND to L2")
|
||||
{
|
||||
VectorFunctionCoefficient coeff(2, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(2);
|
||||
y[0] = 1 - 2 * x[0] + 3 * x[1];
|
||||
y[1] = 2 * (1 - 2 * x[0] + 3 * x[1]);
|
||||
});
|
||||
FunctionCoefficient dcoeff([](const Vector &x)
|
||||
{ return 2 * (-2) - 3; });
|
||||
TestCurl(fespace_nd, fespace_l2, coeff, dcoeff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
VectorFunctionCoefficient coeff(3, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(3);
|
||||
y[0] = 1 + 2 * x[0] - 3 * x[1] + 4 * x[2];
|
||||
y[1] = 4 + 3 * x[0] - 2 * x[1] + 1 * x[2];
|
||||
y[2] = 2 - 1 * x[0] + 4 * x[1] - 3 * x[2];
|
||||
});
|
||||
VectorFunctionCoefficient dcoeff(3, [](const Vector &x, Vector &y)
|
||||
{
|
||||
y.SetSize(3);
|
||||
y[0] = 4 - 1;
|
||||
y[1] = 4 + 1;
|
||||
y[2] = 3 + 3;
|
||||
});
|
||||
TestCurl(fespace_nd, fespace_rt, coeff, dcoeff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lin_interp
|
||||
|
||||
@@ -214,7 +214,14 @@ TEST_CASE("LOR AMS", "[LOR][BatchedLOR][AMS][Parallel][GPU]")
|
||||
ParFiniteElementSpace vert_fespace(edge_fespace.GetParMesh(), &vert_fec);
|
||||
|
||||
ParDiscreteLinearOperator grad(&vert_fespace, &edge_fespace);
|
||||
grad.AddDomainInterpolator(new GradientInterpolator);
|
||||
if (space_type == RT)
|
||||
{
|
||||
grad.AddDomainInterpolator(new CurlInterpolator);
|
||||
}
|
||||
else
|
||||
{
|
||||
grad.AddDomainInterpolator(new GradientInterpolator);
|
||||
}
|
||||
grad.Assemble();
|
||||
grad.Finalize();
|
||||
std::unique_ptr<HypreParMatrix> G(grad.ParallelAssemble());
|
||||
|
||||
@@ -1059,4 +1059,111 @@ TEST_CASE("3D Bilinear VectorFE Integrators PartialAssembly",
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("3D Bilinear Weak Curl Integrators Partial Assembly",
|
||||
"[MixedVectorWeakCurlIntegrator]"
|
||||
"[BilinearFormIntegrator]"
|
||||
"[PartialAssembly]"
|
||||
"[GPU]")
|
||||
{
|
||||
auto order = GENERATE(1, 2);
|
||||
CAPTURE(order);
|
||||
int dim = 3;
|
||||
|
||||
FunctionCoefficient q3_coeff(coeffFunction);
|
||||
VectorFunctionCoefficient F3_coeff(dim, vectorCoeffFunction);
|
||||
|
||||
auto mesh_fname =
|
||||
GENERATE("../../data/fichera-amr.mesh", "../../data/ball-nurbs.mesh");
|
||||
CAPTURE(mesh_fname);
|
||||
Mesh mesh(mesh_fname);
|
||||
REQUIRE(mesh.Dimension() == dim);
|
||||
REQUIRE(mesh.SpaceDimension() == dim);
|
||||
|
||||
// convert nurbs into piecewise-quadratic curved mesh
|
||||
if (mesh.NURBSext)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
mesh.SetCurvature(2);
|
||||
}
|
||||
|
||||
SECTION("RT to ND No Coeff")
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
|
||||
|
||||
MixedBilinearForm bfa(&fespace_rt, &fespace_nd);
|
||||
bfa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator);
|
||||
bfa.Assemble();
|
||||
bfa.Finalize();
|
||||
|
||||
MixedBilinearForm bpa(&fespace_rt, &fespace_nd);
|
||||
bpa.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
bpa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator);
|
||||
bpa.Assemble();
|
||||
|
||||
GridFunction x(&fespace_rt), y_fa(&fespace_nd), y_pa(&fespace_nd);
|
||||
x.Randomize(1234);
|
||||
REQUIRE(bfa.Height() == y_fa.Size());
|
||||
REQUIRE(bfa.Width() == x.Size());
|
||||
REQUIRE(bpa.Height() == y_fa.Size());
|
||||
REQUIRE(bpa.Width() == x.Size());
|
||||
bfa.Mult(x, y_fa);
|
||||
bpa.Mult(x, y_pa);
|
||||
y_pa -= y_fa;
|
||||
REQUIRE( y_pa.Normlinf() == MFEM_Approx(0_r) );
|
||||
}
|
||||
|
||||
SECTION("RT to ND Scalar Coeff")
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
|
||||
|
||||
MixedBilinearForm bfa(&fespace_rt, &fespace_nd);
|
||||
bfa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(q3_coeff));
|
||||
bfa.Assemble();
|
||||
bfa.Finalize();
|
||||
|
||||
MixedBilinearForm bpa(&fespace_rt, &fespace_nd);
|
||||
bpa.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
bpa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(q3_coeff));
|
||||
bpa.Assemble();
|
||||
|
||||
GridFunction x(&fespace_rt), y_fa(&fespace_nd), y_pa(&fespace_nd);
|
||||
x.Randomize(1234);
|
||||
bfa.Mult(x, y_fa);
|
||||
bpa.Mult(x, y_pa);
|
||||
y_pa -= y_fa;
|
||||
REQUIRE( y_pa.Normlinf() == MFEM_Approx(0_r) );
|
||||
}
|
||||
|
||||
SECTION("RT to ND Diagonal Matrix Coeff")
|
||||
{
|
||||
ND_FECollection fec_nd(order, dim);
|
||||
FiniteElementSpace fespace_nd(&mesh, &fec_nd);
|
||||
RT_FECollection fec_rt(order - 1, dim);
|
||||
FiniteElementSpace fespace_rt(&mesh, &fec_rt);
|
||||
|
||||
MixedBilinearForm bfa(&fespace_rt, &fespace_nd);
|
||||
bfa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(F3_coeff));
|
||||
bfa.Assemble();
|
||||
bfa.Finalize();
|
||||
|
||||
MixedBilinearForm bpa(&fespace_rt, &fespace_nd);
|
||||
bpa.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
bpa.AddDomainIntegrator(new MixedVectorWeakCurlIntegrator(F3_coeff));
|
||||
bpa.Assemble();
|
||||
|
||||
GridFunction x(&fespace_rt), y_fa(&fespace_nd), y_pa(&fespace_nd);
|
||||
x.Randomize(1234);
|
||||
bfa.Mult(x, y_fa);
|
||||
bpa.Mult(x, y_pa);
|
||||
y_pa -= y_fa;
|
||||
REQUIRE( y_pa.Normlinf() == MFEM_Approx(0_r) );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace pa_coeff
|
||||
|
||||
@@ -164,12 +164,29 @@ TEST_CASE("ComplexHypreParMatrix GetSystemMatrix",
|
||||
a.AddDomainIntegrator(new VectorFEMassIntegrator(one),
|
||||
new VectorFEMassIntegrator(one));
|
||||
a.Assemble();
|
||||
|
||||
// 2. Test ParSesquilinearForm::FormSystemMatrix directly and verify that
|
||||
// essential entries on the imaginary diagonal are zero.
|
||||
OperatorPtr Ah;
|
||||
a.FormSystemMatrix(ess_tdof_list, Ah);
|
||||
ComplexHypreParMatrix *A_complex = Ah.Is<ComplexHypreParMatrix>();
|
||||
REQUIRE(A_complex != nullptr);
|
||||
Vector diag;
|
||||
A_complex->imag().GetDiag(diag);
|
||||
const Array<int> &ess_tdofs = ess_tdof_list;
|
||||
const Vector &diag_h = diag;
|
||||
ess_tdofs.HostRead();
|
||||
diag_h.HostRead();
|
||||
for (const int tdof : ess_tdofs)
|
||||
{
|
||||
REQUIRE(diag_h[tdof] == 0.0);
|
||||
}
|
||||
|
||||
// 3. Test the call to ComplexHypreParMatrix::GetSystemMatrix and destroying
|
||||
// the returned matrix.
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B);
|
||||
|
||||
// 2. Test the call to ComplexHypreParMatrix::GetSystemMatrix and destroying
|
||||
// the returned matrix.
|
||||
HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
|
||||
delete A;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ TEST_CASE("GlobalBBoxTensorGridMap Parallel",
|
||||
std::map<int, std::vector<int>> pt_to_procs;
|
||||
map.MapPointsToProcs(centers, 1, pt_to_procs);
|
||||
|
||||
REQUIRE(pt_to_procs.size() == nel + 1);
|
||||
REQUIRE(pt_to_procs.size() == (unsigned)nel + 1);
|
||||
for (int i = 0; i < nel; i++)
|
||||
{
|
||||
std::vector<int> procs = pt_to_procs[i];
|
||||
|
||||
@@ -304,6 +304,66 @@ TEST_CASE("pNCMesh PA diagonal", "[Parallel], [NCMesh]")
|
||||
}
|
||||
} // test case
|
||||
|
||||
TEST_CASE("ParNCMesh Rebalance preserves element attributes",
|
||||
"[Parallel], [NCMesh]")
|
||||
{
|
||||
const int rank = Mpi::WorldRank();
|
||||
const int nranks = Mpi::WorldSize();
|
||||
if (nranks < 2) { return; }
|
||||
|
||||
auto mesh_fname = GENERATE("../../data/star.mesh",
|
||||
"../../data/fichera.mesh");
|
||||
CAPTURE(mesh_fname);
|
||||
|
||||
auto CheckRebalance = [rank, nranks, mesh_fname](bool refine,
|
||||
bool custom_partition)
|
||||
{
|
||||
Mesh mesh(mesh_fname);
|
||||
mesh.EnsureNCMesh();
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
|
||||
const int attribute = 1234 + (custom_partition ? rank : 0);
|
||||
for (int i = 0; i < pmesh.GetNE(); i++)
|
||||
{
|
||||
pmesh.SetAttribute(i, attribute);
|
||||
}
|
||||
pmesh.SetAttributes();
|
||||
|
||||
if (refine)
|
||||
{
|
||||
Array<int> refinements;
|
||||
if (pmesh.GetNE() && (custom_partition || rank == 0))
|
||||
{
|
||||
refinements.Append(0);
|
||||
}
|
||||
pmesh.GeneralRefinement(refinements);
|
||||
}
|
||||
|
||||
int expected_attribute = attribute;
|
||||
if (custom_partition)
|
||||
{
|
||||
// Move every element to the next rank, as in GitHub issue #4009.
|
||||
Array<int> partition(pmesh.GetNE());
|
||||
partition = (rank + 1) % nranks;
|
||||
pmesh.Rebalance(partition);
|
||||
expected_attribute = 1234 + (rank + nranks - 1) % nranks;
|
||||
}
|
||||
else
|
||||
{
|
||||
pmesh.Rebalance();
|
||||
}
|
||||
|
||||
for (int i = 0; i < pmesh.GetNE(); i++)
|
||||
{
|
||||
CHECK(pmesh.GetAttribute(i) == expected_attribute);
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("Custom partition, unrefined") { CheckRebalance(false, true); }
|
||||
SECTION("Custom partition, refined") { CheckRebalance(true, true); }
|
||||
SECTION("Default partition, refined") { CheckRebalance(true, false); }
|
||||
}
|
||||
|
||||
TEST_CASE("EdgeFaceConstraint", "[Parallel], [NCMesh]")
|
||||
{
|
||||
auto exact_soln = [](const Vector& x)
|
||||
|
||||
Reference in New Issue
Block a user