Compare commits
193
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
432df01647 | ||
|
|
b3beafe905 | ||
|
|
9c936e24bb | ||
|
|
3005dee1af | ||
|
|
7ef5575ab4 | ||
|
|
3f2c2acf23 | ||
|
|
04b5626fd4 | ||
|
|
8162d3047e | ||
|
|
00550ef4f7 | ||
|
|
a16b216c91 | ||
|
|
4b0d543114 | ||
|
|
940ec885ef | ||
|
|
a72fa476c5 | ||
|
|
3a06bc39df | ||
|
|
a3e9ac8e8d | ||
|
|
353fd60e42 | ||
|
|
da8624fd45 | ||
|
|
064eeb6591 | ||
|
|
690807d631 | ||
|
|
69bfdbe248 | ||
|
|
df22d9da86 | ||
|
|
40045b01e2 | ||
|
|
91fc72b021 | ||
|
|
66be99b4f5 | ||
|
|
8b69106bef | ||
|
|
bfdfec0a2c | ||
|
|
6edd9b07ad | ||
|
|
d767b6f541 | ||
|
|
6ab34c27c1 | ||
|
|
d565ad7d84 | ||
|
|
32df373a82 | ||
|
|
0d1f3028f4 | ||
|
|
7afce5a62c | ||
|
|
1e6cd92ad7 | ||
|
|
efa35e4a79 | ||
|
|
5feb9c21db | ||
|
|
9b049b134a | ||
|
|
28a4a8cc24 | ||
|
|
bbcadbcc3b | ||
|
|
dc64a38a86 | ||
|
|
088db70ad2 | ||
|
|
2162829989 | ||
|
|
4c1a849631 | ||
|
|
898a33125c | ||
|
|
a058e2ce63 | ||
|
|
a73a473055 | ||
|
|
50d720c4d7 | ||
|
|
2ecf10cfe5 | ||
|
|
a1b3fedde3 | ||
|
|
747e871e80 | ||
|
|
9d83a0d23c | ||
|
|
04904936f7 | ||
|
|
0db7b843f5 | ||
|
|
06ec0d019f | ||
|
|
2e2d42a8a9 | ||
|
|
0080f2898d | ||
|
|
fd0d5927f6 | ||
|
|
a30eb78a6b | ||
|
|
167cda84c9 | ||
|
|
5a3f58bdf7 | ||
|
|
2d464874e1 | ||
|
|
e938ec6d95 | ||
|
|
9258085c3d | ||
|
|
db1d1f3aa5 | ||
|
|
d4b06b41cc | ||
|
|
534d74a281 | ||
|
|
1520991750 | ||
|
|
a16de090e4 | ||
|
|
857ddd0c24 | ||
|
|
30acc283d6 | ||
|
|
e00be4f28e | ||
|
|
ad208cadfa | ||
|
|
33e4d56213 | ||
|
|
cb1fd6fccb | ||
|
|
eb6a7afb9c | ||
|
|
95985e9c83 | ||
|
|
a7f182e47c | ||
|
|
10ebf2c2a2 | ||
|
|
a59817b8a7 | ||
|
|
4e8a531bb1 | ||
|
|
8f7db4d393 | ||
|
|
51397513f1 | ||
|
|
11964610e1 | ||
|
|
8591f4eb0a | ||
|
|
94c241c368 | ||
|
|
c35a943aba | ||
|
|
bc20049cd9 | ||
|
|
9937009eab | ||
|
|
9bd06e360e | ||
|
|
2bea6d11f1 | ||
|
|
264886c511 | ||
|
|
7ec3c5a30c | ||
|
|
8412926d1f | ||
|
|
e6a0818041 | ||
|
|
1bb517c695 | ||
|
|
8327c249de | ||
|
|
8208a13de4 | ||
|
|
a000402216 | ||
|
|
85d171e7cb | ||
|
|
8e631732e1 | ||
|
|
15b50a277e | ||
|
|
2a85ec5f97 | ||
|
|
320f491661 | ||
|
|
fd45ae843a | ||
|
|
bfad6c9903 | ||
|
|
3d94969a8b | ||
|
|
973e0486ff | ||
|
|
655536e919 | ||
|
|
5d5e0a5320 | ||
|
|
77b6729309 | ||
|
|
ff03595251 | ||
|
|
f84f1c9416 | ||
|
|
0da14b3875 | ||
|
|
c1a15aa858 | ||
|
|
f2c7e4f166 | ||
|
|
4877a6d350 | ||
|
|
ea4d8c365c | ||
|
|
7de90075e1 | ||
|
|
dba8b05843 | ||
|
|
8fc24ace79 | ||
|
|
79aa92e217 | ||
|
|
96dd27f68f | ||
|
|
ab51c0ad38 | ||
|
|
5ef9a11e9f | ||
|
|
ae6b431161 | ||
|
|
e3a9948ab6 | ||
|
|
b3e18e733b | ||
|
|
6fc3b74033 | ||
|
|
b20b819e0e | ||
|
|
3b016624ca | ||
|
|
0b538f5cd1 | ||
|
|
a97509648a | ||
|
|
6fc40b1ee5 | ||
|
|
ce2b02624d | ||
|
|
dcf2e20f86 | ||
|
|
c8990d45db | ||
|
|
5e71900292 | ||
|
|
4a17f07edf | ||
|
|
1b5e10bd25 | ||
|
|
2f77370746 | ||
|
|
5e436c109e | ||
|
|
346af0560f | ||
|
|
5cdbec35ff | ||
|
|
f917dfb3c1 | ||
|
|
89ae6ad31c | ||
|
|
a7ba2b2dad | ||
|
|
69ea9d3dc4 | ||
|
|
bf24259fda | ||
|
|
a0ac13f0ef | ||
|
|
fc430a2732 | ||
|
|
ce12d60a57 | ||
|
|
25804821c9 | ||
|
|
275ef2d826 | ||
|
|
e77e7f592b | ||
|
|
f2c1441949 | ||
|
|
4bae761338 | ||
|
|
9a6954b957 | ||
|
|
1d35d74e85 | ||
|
|
dceaf60897 | ||
|
|
f761e4d033 | ||
|
|
dd9643cabd | ||
|
|
9d21df44c9 | ||
|
|
cfdd39a066 | ||
|
|
a0e9c74b9d | ||
|
|
634ae97901 | ||
|
|
484dadbe4f | ||
|
|
411ee11ffd | ||
|
|
37d153a393 | ||
|
|
13f1441e6c | ||
|
|
331b940373 | ||
|
|
67c70dc827 | ||
|
|
93a7b6ae86 | ||
|
|
684785eb64 | ||
|
|
bddf1110b4 | ||
|
|
a7cc1e74c3 | ||
|
|
88b98c8fb4 | ||
|
|
6c1ee0c854 | ||
|
|
e7674ba0e7 | ||
|
|
9b83346ed3 | ||
|
|
26d3646c1b | ||
|
|
f7724b30d9 | ||
|
|
c28cfb92ac | ||
|
|
2a5a1fc73b | ||
|
|
c61af0cce9 | ||
|
|
e1bd6275d1 | ||
|
|
0f54e013aa | ||
|
|
8b9b0f7a0d | ||
|
|
fd0ac87506 | ||
|
|
83d753c036 | ||
|
|
fb249c5775 | ||
|
|
a3e73ee1a3 | ||
|
|
9b47fcf5cf | ||
|
|
247fa3fa11 |
@@ -16,7 +16,12 @@ Meshing improvements
|
||||
- The graph linear ordering library Gecko, previously an external dependency, is
|
||||
now included directly in MFEM. As a result, Mesh::GetGeckoElementOrdering is
|
||||
always available. The interface has also been improved, see for example the
|
||||
mesh-explorer miniapp.
|
||||
Mesh Explorer miniapp.
|
||||
|
||||
- Improved Gmsh reader (version 2.2), which now supports both high-order and
|
||||
periodic meshes. Segments, triangles, quadrilaterals, and tetrahedra are
|
||||
supported up to order 10. Wedges and hexahedra are supported up to order 9.
|
||||
For sample periodic meshes, see the periodic*.msh files in the data directory.
|
||||
|
||||
- Added support for finite difference-based gradient and Hessian approximation
|
||||
in the TMOP mesh optimization algorithms. This improves the accuracy of the
|
||||
@@ -27,11 +32,8 @@ Meshing improvements
|
||||
the user to specify different discrete functions for controlling the
|
||||
size, aspect-ratio, orientation, and skew of elements in the mesh.
|
||||
|
||||
- Added TMOP capability for approximate tangential mesh relaxation.
|
||||
|
||||
- Added support for reading periodic meshes in Gmsh format (version 2.2). See
|
||||
for example the periodic-annulus-sector and periodic-torus-sector files in
|
||||
the data directory.
|
||||
- Added TMOP capability for approximate tangential mesh relaxation. Added
|
||||
support and examples for using TMOP on mixed meshes.
|
||||
|
||||
- Added complete action of the TMOP Integrator to account for the spatial
|
||||
derivatives of discrete and analytic targets.
|
||||
@@ -58,6 +60,8 @@ Improved GPU capabilities
|
||||
compute a global sparse matrix. All integrators supported by element assembly
|
||||
are also supported by full assembly. See the '-fa' option in Example 9.
|
||||
|
||||
- Added CUDA support for sparse matrix-vector multiplication with cuSPARSE.
|
||||
|
||||
- Added support for BlockOperator on GPU. See the updated Example 5.
|
||||
|
||||
Discretization improvements
|
||||
@@ -165,6 +169,8 @@ New and updated examples and miniapps
|
||||
|
||||
- Added device support in Example 5/5p.
|
||||
|
||||
- Added the option to plot a function in Mesh Explorer.
|
||||
|
||||
Improved testing
|
||||
----------------
|
||||
- Added a GitLab pipeline that automates PR testing on supercomputing systems
|
||||
|
||||
+32
-17
@@ -89,8 +89,38 @@ enable_language(CXX)
|
||||
if (MFEM_USE_CUDA)
|
||||
# MFEM_USE_CUDA requires CMake 3.8 or newer (for direct CUDA support)
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
# Use ${CMAKE_CXX_COMPILER} as the cuda host compiler.
|
||||
if (NOT CMAKE_CUDA_HOST_COMPILER)
|
||||
set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
enable_language(CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CUDA_FLAGS "--expt-extended-lambda")
|
||||
if (CMAKE_VERSION VERSION_LESS 3.18.0)
|
||||
set(CUDA_FLAGS "-arch=${CUDA_ARCH} ${CUDA_FLAGS}")
|
||||
elseif (NOT CMAKE_CUDA_ARCHITECTURES)
|
||||
string(REGEX REPLACE "^sm_" "" ARCH_NUMBER "${CUDA_ARCH}")
|
||||
if ("${CUDA_ARCH}" STREQUAL "sm_${ARCH_NUMBER}")
|
||||
set(CMAKE_CUDA_ARCHITECTURES "${ARCH_NUMBER}")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown CUDA_ARCH: ${CUDA_ARCH}")
|
||||
endif()
|
||||
else()
|
||||
set(CUDA_ARCH "CMAKE_CUDA_ARCHITECTURES: ${CMAKE_CUDA_ARCHITECTURES}")
|
||||
endif()
|
||||
message(STATUS "Using CUDA architecture: ${CUDA_ARCH}")
|
||||
if (CMAKE_VERSION VERSION_LESS 3.12.0)
|
||||
# CMake versions 3.8 and 3.9 require this to work; 3.10 and 3.11 are not
|
||||
# tested and may not actually need this (but should be ok to keep).
|
||||
set(CUDA_FLAGS "-ccbin=${CMAKE_CXX_COMPILER} ${CUDA_FLAGS}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
set(CMAKE_CUDA_FLAGS "${CUDA_FLAGS}" CACHE STRING
|
||||
"CUDA flags set for MFEM" FORCE)
|
||||
set(CUSPARSE_FOUND TRUE)
|
||||
set(CUSPARSE_LIBRARIES "cusparse")
|
||||
endif()
|
||||
|
||||
if (XSDK_ENABLE_C)
|
||||
@@ -296,22 +326,6 @@ if (MFEM_USE_HIOP)
|
||||
# find_package updates HIOP_FOUND, HIOP_INCLUDE_DIRS, HIOP_LIBRARIES
|
||||
endif()
|
||||
|
||||
# CUDA
|
||||
if (MFEM_USE_CUDA)
|
||||
set(CMAKE_CUDA_STANDARD 11)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CUDA_EXTENSIONS OFF)
|
||||
set(CMAKE_CUDA_FLAGS "-arch=${CUDA_ARCH} --expt-extended-lambda"
|
||||
CACHE STRING "CUDA flags set for MFEM" FORCE)
|
||||
if (MFEM_USE_MPI)
|
||||
set(CUDA_CCBIN_COMPILER ${MPI_CXX_COMPILER})
|
||||
else()
|
||||
set(CUDA_CCBIN_COMPILER ${CMAKE_CXX_COMPILER})
|
||||
endif()
|
||||
string(APPEND CMAKE_CUDA_FLAGS " -ccbin ${CUDA_CCBIN_COMPILER}")
|
||||
set(CMAKE_CUDA_HOST_LINK_LAUNCHER ${CUDA_CCBIN_COMPILER})
|
||||
endif()
|
||||
|
||||
# OCCA
|
||||
if (MFEM_USE_OCCA)
|
||||
find_package(OCCA REQUIRED)
|
||||
@@ -357,7 +371,8 @@ endif()
|
||||
# be before SuiteSparse.
|
||||
set(MFEM_TPLS MPI_CXX OPENMP BLAS LAPACK METIS HYPRE SuiteSparse SUNDIALS PETSC
|
||||
SLEPC MESQUITE SuperLUDist STRUMPACK AXOM CONDUIT Ginkgo GNUTLS GSLIB NETCDF
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2)
|
||||
MPFR PUMI HIOP POSIXCLOCKS MFEMBacktrace ZLIB OCCA CEED RAJA UMPIRE ADIOS2
|
||||
CUSPARSE)
|
||||
# Add all *_FOUND libraries in the variable TPL_LIBRARIES.
|
||||
set(TPL_LIBRARIES "")
|
||||
set(TPL_INCLUDE_DIRS "")
|
||||
|
||||
@@ -663,7 +663,7 @@ The specific libraries and their options are:
|
||||
URL: https://github.com/CEED/libCEED
|
||||
https://ceed.exascaleproject.org/libceed
|
||||
Options: CEED_DIR, CEED_OPT, CEED_LIB.
|
||||
Versions: libCEED >= 0.6, git-hash a970f63.
|
||||
Versions: libCEED > 0.6, git-hash fe5822c.
|
||||
|
||||
- RAJA (optional), used when MFEM_USE_RAJA = YES.
|
||||
Beginning with MFEM v4.1, only RAJA v0.10.0+ is supported.
|
||||
|
||||
@@ -128,7 +128,15 @@ function(add_mfem_miniapp MFEM_EXE_NAME)
|
||||
if (MFEM_USE_CUDA)
|
||||
set_property(SOURCE ${MAIN_LIST} ${EXTRA_SOURCES_LIST}
|
||||
PROPERTY LANGUAGE CUDA)
|
||||
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
|
||||
list(TRANSFORM EXTRA_OPTIONS_LIST PREPEND "-Xcompiler=")
|
||||
else()
|
||||
set(LIST_)
|
||||
foreach(item IN LISTS EXTRA_OPTIONS_LIST)
|
||||
list(APPEND LIST_ "-Xcompiler=${item}")
|
||||
endforeach()
|
||||
set(EXTRA_OPTIONS_LIST ${LIST_})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Actually add the executable
|
||||
|
||||
+2
-2
@@ -341,9 +341,9 @@ GSLIB_DIR = @MFEM_DIR@/../gslib/build
|
||||
GSLIB_OPT = -I$(GSLIB_DIR)/include
|
||||
GSLIB_LIB = -L$(GSLIB_DIR)/lib -lgs
|
||||
|
||||
# CUDA library configuration (currently not needed)
|
||||
# CUDA library configuration
|
||||
CUDA_OPT =
|
||||
CUDA_LIB =
|
||||
CUDA_LIB = -lcusparse
|
||||
|
||||
# HIP library configuration (currently not needed)
|
||||
HIP_OPT =
|
||||
|
||||
@@ -1,13 +1,38 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
|
||||
periodic = 1;
|
||||
|
||||
// Set the geometry order (1, 2, ..., 9)
|
||||
order = 3;
|
||||
|
||||
// Set the element type (3 - triangles, 4 - quadrilaterals)
|
||||
type = 3;
|
||||
|
||||
// Number of radial elements
|
||||
nrad = 2;
|
||||
|
||||
// Number of azimuthal elements on inner arc
|
||||
nazm1 = 3;
|
||||
|
||||
// Number of azimuthal elements on outer arc
|
||||
nazm2 = 5;
|
||||
|
||||
// Note: Using type = 4 with nazm1 != nazm2 can lead to mixed meshes
|
||||
// containing both triangles and quadrilaterals.
|
||||
|
||||
// Inner and outer radii
|
||||
R1 = 1.0;
|
||||
R2 = 2.0;
|
||||
|
||||
// Angular size of the sector
|
||||
Phi = Pi/3.0;
|
||||
|
||||
Point(1) = {0.0, 0, 0, 1.0};
|
||||
Point(2) = {R1, 0, 0, 1.0};
|
||||
Point(3) = {R2, 0, 0, 1.0};
|
||||
Point(4) = {R1*Cos(Pi/3), R1*Sin(Pi/3), 0, 1.0};
|
||||
Point(5) = {R2*Cos(Pi/3), R2*Sin(Pi/3), 0, 1.0};
|
||||
Point(4) = {R1*Cos(Phi), R1*Sin(Phi), 0, 1.0};
|
||||
Point(5) = {R2*Cos(Phi), R2*Sin(Phi), 0, 1.0};
|
||||
Line(1) = {2, 3};
|
||||
Line(2) = {4, 5};
|
||||
Circle(3) = {2, 1, 4};
|
||||
@@ -15,13 +40,23 @@ Circle(4) = {3, 1, 5};
|
||||
Curve Loop(5) = {1, 4, -2, -3};
|
||||
Plane Surface(1) = {5};
|
||||
|
||||
Transfinite Curve{1} = 7;
|
||||
Transfinite Curve{2} = 7;
|
||||
Transfinite Curve{3} = 4;
|
||||
Transfinite Curve{4} = 10;
|
||||
Transfinite Curve{1} = nrad+1;
|
||||
Transfinite Curve{2} = nrad+1;
|
||||
Transfinite Curve{3} = nazm1+1;
|
||||
Transfinite Curve{4} = nazm2+1;
|
||||
|
||||
If (nazm1 == nazm2)
|
||||
Transfinite Surface{1};
|
||||
EndIf
|
||||
|
||||
If (type == 4)
|
||||
Recombine Surface {1};
|
||||
EndIf
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
|
||||
If (periodic)
|
||||
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Phi};
|
||||
EndIf
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Curve(1) = {3};
|
||||
@@ -30,8 +65,22 @@ Physical Curve(3) = {1};
|
||||
Physical Curve(4) = {2};
|
||||
Physical Surface(1) = {1};
|
||||
|
||||
// Optimize the high-order mesh
|
||||
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
|
||||
// Mesh.ElementOrder = order;
|
||||
// Mesh.HighOrderOptimize = 1;
|
||||
|
||||
// Generate 2D mesh
|
||||
Mesh 2;
|
||||
SetOrder order;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
|
||||
Save "periodic-annulus-sector.msh";
|
||||
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
|
||||
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
|
||||
// Plugin(AnalyseMeshQuality).Run;
|
||||
|
||||
If (periodic)
|
||||
Save Sprintf("periodic-annulus-sector-t%01g-o%01g.msh", type, order);
|
||||
Else
|
||||
Save Sprintf("annulus-sector-t%01g-o%01g.msh", type, order);
|
||||
EndIf
|
||||
|
||||
+168
-161
@@ -2,184 +2,191 @@ $MeshFormat
|
||||
2.2 0 8
|
||||
$EndMeshFormat
|
||||
$Nodes
|
||||
55
|
||||
136
|
||||
1 1 0 0
|
||||
2 2 0 0
|
||||
3 0.5000000000000001 0.8660254037844386 0
|
||||
4 1 1.732050807568877 0
|
||||
5 1.166666666666667 0 0
|
||||
6 1.333333333333333 0 0
|
||||
7 1.5 0 0
|
||||
5 1.5 0 0
|
||||
6 1.166666666666667 0 0
|
||||
7 1.333333333333333 0 0
|
||||
8 1.666666666666667 0 0
|
||||
9 1.833333333333333 0 0
|
||||
10 0.5833333333333335 1.010362971081845 0
|
||||
11 0.6666666666666667 1.154700538379251 0
|
||||
12 0.7500000000000002 1.299038105676658 0
|
||||
10 0.7500000000000002 1.299038105676658 0
|
||||
11 0.5833333333333335 1.010362971081845 0
|
||||
12 0.6666666666666667 1.154700538379251 0
|
||||
13 0.8333333333333335 1.443375672974064 0
|
||||
14 0.9166666666666669 1.587713240271471 0
|
||||
15 0.9396926207859085 0.3420201433256683 0
|
||||
16 0.7660444431189786 0.6427876096865386 0
|
||||
17 1.986476715483886 0.2321858282504602 0
|
||||
18 1.946089741159648 0.4612317414848793 0
|
||||
19 1.879385241571817 0.6840402866513365 0
|
||||
20 1.787265280646825 0.8975983604009234 0
|
||||
21 1.670975622825874 1.09901795614161 0
|
||||
22 1.532088886237958 1.285575219373077 0
|
||||
23 1.372483275737469 1.454747283146095 0
|
||||
24 1.194317183405575 1.604246385510085 0
|
||||
25 1.425989114816062 0.1915326920916892 0
|
||||
26 0.8788667344146573 1.13917645290495 0
|
||||
27 1.630372059110754 0.7154531062316609 0
|
||||
28 1.436395769298814 1.053728612482506 0
|
||||
29 1.081023776188756 0.6241293681829633 0
|
||||
30 1.168737372335971 1.428012728596308 0
|
||||
31 1.821063986059922 0.298149890497067 0
|
||||
32 1.234707097211386 0.3469796339295647 0
|
||||
33 1.377747393186519 0.6200150626754309 0
|
||||
34 1.457047681210906 0.3890895843559762 0
|
||||
35 0.917846726184522 0.8957978954532204 0
|
||||
36 1.218335619030348 0.9017812086952638 0
|
||||
37 1.066623110765233 1.061857005744772 0
|
||||
38 1.587029716281926 0.1355955181472859 0
|
||||
39 1.744445799211916 0.1441515753740107 0
|
||||
40 1.25 0.1443375672974065 0
|
||||
41 1.453660070628011 0.8435769396609902 0
|
||||
42 1.741367044061892 0.499612708014486 0
|
||||
43 1.30550638526547 1.257610469847477 0
|
||||
44 1.118213276932792 0.1666674689105279 0
|
||||
45 0.9109440214958271 1.306610291787315 0
|
||||
46 0.9970618258753989 1.438658589955562 0
|
||||
47 0.7499999999999998 1.010362971081845 0
|
||||
48 0.7034449005273667 0.8850673702175776 0
|
||||
49 1.605449512513618 0.9269067082200894 0
|
||||
50 1.561654019115059 0.5298592532912715 0
|
||||
51 1.229782222487711 1.096820457143683 0
|
||||
52 1.617066998712459 0.3090202662210922 0
|
||||
53 1.079645953234324 1.246963713711438 0
|
||||
54 1.877063966817811 0.1348974588243076 0
|
||||
55 1.055356609656722 1.558136350380461 0
|
||||
17 0.993238357741943 0.1160929141252301 0
|
||||
18 0.9730448705798238 0.2306158707424401 0
|
||||
19 0.8936326403234125 0.4487991802004617 0
|
||||
20 0.8354878114129367 0.5495089780708056 0
|
||||
21 0.6862416378687343 0.7273736415730481 0
|
||||
22 0.597158591702787 0.8021231927550432 0
|
||||
23 1.956295201467611 0.4158233816355181 0
|
||||
24 1.827090915285202 0.8134732861515996 0
|
||||
25 1.618033988749896 1.175570504584944 0
|
||||
26 1.338261212717719 1.486289650954786 0
|
||||
27 1.995128100519648 0.1395129474882505 0
|
||||
28 1.980536137483141 0.278346201920131 0
|
||||
29 1.922523391876638 0.551274711633998 0
|
||||
30 1.879385241571817 0.6840402866513373 0
|
||||
31 1.765895185717855 0.9389431255717802 0
|
||||
32 1.696096192312853 1.059838528466408 0
|
||||
33 1.532088886237958 1.285575219373077 0
|
||||
34 1.438679600677305 1.389316740917992 0
|
||||
35 1.231322950651319 1.576021507213442 0
|
||||
36 1.118385806941496 1.658075145110082 0
|
||||
37 1.162276263405681 0.6710405135499813 0
|
||||
38 1.248615852873337 1.079531485311822 0
|
||||
39 1.559209616901855 0.5415673055003691 0
|
||||
40 1.478306597054007 0.8535007117539289 0
|
||||
41 0.9210953433941653 0.9653302893212266 0
|
||||
42 1.296548225291847 0.3150268220262836 0
|
||||
43 1.055002035226811 1.358510675893086 0
|
||||
44 1.704005774249187 0.2344032256041583 0
|
||||
45 0.6403651144647218 0.8991270322967013 0
|
||||
46 0.7807302289294435 0.9322286608089638 0
|
||||
47 0.864063562262777 1.07656622810637 0
|
||||
48 0.8070317811313885 1.187802166891514 0
|
||||
49 0.7236984477980553 1.043464599594108 0
|
||||
50 1.432182741763949 0.1050089406754279 0
|
||||
51 1.364365483527898 0.2100178813508558 0
|
||||
52 1.197698816861231 0.2100178813508558 0
|
||||
53 1.098849408430616 0.1050089406754279 0
|
||||
54 1.265516075097282 0.1050089406754278 0
|
||||
55 0.8177280765440409 0.7503018362314346 0
|
||||
56 0.869411709969103 0.8578160627763305 0
|
||||
57 0.7348318576552288 0.8316090412164392 0
|
||||
58 1.177596357123201 0.3240245957927452 0
|
||||
59 1.058644488954555 0.3330223695592067 0
|
||||
60 1.087610484537871 0.2205785356313179 0
|
||||
61 1.267619707955123 0.7318605796179638 0
|
||||
62 1.372963152504565 0.7926806456859463 0
|
||||
63 1.40174301566045 0.9288443029398934 0
|
||||
64 1.325179434266893 1.004187894125858 0
|
||||
65 1.219835989717452 0.9433678280578752 0
|
||||
66 1.191056126561566 0.8072041708039283 0
|
||||
67 1.296399571111008 0.8680242368719107 0
|
||||
68 1.532241943619239 0.645545107584889 0
|
||||
69 1.505274270336623 0.7495229096694089 0
|
||||
70 1.294587381237739 0.6278827775334439 0
|
||||
71 1.426898499069797 0.5847250415169065 0
|
||||
72 1.399930825787181 0.6887028436014264 0
|
||||
73 1.139442349713613 1.041464419981624 0
|
||||
74 1.030268846553889 1.003397354651425 0
|
||||
75 1.001488983398004 0.8672336973974781 0
|
||||
76 1.081882623401843 0.7691371054737297 0
|
||||
77 1.110662486557728 0.9053007627276766 0
|
||||
78 1.207033584034403 0.5523692830420821 0
|
||||
79 1.251790904663125 0.4336980525341829 0
|
||||
80 1.384102022495183 0.3905403165176455 0
|
||||
81 1.471655819698519 0.4660538110090073 0
|
||||
82 1.339344701866461 0.5092115470255447 0
|
||||
83 1.73779714915742 0.7228379592678562 0
|
||||
84 1.648503383029637 0.6322026323841127 0
|
||||
85 1.691571478423774 0.4996526642120855 0
|
||||
86 1.823933339945692 0.4577380229238018 0
|
||||
87 1.787039416783436 0.5922941012619014 0
|
||||
88 1.308379426102925 1.350703595740465 0
|
||||
89 1.278497639488131 1.215117540526144 0
|
||||
90 1.371755231498856 1.111544491736196 0
|
||||
91 1.494894610124376 1.14355749816057 0
|
||||
92 1.4064614465962 1.25147448186763 0
|
||||
93 1.013887168325833 0.451693600067106 0
|
||||
94 1.088081715865757 0.5613670568085436 0
|
||||
95 1.03019898997678 0.6616228789288338 0
|
||||
96 0.8981217165478794 0.6522052443076862 0
|
||||
97 0.9637989050473432 0.5564495572737495 0
|
||||
98 1.432367408277627 0.2881522898855752 0
|
||||
99 1.568186591263407 0.2612777577448668 0
|
||||
100 1.655740388466743 0.3367912522362286 0
|
||||
101 1.607475002684299 0.4391792788682989 0
|
||||
102 1.519921205480963 0.3636657843769371 0
|
||||
103 1.184077913657828 1.17252454883891 0
|
||||
104 1.119539974442319 1.265517612365998 0
|
||||
105 1.010366471282595 1.2274505470358 0
|
||||
106 0.9657309073383804 1.096390418178513 0
|
||||
107 1.074904410498104 1.134457483508712 0
|
||||
108 1.901335258083062 0.07813440853471942 0
|
||||
109 1.802670516166124 0.1562688170694388 0
|
||||
110 1.636003849499458 0.156268817069439 0
|
||||
111 1.568001924749729 0.07813440853471942 0
|
||||
112 1.734668591416396 0.07813440853471944 0
|
||||
113 0.8516673450756037 1.318862295748801 0
|
||||
114 0.9533346901512071 1.338686485820944 0
|
||||
115 1.03666802348454 1.48302405311835 0
|
||||
116 1.01833401174227 1.607537430343614 0
|
||||
117 0.9350006784089369 1.463199863046207 0
|
||||
118 1.710829475874804 0.8268157613523761 0
|
||||
119 1.594568036464405 0.8401582365531526 0
|
||||
120 1.621535709747021 0.7361804344686326 0
|
||||
121 1.52488239428597 0.9608573093642675 0
|
||||
122 1.571458191517933 1.068213906974606 0
|
||||
123 1.448318812892413 1.036200900550232 0
|
||||
124 0.908699126206992 1.207626356963657 0
|
||||
125 1.500184666513678 0.1831433492101474 0
|
||||
126 1.646765991694905 0.9507607885973723 0
|
||||
127 0.9498053499729417 0.7597194708525821 0
|
||||
128 1.132839036494479 0.4426958263006443 0
|
||||
129 1.149421761057113 1.40110366758032 0
|
||||
130 1.243841486887416 1.443696659267553 0
|
||||
131 1.134903597606542 1.530869109405537 0
|
||||
132 1.872198725728137 0.3553499962917315 0
|
||||
133 1.788102249988661 0.2948766109479449 0
|
||||
134 1.893223337417325 0.2174207916708467 0
|
||||
135 1.213959700272622 1.308110604053232 0
|
||||
136 1.739836864206217 0.3972646375800152 0
|
||||
$EndNodes
|
||||
$Elements
|
||||
108
|
||||
1 1 2 3 1 1 5
|
||||
2 1 2 3 1 5 6
|
||||
3 1 2 3 1 6 7
|
||||
4 1 2 3 1 7 8
|
||||
5 1 2 3 1 8 9
|
||||
6 1 2 3 1 9 2
|
||||
7 1 2 4 2 3 10
|
||||
8 1 2 4 2 10 11
|
||||
9 1 2 4 2 11 12
|
||||
10 1 2 4 2 12 13
|
||||
11 1 2 4 2 13 14
|
||||
12 1 2 4 2 14 4
|
||||
13 1 2 1 3 1 15
|
||||
14 1 2 1 3 15 16
|
||||
15 1 2 1 3 16 3
|
||||
16 1 2 2 4 2 17
|
||||
17 1 2 2 4 17 18
|
||||
18 1 2 2 4 18 19
|
||||
19 1 2 2 4 19 20
|
||||
20 1 2 2 4 20 21
|
||||
21 1 2 2 4 21 22
|
||||
22 1 2 2 4 22 23
|
||||
23 1 2 2 4 23 24
|
||||
24 1 2 2 4 24 4
|
||||
25 2 2 1 1 32 40 25
|
||||
26 2 2 1 1 25 34 32
|
||||
27 2 2 1 1 33 41 36
|
||||
28 2 2 1 1 38 52 25
|
||||
29 2 2 1 1 33 36 29
|
||||
30 2 2 1 1 26 47 35
|
||||
31 2 2 1 1 35 37 26
|
||||
32 2 2 1 1 25 52 34
|
||||
33 2 2 1 1 32 44 40
|
||||
34 2 2 1 1 15 32 29
|
||||
35 2 2 1 1 15 29 16
|
||||
36 2 2 1 1 36 41 28
|
||||
37 2 2 1 1 32 33 29
|
||||
38 2 2 1 1 50 52 42
|
||||
39 2 2 1 1 32 34 33
|
||||
40 2 2 1 1 42 52 31
|
||||
41 2 2 1 1 43 53 51
|
||||
42 2 2 1 1 27 41 33
|
||||
43 2 2 1 1 26 53 45
|
||||
44 2 2 1 1 18 31 17
|
||||
45 2 2 1 1 29 35 16
|
||||
46 2 2 1 1 29 36 35
|
||||
47 2 2 1 1 24 30 23
|
||||
48 2 2 1 1 30 53 43
|
||||
49 2 2 1 1 17 54 2
|
||||
50 2 2 1 1 4 55 24
|
||||
51 2 2 1 1 28 51 36
|
||||
52 2 2 1 1 47 48 35
|
||||
53 2 2 1 1 36 37 35
|
||||
54 2 2 1 1 37 53 26
|
||||
55 2 2 1 1 22 28 21
|
||||
56 2 2 1 1 20 27 19
|
||||
57 2 2 1 1 33 50 27
|
||||
58 2 2 1 1 15 44 32
|
||||
59 2 2 1 1 18 42 31
|
||||
60 2 2 1 1 30 43 23
|
||||
61 2 2 1 1 35 48 16
|
||||
62 2 2 1 1 31 54 17
|
||||
63 2 2 1 1 9 39 8
|
||||
64 2 2 1 1 8 38 7
|
||||
65 2 2 1 1 7 25 6
|
||||
66 2 2 1 1 22 43 28
|
||||
67 2 2 1 1 23 43 22
|
||||
68 2 2 1 1 39 54 31
|
||||
69 2 2 1 1 19 42 18
|
||||
70 2 2 1 1 24 55 30
|
||||
71 2 2 1 1 27 42 19
|
||||
72 2 2 1 1 13 46 14
|
||||
73 2 2 1 1 51 53 37
|
||||
74 2 2 1 1 39 52 38
|
||||
75 2 2 1 1 6 40 5
|
||||
76 2 2 1 1 34 52 50
|
||||
77 2 2 1 1 12 45 13
|
||||
78 2 2 1 1 30 55 46
|
||||
79 2 2 1 1 10 47 11
|
||||
80 2 2 1 1 8 39 38
|
||||
81 2 2 1 1 28 49 21
|
||||
82 2 2 1 1 7 38 25
|
||||
83 2 2 1 1 41 49 28
|
||||
84 2 2 1 1 20 49 27
|
||||
85 2 2 1 1 11 26 12
|
||||
86 2 2 1 1 27 49 41
|
||||
87 2 2 1 1 31 52 39
|
||||
88 2 2 1 1 25 40 6
|
||||
89 2 2 1 1 2 54 9
|
||||
90 2 2 1 1 14 55 4
|
||||
91 2 2 1 1 45 53 46
|
||||
92 2 2 1 1 45 46 13
|
||||
93 2 2 1 1 5 44 1
|
||||
94 2 2 1 1 21 49 20
|
||||
95 2 2 1 1 46 53 30
|
||||
96 2 2 1 1 3 48 10
|
||||
97 2 2 1 1 34 50 33
|
||||
98 2 2 1 1 36 51 37
|
||||
99 2 2 1 1 26 45 12
|
||||
100 2 2 1 1 11 47 26
|
||||
101 2 2 1 1 27 50 42
|
||||
102 2 2 1 1 40 44 5
|
||||
103 2 2 1 1 43 51 28
|
||||
104 2 2 1 1 10 48 47
|
||||
105 2 2 1 1 9 54 39
|
||||
106 2 2 1 1 46 55 14
|
||||
107 2 2 1 1 1 44 15
|
||||
108 2 2 1 1 16 48 3
|
||||
38
|
||||
1 26 2 3 1 1 5 6 7
|
||||
2 26 2 3 1 5 2 8 9
|
||||
3 26 2 4 2 3 10 11 12
|
||||
4 26 2 4 2 10 4 13 14
|
||||
5 26 2 1 3 1 15 17 18
|
||||
6 26 2 1 3 15 16 19 20
|
||||
7 26 2 1 3 16 3 21 22
|
||||
8 26 2 2 4 2 23 27 28
|
||||
9 26 2 2 4 23 24 29 30
|
||||
10 26 2 2 4 24 25 31 32
|
||||
11 26 2 2 4 25 26 33 34
|
||||
12 26 2 2 4 26 4 35 36
|
||||
13 21 2 1 1 3 41 10 45 46 47 48 12 11 49
|
||||
14 21 2 1 1 5 42 1 50 51 52 53 6 7 54
|
||||
15 21 2 1 1 16 41 3 55 56 46 45 22 21 57
|
||||
16 21 2 1 1 1 42 15 53 52 58 59 18 17 60
|
||||
17 21 2 1 1 37 40 38 61 62 63 64 65 66 67
|
||||
18 21 2 1 1 39 40 37 68 69 62 61 70 71 72
|
||||
19 21 2 1 1 38 41 37 73 74 75 76 66 65 77
|
||||
20 21 2 1 1 37 42 39 78 79 80 81 71 70 82
|
||||
21 21 2 1 1 24 39 23 83 84 85 86 29 30 87
|
||||
22 21 2 1 1 26 38 25 88 89 90 91 33 34 92
|
||||
23 21 2 1 1 15 37 16 93 94 95 96 20 19 97
|
||||
24 21 2 1 1 42 44 39 98 99 100 101 81 80 102
|
||||
25 21 2 1 1 38 43 41 103 104 105 106 74 73 107
|
||||
26 21 2 1 1 2 44 5 108 109 110 111 8 9 112
|
||||
27 21 2 1 1 10 43 4 113 114 115 116 14 13 117
|
||||
28 21 2 1 1 24 40 39 118 119 69 68 84 83 120
|
||||
29 21 2 1 1 38 40 25 64 63 121 122 91 90 123
|
||||
30 21 2 1 1 41 43 10 106 105 114 113 48 47 124
|
||||
31 21 2 1 1 5 44 42 111 110 99 98 51 50 125
|
||||
32 21 2 1 1 25 40 24 122 121 119 118 31 32 126
|
||||
33 21 2 1 1 37 41 16 76 75 56 55 96 95 127
|
||||
34 21 2 1 1 15 42 37 59 58 79 78 94 93 128
|
||||
35 21 2 1 1 4 43 26 116 115 129 130 35 36 131
|
||||
36 21 2 1 1 23 44 2 132 133 109 108 27 28 134
|
||||
37 21 2 1 1 26 43 38 130 129 104 103 89 88 135
|
||||
38 21 2 1 1 39 44 23 101 100 133 132 86 85 136
|
||||
$EndElements
|
||||
$Periodic
|
||||
1
|
||||
1 1 2
|
||||
Affine 0.5000000000000001 0.8660254037844386 0 0 -0.8660254037844386 0.5000000000000001 0 0 0 0 1 0 0 0 0 1
|
||||
7
|
||||
9 14
|
||||
6 11
|
||||
8 13
|
||||
3
|
||||
5 10
|
||||
7 12
|
||||
2 4
|
||||
1 3
|
||||
2 4
|
||||
$EndPeriodic
|
||||
|
||||
+129
-13
@@ -1,25 +1,141 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
// Select periodic mesh by setting this to either 0 - standard, 1 - periodic
|
||||
periodic = 1;
|
||||
|
||||
R = 1.5;
|
||||
r = 0.5;
|
||||
// Set the geometry order (1, 2, ..., 10 for tetrahedra or 9 for other types)
|
||||
order = 3;
|
||||
|
||||
Torus(1) = {0,0,0, R, r, Pi/3};
|
||||
// Set the element type (4 - tetrahedra, 6 - wedges, 8 - hexahedra)
|
||||
type = 8;
|
||||
|
||||
pts() = PointsOf{ Volume{1}; };
|
||||
// Minor and major radii
|
||||
R1 = 1.0;
|
||||
R2 = 2.0;
|
||||
|
||||
Characteristic Length{ pts() } = 0.25;
|
||||
// Side length of interior square
|
||||
A1 = 0.8;
|
||||
|
||||
// Angular size of the sector
|
||||
Phi = Pi/3.0;
|
||||
|
||||
// Number of azimuthal elements
|
||||
nazm = 3;
|
||||
|
||||
// Number of elements around a quarter of the circle
|
||||
narc = 2;
|
||||
|
||||
// Number of elements between surface and interior square
|
||||
nshl = 1;
|
||||
|
||||
lc = 0.5;
|
||||
a1 = A1 / Sqrt(2.0);
|
||||
|
||||
Point(1) = {R2+R1, 0, 0, lc};
|
||||
Point(2) = {R2, 0, R1, lc};
|
||||
Point(3) = {R2-R1, 0, 0, lc};
|
||||
Point(4) = {R2, 0, -R1, lc};
|
||||
Point(5) = {R2, 0, 0, lc};
|
||||
Point(6) = {R2+a1, 0, 0, lc};
|
||||
Point(7) = {R2, 0, a1, lc};
|
||||
Point(8) = {R2-a1, 0, 0, lc};
|
||||
Point(9) = {R2, 0, -a1, lc};
|
||||
|
||||
Circle(1) = {1,5,2};
|
||||
Circle(2) = {2,5,3};
|
||||
Circle(3) = {3,5,4};
|
||||
Circle(4) = {4,5,1};
|
||||
|
||||
Line(5) = {6,1};
|
||||
Line(6) = {7,2};
|
||||
Line(7) = {8,3};
|
||||
Line(8) = {9,4};
|
||||
|
||||
Line(9) = {6, 7};
|
||||
Line(10) = {7, 8};
|
||||
Line(11) = {8, 9};
|
||||
Line(12) = {9, 6};
|
||||
|
||||
Line Loop(101) = {1, -6, -9, 5};
|
||||
Line Loop(102) = {2, -7, -10, 6};
|
||||
Line Loop(103) = {3, -8, -11, 7};
|
||||
Line Loop(104) = {4, -5, -12, 8};
|
||||
Line Loop(105) = {9, 10, 11, 12};
|
||||
|
||||
Plane Surface(201) = {101};
|
||||
Plane Surface(202) = {102};
|
||||
Plane Surface(203) = {103};
|
||||
Plane Surface(204) = {104};
|
||||
Plane Surface(205) = {105};
|
||||
|
||||
Transfinite Curve{1} = narc+1;
|
||||
Transfinite Curve{2} = narc+1;
|
||||
Transfinite Curve{3} = narc+1;
|
||||
Transfinite Curve{4} = narc+1;
|
||||
|
||||
Transfinite Curve{5} = nshl+1;
|
||||
Transfinite Curve{6} = nshl+1;
|
||||
Transfinite Curve{7} = nshl+1;
|
||||
Transfinite Curve{8} = nshl+1;
|
||||
|
||||
Transfinite Curve{9} = narc+1;
|
||||
Transfinite Curve{10} = narc+1;
|
||||
Transfinite Curve{11} = narc+1;
|
||||
Transfinite Curve{12} = narc+1;
|
||||
|
||||
If (type == 8)
|
||||
Recombine Surface {201};
|
||||
Recombine Surface {202};
|
||||
Recombine Surface {203};
|
||||
Recombine Surface {204};
|
||||
Recombine Surface {205};
|
||||
|
||||
Transfinite Surface {201} = {1,2,7,6};
|
||||
Transfinite Surface {202} = {2,3,8,7};
|
||||
Transfinite Surface {203} = {3,4,9,8};
|
||||
Transfinite Surface {204} = {4,1,6,9};
|
||||
Transfinite Surface {205} = {6,7,8,9};
|
||||
EndIf
|
||||
|
||||
If (type == 4)
|
||||
Extrude { {0,0,1} , {0,0,0} , Phi} {
|
||||
Surface{201,202,203,204,205}; Layers{nazm};
|
||||
}
|
||||
Else
|
||||
Extrude { {0,0,1} , {0,0,0} , Phi} {
|
||||
Surface{201,202,203,204,205}; Layers{nazm}; Recombine;
|
||||
}
|
||||
EndIf
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
|
||||
If (periodic)
|
||||
Periodic Surface{227} = {201} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{249} = {202} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{271} = {203} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{293} = {204} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
Periodic Surface{315} = {205} Rotate{{0,0,1}, {0,0,0}, Phi};
|
||||
EndIf
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Surface(1) = {1};
|
||||
Physical Surface(2) = {2};
|
||||
Physical Surface(3) = {3};
|
||||
Physical Volume(1) = {1};
|
||||
Physical Surface(1) = {201,202,203,204,205};
|
||||
Physical Surface(2) = {227,249,271,293,315};
|
||||
Physical Surface(3) = {214,236,258,280};
|
||||
Physical Volume(1) = {1,2,3,4,5};
|
||||
|
||||
// Optimize the high-order mesh
|
||||
// See https://gmsh.info/doc/texinfo/gmsh.html#index-Mesh_002eHighOrderOptimize
|
||||
// Mesh.ElementOrder = order;
|
||||
// Mesh.HighOrderOptimize = 1;
|
||||
|
||||
// Generate 3D mesh
|
||||
Mesh 3;
|
||||
|
||||
SetOrder order;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
Save "periodic-torus-sector.msh";
|
||||
|
||||
// Check the element quality (the Plugin may be called AnalyseCurvedMesh)
|
||||
// Plugin(AnalyseMeshQuality).JacobianDeterminant = 1;
|
||||
// Plugin(AnalyseMeshQuality).Run;
|
||||
|
||||
If (periodic)
|
||||
Save Sprintf("periodic-torus-sector-t%01g-o%01g.msh", type, order);
|
||||
Else
|
||||
Save Sprintf("torus-sector-t%01g-o%01g.msh", type, order);
|
||||
EndIf
|
||||
|
||||
+1344
-1046
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
20
|
||||
1 3 0 1 6 5
|
||||
1 3 1 2 7 6
|
||||
1 3 2 3 8 7
|
||||
1 3 3 4 9 8
|
||||
1 3 5 6 11 10
|
||||
1 2 6 7 11
|
||||
1 2 7 12 11
|
||||
1 2 7 8 13
|
||||
1 2 7 13 12
|
||||
1 3 8 9 14 13
|
||||
1 3 10 11 16 15
|
||||
1 2 11 12 17
|
||||
1 2 11 17 16
|
||||
1 2 12 13 17
|
||||
1 2 13 18 17
|
||||
1 3 13 14 19 18
|
||||
1 3 15 16 21 20
|
||||
1 3 16 17 22 21
|
||||
1 3 17 18 23 22
|
||||
1 3 18 19 24 23
|
||||
|
||||
boundary
|
||||
16
|
||||
2 1 0 1
|
||||
2 1 1 2
|
||||
2 1 2 3
|
||||
2 1 3 4
|
||||
2 1 21 20
|
||||
2 1 22 21
|
||||
2 1 23 22
|
||||
2 1 24 23
|
||||
1 1 5 0
|
||||
1 1 10 5
|
||||
1 1 15 10
|
||||
1 1 20 15
|
||||
1 1 4 9
|
||||
1 1 9 14
|
||||
1 1 14 19
|
||||
1 1 19 24
|
||||
|
||||
vertices
|
||||
25
|
||||
|
||||
nodes
|
||||
FiniteElementSpace
|
||||
FiniteElementCollection: H1_2D_P1
|
||||
VDim: 2
|
||||
Ordering: 0
|
||||
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0.25
|
||||
0.5
|
||||
0.75
|
||||
1
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.25
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.5
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
0.75
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
@@ -144,8 +144,7 @@ namespace mfem {
|
||||
* - <a class="el" href="maxwell_8cpp_source.html">Maxwell</a>: simple transient full-wave electromagnetics simulation code
|
||||
* - <a class="el" href="joule_8cpp_source.html">Joule</a>: transient magnetics and Joule heating miniapp
|
||||
* - <a class="el" href="classmfem_1_1navier_1_1NavierSolver.html">Navier</a>: solve the transient incompressible Navier-Stokes equations
|
||||
|
||||
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
|
||||
* - <a class="el" href="mobius-strip_8cpp_source.html">Mobius Strip</a>: generate various Mobius strip-like meshes
|
||||
* - <a class="el" href="klein-bottle_8cpp_source.html">Klein Bottle</a>: generate three types of Klein bottle surfaces
|
||||
* - <a class="el" href="toroid_8cpp_source.html">Toroid</a>: generate simple toroidal meshes
|
||||
* - <a class="el" href="twist_8cpp_source.html">Twist</a>: generate simple periodic meshes
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ html: $(DOXYGEN_CONF)
|
||||
@# Generate the html documentation
|
||||
@doxygen $(DOXYGEN_CONF)
|
||||
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
|
||||
@cat warnings.log
|
||||
@cat warnings.log 1>&2
|
||||
@# Generate the log of undocumented methods
|
||||
@( cat $(DOXYGEN_CONF) ; echo "GENERATE_HTML=NO" ; echo "EXTRACT_ALL=NO" ; echo "WARN_LOGFILE=undoc.log" ; echo "QUIET=YES" ) | doxygen - &> /dev/null
|
||||
|
||||
|
||||
+28
-6
@@ -175,7 +175,8 @@ int main(int argc, char *argv[])
|
||||
// domain integrator.
|
||||
BilinearForm a(&fespace);
|
||||
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
|
||||
a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
//a.AddDomainIntegrator(new DiffusionIntegrator(one));
|
||||
a.AddDomainIntegrator(new MassIntegrator(one));
|
||||
|
||||
// 10. Assemble the bilinear form and the corresponding linear system,
|
||||
// applying any necessary transformations such as: eliminating boundary
|
||||
@@ -184,19 +185,40 @@ int main(int argc, char *argv[])
|
||||
if (static_cond) { a.EnableStaticCondensation(); }
|
||||
a.Assemble();
|
||||
|
||||
OperatorPtr A;
|
||||
OperatorPtr A, As;
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
Array<int> empty_list;
|
||||
a.FormSystemMatrix(empty_list, As);
|
||||
//a.FormLinearSystem(empty_list, x, b, A, X, B);
|
||||
//a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
cout << "Size of linear system: " << A->Height() << endl;
|
||||
//cout << "Size of linear system: " << A->Height() << endl;
|
||||
|
||||
// 11. Solve the linear system A X = B.
|
||||
if (!pa)
|
||||
{
|
||||
#ifndef MFEM_USE_SUITESPARSE
|
||||
// Use a simple symmetric Gauss-Seidel preconditioner with PCG.
|
||||
GSSmoother M((SparseMatrix&)(*A));
|
||||
PCG(*A, M, B, X, 1, 200, 1e-12, 0.0);
|
||||
//GSSmoother M((SparseMatrix&)(*A));
|
||||
|
||||
//SparseMatrix &Asp = *As.As<SparseMatrix>();
|
||||
SparseMatrix &Asp = a.SpMat();
|
||||
|
||||
Asp.Finalize();
|
||||
Asp.SortColumnIndices();
|
||||
|
||||
Vector tmpx(B.Size());
|
||||
Vector tmpy(B.Size());
|
||||
tmpx = 1.0;
|
||||
tmpy = 0.0;
|
||||
|
||||
//As.As<SparseMatrix>()->Mult(tmpx, tmpy);
|
||||
Asp.Mult(tmpx, tmpy);
|
||||
|
||||
//IncompleteCholesky M(*As.As<SparseMatrix>());
|
||||
IncompleteCholesky M(Asp);
|
||||
//ILUcusparse M(*A.As<SparseMatrix>());
|
||||
PCG(*As, M, B, X, 1, 200, 1e-12, 0.0);
|
||||
#else
|
||||
// If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
|
||||
UMFPackSolver umf_solver;
|
||||
|
||||
+20
-3
@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
int ref_levels =
|
||||
(int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
for (int l = 0; l < ref_levels-1; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
}
|
||||
@@ -134,7 +134,7 @@ int main(int argc, char *argv[])
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
{
|
||||
int par_ref_levels = 2;
|
||||
int par_ref_levels = 1;
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh.UniformRefinement();
|
||||
@@ -216,6 +216,13 @@ int main(int argc, char *argv[])
|
||||
Vector B, X;
|
||||
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
|
||||
|
||||
SparseMatrix Asp;
|
||||
A.As<HypreParMatrix>()->GetDiag(Asp);
|
||||
Vector diag;
|
||||
|
||||
StopWatch sw;
|
||||
sw.Start();
|
||||
|
||||
// 13. Solve the linear system A X = B.
|
||||
// * With full assembly, use the BoomerAMG preconditioner from hypre.
|
||||
// * With partial assembly, use Jacobi smoothing, for now.
|
||||
@@ -229,7 +236,14 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
prec = new HypreBoomerAMG;
|
||||
//prec = new HypreBoomerAMG;
|
||||
Asp.Finalize();
|
||||
Asp.SortColumnIndices();
|
||||
|
||||
Asp.GetDiag(diag);
|
||||
prec = new OperatorJacobiSmoother(diag, ess_tdof_list);
|
||||
//prec = new IncompleteCholesky(Asp);
|
||||
//prec = new ILUcusparse(Asp);
|
||||
}
|
||||
CGSolver cg(MPI_COMM_WORLD);
|
||||
cg.SetRelTol(1e-12);
|
||||
@@ -240,6 +254,9 @@ int main(int argc, char *argv[])
|
||||
cg.Mult(B, X);
|
||||
delete prec;
|
||||
|
||||
sw.Stop();
|
||||
cout << "Step 13 solve time " << sw.RealTime() << endl;
|
||||
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a.RecoverFEMSolution(X, b, x);
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose between 0: H(Curl) or 1: H(Div)");
|
||||
"Choose between 0: grad, 1: curl, 2: div");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&prob, "-p", "--problem-type",
|
||||
"Choose between 0: H(Curl) or 1: H(Div)");
|
||||
"Choose between 0: grad, 1: curl, 2: div");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&pa, "-pa", "--partial-assembly", "-no-pa",
|
||||
|
||||
@@ -627,6 +627,33 @@ void BilinearForm::AssembleDiagonal(Vector &diag) const
|
||||
MFEM_ASSERT(diag.Size() == fes->GetTrueVSize(),
|
||||
"Vector for holding diagonal has wrong size!");
|
||||
const Operator *P = fes->GetProlongationMatrix();
|
||||
// For an AMR mesh, a convergent diagonal is assembled with |P^T| d_e,
|
||||
// where |P^T| has the entry-wise absolute values of the conforming
|
||||
// prolongation transpose operator.
|
||||
if (P && !fes->Conforming())
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
ext->AssembleDiagonal(local_diag);
|
||||
const SparseMatrix *SP = dynamic_cast<const SparseMatrix*>(P);
|
||||
#ifdef MFEM_USE_MPI
|
||||
const HypreParMatrix *HP = dynamic_cast<const HypreParMatrix*>(P);
|
||||
#endif
|
||||
if (SP)
|
||||
{
|
||||
SP->AbsMultTranspose(local_diag, diag);
|
||||
}
|
||||
#ifdef MFEM_USE_MPI
|
||||
else if (HP)
|
||||
{
|
||||
HP->AbsMultTranspose(1.0, local_diag, 0.0, diag);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Prolongation matrix has unexpected type.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!IsIdentityProlongation(P))
|
||||
{
|
||||
Vector local_diag(P->Height());
|
||||
|
||||
@@ -96,6 +96,9 @@ void PABilinearFormExtension::Assemble()
|
||||
integrators[i]->AssemblePA(*a->FESpace());
|
||||
}
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBoundaryIntegrator yet.");
|
||||
|
||||
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
|
||||
const int intFaceIntegratorCount = intFaceIntegrators.Size();
|
||||
for (int i = 0; i < intFaceIntegratorCount; ++i)
|
||||
@@ -320,6 +323,9 @@ void EABilinearFormExtension::Assemble()
|
||||
GetTraceElement(0, trialFes->GetMesh()->GetFaceBaseGeometry(0)) ->
|
||||
GetDof();
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Element assembly does not support AddBoundaryIntegrator yet.");
|
||||
|
||||
Array<BilinearFormIntegrator*> &intFaceIntegrators = *a->GetFBFI();
|
||||
const int intFaceIntegratorCount = intFaceIntegrators.Size();
|
||||
if (intFaceIntegratorCount>0)
|
||||
@@ -794,6 +800,12 @@ void PAMixedBilinearFormExtension::Assemble()
|
||||
{
|
||||
integrators[i]->AssemblePA(*trialFes, *testFes);
|
||||
}
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBoundaryIntegrator yet.");
|
||||
MFEM_VERIFY(a->GetTFBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddTraceFaceIntegrator yet.");
|
||||
MFEM_VERIFY(a->GetBTFBFI()->Size() == 0,
|
||||
"Partial assembly does not support AddBdrTraceFaceIntegrator yet.");
|
||||
}
|
||||
|
||||
void PAMixedBilinearFormExtension::Update()
|
||||
|
||||
+13
-1
@@ -20,6 +20,13 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HCURL_MAX_D1D = 5;
|
||||
constexpr int HCURL_MAX_Q1D = 6;
|
||||
|
||||
constexpr int HDIV_MAX_D1D = 5;
|
||||
constexpr int HDIV_MAX_Q1D = 6;
|
||||
|
||||
/// Abstract base class BilinearFormIntegrator
|
||||
class BilinearFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
@@ -2390,8 +2397,11 @@ protected:
|
||||
Vector pa_data;
|
||||
const DofToQuad *mapsO; ///< Not owned. DOF-to-quad map, open.
|
||||
const DofToQuad *mapsC; ///< Not owned. DOF-to-quad map, closed.
|
||||
const DofToQuad *mapsOtest; ///< Not owned. DOF-to-quad map, open.
|
||||
const DofToQuad *mapsCtest; ///< Not owned. DOF-to-quad map, closed.
|
||||
const GeometricFactors *geom; ///< Not owned
|
||||
int dim, ne, nq, dofs1D, quad1D, fetype;
|
||||
int dim, ne, nq, dofs1D, dofs1Dtest, quad1D, trial_fetype, test_fetype;
|
||||
bool symmetric = true; ///< False if using a nonsymmetric matrix coefficient
|
||||
|
||||
public:
|
||||
VectorFEMassIntegrator() { Init(NULL, NULL, NULL); }
|
||||
@@ -2412,6 +2422,8 @@ public:
|
||||
|
||||
using BilinearFormIntegrator::AssemblePA;
|
||||
virtual void AssemblePA(const FiniteElementSpace &fes);
|
||||
virtual void AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
const FiniteElementSpace &test_fes);
|
||||
virtual void AddMultPA(const Vector &x, Vector &y) const;
|
||||
virtual void AssembleDiagonalPA(Vector& diag);
|
||||
};
|
||||
|
||||
@@ -130,8 +130,8 @@ static void EADiffusionAssemble2D(const int NE,
|
||||
|
||||
template<int T_D1D = 0, int T_Q1D = 0>
|
||||
static void EADiffusionAssemble3D(const int NE,
|
||||
const Array<double> &g,
|
||||
const Array<double> &b,
|
||||
const Array<double> &g,
|
||||
const Vector &padata,
|
||||
Vector &eadata,
|
||||
const int d1d = 0,
|
||||
|
||||
@@ -96,26 +96,28 @@ void PADiffusionSetup2D<2>(const int Q1D,
|
||||
const Vector &c,
|
||||
Vector &d)
|
||||
{
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 3, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,2,2,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / ((J11*J22)-(J21*J12));
|
||||
D(q,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
|
||||
D(q,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
|
||||
D(q,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J21 = J(qx,qy,1,0,e);
|
||||
const double J12 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
const double c_detJ = W(qx,qy) * coeff / ((J11*J22)-(J21*J12));
|
||||
D(qx,qy,0,e) = c_detJ * (J12*J12 + J22*J22); // 1,1
|
||||
D(qx,qy,1,e) = -c_detJ * (J12*J11 + J22*J21); // 1,2
|
||||
D(qx,qy,2,e) = c_detJ * (J11*J11 + J21*J21); // 2,2
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -131,33 +133,35 @@ void PADiffusionSetup2D<3>(const int Q1D,
|
||||
{
|
||||
constexpr int DIM = 2;
|
||||
constexpr int SDIM = 3;
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, SDIM, DIM, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 3, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,SDIM,DIM,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D, 3, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double wq = W[q];
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double E = J11*J11 + J21*J21 + J31*J31;
|
||||
const double G = J12*J12 + J22*J22 + J32*J32;
|
||||
const double F = J11*J12 + J21*J22 + J31*J32;
|
||||
const double iw = 1.0 / sqrt(E*G - F*F);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double alpha = wq * coeff * iw;
|
||||
D(q,0,e) = alpha * G; // 1,1
|
||||
D(q,1,e) = -alpha * F; // 1,2
|
||||
D(q,2,e) = alpha * E; // 2,2
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double wq = W(qx,qy);
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J21 = J(qx,qy,1,0,e);
|
||||
const double J31 = J(qx,qy,2,0,e);
|
||||
const double J12 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double J32 = J(qx,qy,2,1,e);
|
||||
const double E = J11*J11 + J21*J21 + J31*J31;
|
||||
const double G = J12*J12 + J22*J22 + J32*J32;
|
||||
const double F = J11*J12 + J21*J22 + J31*J32;
|
||||
const double iw = 1.0 / sqrt(E*G - F*F);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
const double alpha = wq * coeff * iw;
|
||||
D(qx,qy,0,e) = alpha * G; // 1,1
|
||||
D(qx,qy,1,e) = -alpha * F; // 1,2
|
||||
D(qx,qy,2,e) = alpha * E; // 2,2
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -170,47 +174,53 @@ static void PADiffusionSetup3D(const int Q1D,
|
||||
const Vector &c,
|
||||
Vector &d)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
const bool const_c = c.Size() == 1;
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
auto C = const_c ? Reshape(c.Read(), 1, 1) : Reshape(c.Read(), NQ, NE);
|
||||
auto D = Reshape(d.Write(), NQ, 6, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto W = Reshape(w.Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(j.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const auto C = const_c ? Reshape(c.Read(), 1,1,1,1) :
|
||||
Reshape(c.Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto D = Reshape(d.Write(), Q1D,Q1D,Q1D, 6, NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
const double c_detJ = W[q] * coeff / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
|
||||
D(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
|
||||
D(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
|
||||
D(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
|
||||
D(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
|
||||
D(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
|
||||
D(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
|
||||
const double c_detJ = W(qx,qy,qz) * coeff / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) adj(J)^T
|
||||
D(qx,qy,qz,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13); // 1,1
|
||||
D(qx,qy,qz,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23); // 2,1
|
||||
D(qx,qy,qz,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33); // 3,1
|
||||
D(qx,qy,qz,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23); // 2,2
|
||||
D(qx,qy,qz,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33); // 3,2
|
||||
D(qx,qy,qz,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33); // 3,3
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+141
-58
@@ -19,10 +19,6 @@ using namespace std;
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HCURL_MAX_D1D = 5;
|
||||
constexpr int HCURL_MAX_Q1D = 6;
|
||||
|
||||
// PA H(curl) Mass Assemble 2D kernel
|
||||
void PAHcurlSetup2D(const int Q1D,
|
||||
const int coeffDim,
|
||||
@@ -33,11 +29,11 @@ void PAHcurlSetup2D(const int Q1D,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool symmetric = (coeffDim != 4);
|
||||
auto W = w.Read();
|
||||
|
||||
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
|
||||
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
|
||||
auto y = Reshape(op.Write(), NQ, 3, NE);
|
||||
auto y = Reshape(op.Write(), NQ, symmetric ? 3 : 4, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -47,12 +43,39 @@ void PAHcurlSetup2D(const int Q1D,
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double c_detJ1 = W[q] * coeff(0, q, e) / ((J11*J22)-(J21*J12));
|
||||
const double c_detJ2 = coeffDim == 2 ? W[q] * coeff(1, q, e)
|
||||
/ ((J11*J22)-(J21*J12)) : c_detJ1;
|
||||
y(q,0,e) = (c_detJ2*J12*J12 + c_detJ1*J22*J22); // 1,1
|
||||
y(q,1,e) = -(c_detJ2*J12*J11 + c_detJ1*J22*J21); // 1,2
|
||||
y(q,2,e) = (c_detJ2*J11*J11 + c_detJ1*J21*J21); // 2,2
|
||||
|
||||
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
|
||||
{
|
||||
// First compute entries of R = MJ^{-T}, without det J factor.
|
||||
const double M11 = coeff(0, q, e);
|
||||
const double M12 = coeff(1, q, e);
|
||||
const double M21 = symmetric ? M12 : coeff(2, q, e);
|
||||
const double M22 = symmetric ? coeff(2, q, e) : coeff(3, q, e);
|
||||
const double R11 = M11*J22 - M12*J12;
|
||||
const double R21 = M21*J22 - M22*J12;
|
||||
const double R12 = -M11*J21 + M12*J11;
|
||||
const double R22 = -M21*J21 + M22*J11;
|
||||
|
||||
// Now set y to J^{-1}R.
|
||||
const double w_detJ = W[q] / ((J11*J22)-(J21*J12));
|
||||
y(q,0,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
|
||||
y(q,1,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
|
||||
y(q,2,e) = w_detJ * (symmetric ? (-J21*R12 + J11*R22) :
|
||||
(J22*R12 - J12*R22)); // 2,2 or 1,2
|
||||
if (!symmetric)
|
||||
{
|
||||
y(q,3,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
|
||||
}
|
||||
}
|
||||
else // Vector or scalar coefficient version
|
||||
{
|
||||
const double c_detJ1 = W[q] * coeff(0, q, e) / ((J11*J22)-(J21*J12));
|
||||
const double c_detJ2 = (coeffDim == 2) ? W[q] * coeff(1, q, e)
|
||||
/ ((J11*J22)-(J21*J12)) : c_detJ1;
|
||||
y(q,0,e) = (c_detJ2*J12*J12 + c_detJ1*J22*J22); // 1,1
|
||||
y(q,1,e) = -(c_detJ2*J12*J11 + c_detJ1*J22*J21); // 1,2
|
||||
y(q,2,e) = (c_detJ2*J11*J11 + c_detJ1*J21*J21); // 2,2
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -67,10 +90,11 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
const bool symmetric = (coeffDim != 9);
|
||||
auto W = w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
|
||||
auto y = Reshape(op.Write(), NQ, 6, NE);
|
||||
auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -89,9 +113,6 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double w_detJ = W[q] / detJ;
|
||||
const double D1 = coeff(0, q, e);
|
||||
const double D2 = coeffDim == 3 ? coeff(1, q, e) : D1;
|
||||
const double D3 = coeffDim == 3 ? coeff(2, q, e) : D1;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
@@ -102,13 +123,66 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
// detJ J^{-1} J^{-T} = (1/detJ) adj(J) D adj(J)^T
|
||||
y(q,0,e) = w_detJ * (D1*A11*A11 + D2*A12*A12 + D3*A13*A13); // 1,1
|
||||
y(q,1,e) = w_detJ * (D1*A11*A21 + D2*A12*A22 + D3*A13*A23); // 2,1
|
||||
y(q,2,e) = w_detJ * (D1*A11*A31 + D2*A12*A32 + D3*A13*A33); // 3,1
|
||||
y(q,3,e) = w_detJ * (D1*A21*A21 + D2*A22*A22 + D3*A23*A23); // 2,2
|
||||
y(q,4,e) = w_detJ * (D1*A21*A31 + D2*A22*A32 + D3*A23*A33); // 3,2
|
||||
y(q,5,e) = w_detJ * (D1*A31*A31 + D2*A32*A32 + D3*A33*A33); // 3,3
|
||||
|
||||
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
|
||||
{
|
||||
// First compute entries of R = MJ^{-T} = M adj(J)^T, without det J factor.
|
||||
const double M11 = coeff(0, q, e);
|
||||
const double M12 = coeff(1, q, e);
|
||||
const double M13 = coeff(2, q, e);
|
||||
const double M21 = (!symmetric) ? coeff(3, q, e) : M12;
|
||||
const double M22 = (!symmetric) ? coeff(4, q, e) : coeff(3, q, e);
|
||||
const double M23 = (!symmetric) ? coeff(5, q, e) : coeff(4, q, e);
|
||||
const double M31 = (!symmetric) ? coeff(6, q, e) : M13;
|
||||
const double M32 = (!symmetric) ? coeff(7, q, e) : M23;
|
||||
const double M33 = (!symmetric) ? coeff(8, q, e) : coeff(5, q, e);
|
||||
|
||||
const double R11 = M11*A11 + M12*A12 + M13*A13;
|
||||
const double R12 = M11*A21 + M12*A22 + M13*A23;
|
||||
const double R13 = M11*A31 + M12*A32 + M13*A33;
|
||||
const double R21 = M21*A11 + M22*A12 + M23*A13;
|
||||
const double R22 = M21*A21 + M22*A22 + M23*A23;
|
||||
const double R23 = M21*A31 + M22*A32 + M23*A33;
|
||||
const double R31 = M31*A11 + M32*A12 + M33*A13;
|
||||
const double R32 = M31*A21 + M32*A22 + M33*A23;
|
||||
const double R33 = M31*A31 + M32*A32 + M33*A33;
|
||||
|
||||
// Now set y to J^{-1} R = adj(J) R
|
||||
y(q,0,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
|
||||
const double Y12 = w_detJ * (A11*R12 + A12*R22 + A13*R32);
|
||||
y(q,1,e) = Y12; // 1,2
|
||||
y(q,2,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
|
||||
|
||||
const double Y21 = w_detJ * (A21*R11 + A22*R21 + A23*R31);
|
||||
const double Y22 = w_detJ * (A21*R12 + A22*R22 + A23*R32);
|
||||
const double Y23 = w_detJ * (A21*R13 + A22*R23 + A23*R33);
|
||||
|
||||
const double Y33 = w_detJ * (A31*R13 + A32*R23 + A33*R33);
|
||||
|
||||
y(q,3,e) = symmetric ? Y22 : Y21; // 2,2 or 2,1
|
||||
y(q,4,e) = symmetric ? Y23 : Y22; // 2,3 or 2,2
|
||||
y(q,5,e) = symmetric ? Y33 : Y23; // 3,3 or 2,3
|
||||
|
||||
if (!symmetric)
|
||||
{
|
||||
y(q,6,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
|
||||
y(q,7,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
|
||||
y(q,8,e) = Y33; // 3,3
|
||||
}
|
||||
}
|
||||
else // Vector or scalar coefficient version
|
||||
{
|
||||
const double D1 = coeff(0, q, e);
|
||||
const double D2 = coeffDim == 3 ? coeff(1, q, e) : D1;
|
||||
const double D3 = coeffDim == 3 ? coeff(2, q, e) : D1;
|
||||
// detJ J^{-1} D J^{-T} = (1/detJ) adj(J) D adj(J)^T
|
||||
y(q,0,e) = w_detJ * (D1*A11*A11 + D2*A12*A12 + D3*A13*A13); // 1,1
|
||||
y(q,1,e) = w_detJ * (D1*A11*A21 + D2*A12*A22 + D3*A13*A23); // 2,1
|
||||
y(q,2,e) = w_detJ * (D1*A11*A31 + D2*A12*A32 + D3*A13*A33); // 3,1
|
||||
y(q,3,e) = w_detJ * (D1*A21*A21 + D2*A22*A22 + D3*A23*A23); // 2,2
|
||||
y(q,4,e) = w_detJ * (D1*A21*A31 + D2*A22*A32 + D3*A23*A33); // 3,2
|
||||
y(q,5,e) = w_detJ * (D1*A31*A31 + D2*A32*A32 + D3*A33*A33); // 3,3
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -116,6 +190,7 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
void PAHcurlMassApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
@@ -132,7 +207,7 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(_Bot.Read(), D1D-1, Q1D);
|
||||
auto Bct = Reshape(_Bct.Read(), D1D, Q1D);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, 3, NE);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
|
||||
auto x = Reshape(_x.Read(), 2*(D1D-1)*D1D, NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 2*(D1D-1)*D1D, NE);
|
||||
|
||||
@@ -194,12 +269,13 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double O11 = op(qx,qy,0,e);
|
||||
const double O12 = op(qx,qy,1,e);
|
||||
const double O22 = op(qx,qy,2,e);
|
||||
const double O21 = op(qx,qy,1,e);
|
||||
const double O12 = symmetric ? O21 : op(qx,qy,2,e);
|
||||
const double O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
|
||||
const double massX = mass[qy][qx][0];
|
||||
const double massY = mass[qy][qx][1];
|
||||
mass[qy][qx][0] = (O11*massX)+(O12*massY);
|
||||
mass[qy][qx][1] = (O12*massX)+(O22*massY);
|
||||
mass[qy][qx][1] = (O21*massX)+(O22*massY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +291,7 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
double massX[MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0;
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -244,6 +320,7 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
@@ -254,7 +331,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
|
||||
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, 3, NE);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
|
||||
auto diag = Reshape(_diag.ReadWrite(), 2*(D1D-1)*D1D, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
@@ -277,7 +354,8 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
{
|
||||
const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
|
||||
|
||||
mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) : op(qx,qy,2,e));
|
||||
mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) :
|
||||
op(qx,qy,symmetric ? 2 : 3, e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +377,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
@@ -313,7 +392,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
|
||||
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
|
||||
auto diag = Reshape(_diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
@@ -326,7 +405,8 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const int D1Dy = (c == 1) ? D1D - 1 : D1D;
|
||||
const int D1Dx = (c == 0) ? D1D - 1 : D1D;
|
||||
|
||||
const int opc = (c == 0) ? 0 : ((c == 1) ? 3 : 5);
|
||||
const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
|
||||
(symmetric ? 5 : 8));
|
||||
|
||||
double mass[MAX_Q1D];
|
||||
|
||||
@@ -369,6 +449,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
void PAHcurlMassApply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
@@ -388,7 +469,7 @@ void PAHcurlMassApply3D(const int D1D,
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(_Bot.Read(), D1D-1, Q1D);
|
||||
auto Bct = Reshape(_Bct.Read(), D1D, Q1D);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
|
||||
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*D1D, NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
|
||||
|
||||
@@ -483,15 +564,18 @@ void PAHcurlMassApply3D(const int D1D,
|
||||
const double O11 = op(qx,qy,qz,0,e);
|
||||
const double O12 = op(qx,qy,qz,1,e);
|
||||
const double O13 = op(qx,qy,qz,2,e);
|
||||
const double O22 = op(qx,qy,qz,3,e);
|
||||
const double O23 = op(qx,qy,qz,4,e);
|
||||
const double O33 = op(qx,qy,qz,5,e);
|
||||
const double O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
|
||||
const double O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
|
||||
const double O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
|
||||
const double O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
|
||||
const double O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
|
||||
const double O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
|
||||
const double massX = mass[qz][qy][qx][0];
|
||||
const double massY = mass[qz][qy][qx][1];
|
||||
const double massZ = mass[qz][qy][qx][2];
|
||||
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
|
||||
mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
|
||||
mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
|
||||
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
|
||||
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,7 +596,7 @@ void PAHcurlMassApply3D(const int D1D,
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] = 0;
|
||||
massXY[dy][dx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -727,7 +811,7 @@ static void PACurlCurlApply2D(const int D1D,
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
curl[qy][qx] = 0;
|
||||
curl[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -789,7 +873,7 @@ static void PACurlCurlApply2D(const int D1D,
|
||||
double gradX[MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
gradX[dx] = 0;
|
||||
gradX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -1757,7 +1841,7 @@ void PAHcurlH1Apply3D(const int D1D,
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] = 0;
|
||||
massXY[dy][dx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -1900,7 +1984,7 @@ void PAHcurlH1Apply2D(const int D1D,
|
||||
double massX[MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0;
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -1926,15 +2010,14 @@ void PAHcurlH1Apply2D(const int D1D,
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// PA H(curl) Mass Assemble 3D kernel
|
||||
static void PAHcurlL2Setup3D(const int Q1D,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
const Array<double> &w,
|
||||
Vector &_coeff,
|
||||
Vector &op)
|
||||
// PA H(curl) assemble kernel
|
||||
void PAHcurlL2Setup(const int NQ,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
const Array<double> &w,
|
||||
Vector &_coeff,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
auto W = w.Read();
|
||||
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
|
||||
auto y = Reshape(op.Write(), coeffDim, NQ, NE);
|
||||
@@ -2035,7 +2118,7 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
if (testType == mfem::FiniteElement::CURL &&
|
||||
trialType == mfem::FiniteElement::CURL && dim == 3)
|
||||
{
|
||||
PAHcurlL2Setup3D(quad1D, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
}
|
||||
else if (testType == mfem::FiniteElement::DIV &&
|
||||
trialType == mfem::FiniteElement::CURL && dim == 3 &&
|
||||
@@ -2346,7 +2429,7 @@ static void PAHcurlL2Apply3D(const int D1D,
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] = 0;
|
||||
massXY[dy][dx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -2354,7 +2437,7 @@ static void PAHcurlL2Apply3D(const int D1D,
|
||||
double massX[MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0;
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -2425,7 +2508,7 @@ static void PAHcurlHdivApply3D(const int D1D,
|
||||
auto Gc = Reshape(_Gc.Read(), Q1D, D1D);
|
||||
auto op = Reshape(_op.Read(), Q1D, Q1D, Q1D, 6, NE);
|
||||
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*D1D, NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1D, NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1Dtest, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -2700,7 +2783,7 @@ static void PAHcurlHdivApply3D(const int D1D,
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] = 0;
|
||||
massXY[dy][dx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
@@ -2708,7 +2791,7 @@ static void PAHcurlHdivApply3D(const int D1D,
|
||||
double massX[HCURL_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0;
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
@@ -2844,7 +2927,7 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
|
||||
|
||||
if (trialType == mfem::FiniteElement::CURL && dim == 3)
|
||||
{
|
||||
PAHcurlL2Setup3D(quad1D, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -23,11 +23,6 @@ using namespace std;
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Local maximum size of dofs and quads in 1D
|
||||
constexpr int HDIV_MAX_D1D = 5;
|
||||
constexpr int HDIV_MAX_Q1D = 6;
|
||||
|
||||
|
||||
// PA H(div) Mass Assemble 2D kernel
|
||||
void PAHdivSetup2D(const int Q1D,
|
||||
const int NE,
|
||||
|
||||
+46
-31
@@ -92,49 +92,64 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes)
|
||||
if (dim==2)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const int Q1D = quad1D;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto w = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,2,2,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,2,2,NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1) :
|
||||
Reshape(coeff.Read(), Q1D,Q1D,NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D,Q1D, NE);
|
||||
MFEM_FORALL_2D(e, NE, Q1D,Q1D,1,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J12 = J(q,1,0,e);
|
||||
const double J21 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double detJ = (J11*J22)-(J21*J12);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = w[q] * coeff * detJ;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,0,0,e);
|
||||
const double J12 = J(qx,qy,1,0,e);
|
||||
const double J21 = J(qx,qy,0,1,e);
|
||||
const double J22 = J(qx,qy,1,1,e);
|
||||
const double detJ = (J11*J22)-(J21*J12);
|
||||
const double coeff = const_c ? C(0,0,0) : C(qx,qy,e);
|
||||
v(qx,qy,e) = W(qx,qy) * coeff * detJ;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (dim==3)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const int Q1D = quad1D;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
auto W = ir->GetWeights().Read();
|
||||
auto J = Reshape(geom->J.Read(), NQ,3,3,NE);
|
||||
auto C =
|
||||
const_c ? Reshape(coeff.Read(), 1,1) : Reshape(coeff.Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ,NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
const auto W = Reshape(ir->GetWeights().Read(), Q1D,Q1D,Q1D);
|
||||
const auto J = Reshape(geom->J.Read(), Q1D,Q1D,Q1D,3,3,NE);
|
||||
const auto C = const_c ? Reshape(coeff.Read(), 1,1,1,1) :
|
||||
Reshape(coeff.Read(), Q1D,Q1D,Q1D,NE);
|
||||
auto v = Reshape(pa_data.Write(), Q1D,Q1D,Q1D,NE);
|
||||
MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_FOREACH_THREAD(qx,x,Q1D)
|
||||
{
|
||||
const double J11 = J(q,0,0,e), J12 = J(q,0,1,e), J13 = J(q,0,2,e);
|
||||
const double J21 = J(q,1,0,e), J22 = J(q,1,1,e), J23 = J(q,1,2,e);
|
||||
const double J31 = J(q,2,0,e), J32 = J(q,2,1,e), J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0) : C(q,e);
|
||||
v(q,e) = W[q] * coeff * detJ;
|
||||
MFEM_FOREACH_THREAD(qy,y,Q1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(qz,z,Q1D)
|
||||
{
|
||||
const double J11 = J(qx,qy,qz,0,0,e);
|
||||
const double J21 = J(qx,qy,qz,1,0,e);
|
||||
const double J31 = J(qx,qy,qz,2,0,e);
|
||||
const double J12 = J(qx,qy,qz,0,1,e);
|
||||
const double J22 = J(qx,qy,qz,1,1,e);
|
||||
const double J32 = J(qx,qy,qz,2,1,e);
|
||||
const double J13 = J(qx,qy,qz,0,2,e);
|
||||
const double J23 = J(qx,qy,qz,1,2,e);
|
||||
const double J33 = J(qx,qy,qz,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double coeff = const_c ? C(0,0,0,0) : C(qx,qy,qz,e);
|
||||
v(qx,qy,qz,e) = W(qx,qy,qz) * coeff * detJ;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+701
-35
@@ -34,6 +34,7 @@ void PAHcurlSetup3D(const int Q1D,
|
||||
void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
@@ -42,6 +43,7 @@ void PAHcurlMassAssembleDiagonal2D(const int D1D,
|
||||
void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Vector &_op,
|
||||
@@ -50,6 +52,7 @@ void PAHcurlMassAssembleDiagonal3D(const int D1D,
|
||||
void PAHcurlMassApply2D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
@@ -61,6 +64,7 @@ void PAHcurlMassApply2D(const int D1D,
|
||||
void PAHcurlMassApply3D(const int D1D,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool symmetric,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
@@ -143,20 +147,573 @@ void PAHdivMassApply3D(const int D1D,
|
||||
const Vector &_x,
|
||||
Vector &_y);
|
||||
|
||||
void PAHcurlL2Setup(const int NQ,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
const Array<double> &w,
|
||||
Vector &_coeff,
|
||||
Vector &op);
|
||||
|
||||
// PA H(curl) x H(div) mass assemble 3D kernel, with factor
|
||||
// dF^{-1} C dF for a vector or matrix coefficient C.
|
||||
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
|
||||
void PAHcurlHdivSetup3D(const int Q1D,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
const bool transpose,
|
||||
const Array<double> &_w,
|
||||
const Vector &j,
|
||||
Vector &_coeff,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D*Q1D;
|
||||
const bool symmetric = (coeffDim != 9);
|
||||
auto W = _w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 3, 3, NE);
|
||||
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
|
||||
auto y = Reshape(op.Write(), 9, NQ, NE);
|
||||
|
||||
const int i11 = 0;
|
||||
const int i12 = transpose ? 3 : 1;
|
||||
const int i13 = transpose ? 6 : 2;
|
||||
const int i21 = transpose ? 1 : 3;
|
||||
const int i22 = 4;
|
||||
const int i23 = transpose ? 7 : 5;
|
||||
const int i31 = transpose ? 2 : 6;
|
||||
const int i32 = transpose ? 5 : 7;
|
||||
const int i33 = 8;
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J31 = J(q,2,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double J32 = J(q,2,1,e);
|
||||
const double J13 = J(q,0,2,e);
|
||||
const double J23 = J(q,1,2,e);
|
||||
const double J33 = J(q,2,2,e);
|
||||
const double detJ = J11 * (J22 * J33 - J32 * J23) -
|
||||
/* */ J21 * (J12 * J33 - J32 * J13) +
|
||||
/* */ J31 * (J12 * J23 - J22 * J13);
|
||||
const double w_detJ = W[q] / detJ;
|
||||
// adj(J)
|
||||
const double A11 = (J22 * J33) - (J23 * J32);
|
||||
const double A12 = (J32 * J13) - (J12 * J33);
|
||||
const double A13 = (J12 * J23) - (J22 * J13);
|
||||
const double A21 = (J31 * J23) - (J21 * J33);
|
||||
const double A22 = (J11 * J33) - (J13 * J31);
|
||||
const double A23 = (J21 * J13) - (J11 * J23);
|
||||
const double A31 = (J21 * J32) - (J31 * J22);
|
||||
const double A32 = (J31 * J12) - (J11 * J32);
|
||||
const double A33 = (J11 * J22) - (J12 * J21);
|
||||
|
||||
if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
|
||||
{
|
||||
// First compute entries of R = MJ
|
||||
const double M11 = (!symmetric) ? coeff(i11, q, e) : coeff(0, q, e);
|
||||
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
|
||||
const double M13 = (!symmetric) ? coeff(i13, q, e) : coeff(2, q, e);
|
||||
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
|
||||
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(3, q, e);
|
||||
const double M23 = (!symmetric) ? coeff(i23, q, e) : coeff(4, q, e);
|
||||
const double M31 = (!symmetric) ? coeff(i31, q, e) : M13;
|
||||
const double M32 = (!symmetric) ? coeff(i32, q, e) : M23;
|
||||
const double M33 = (!symmetric) ? coeff(i33, q, e) : coeff(5, q, e);
|
||||
|
||||
const double R11 = M11*J11 + M12*J12 + M13*J13;
|
||||
const double R12 = M11*J21 + M12*J22 + M13*J23;
|
||||
const double R13 = M11*J31 + M12*J32 + M13*J33;
|
||||
const double R21 = M21*J11 + M22*J12 + M23*J13;
|
||||
const double R22 = M21*J21 + M22*J22 + M23*J23;
|
||||
const double R23 = M21*J31 + M22*J32 + M23*J33;
|
||||
const double R31 = M31*J11 + M32*J12 + M33*J13;
|
||||
const double R32 = M31*J21 + M32*J22 + M33*J23;
|
||||
const double R33 = M31*J31 + M32*J32 + M33*J33;
|
||||
|
||||
// Now set y to detJ J^{-1} R = adj(J) R
|
||||
y(i11,q,e) = w_detJ * (A11*R11 + A12*R21 + A13*R31); // 1,1
|
||||
y(i12,q,e) = w_detJ * (A11*R12 + A12*R22 + A13*R32); // 1,2
|
||||
y(i13,q,e) = w_detJ * (A11*R13 + A12*R23 + A13*R33); // 1,3
|
||||
y(i21,q,e) = w_detJ * (A21*R11 + A22*R21 + A23*R31); // 2,1
|
||||
y(i22,q,e) = w_detJ * (A21*R12 + A22*R22 + A23*R32); // 2,2
|
||||
y(i23,q,e) = w_detJ * (A21*R13 + A22*R23 + A23*R33); // 2,3
|
||||
y(i31,q,e) = w_detJ * (A31*R11 + A32*R21 + A33*R31); // 3,1
|
||||
y(i32,q,e) = w_detJ * (A31*R12 + A32*R22 + A33*R32); // 3,2
|
||||
y(i33,q,e) = w_detJ * (A31*R13 + A32*R23 + A33*R33); // 3,3
|
||||
}
|
||||
else if (coeffDim == 3) // Vector coefficient version
|
||||
{
|
||||
const double D1 = coeff(0, q, e);
|
||||
const double D2 = coeff(1, q, e);
|
||||
const double D3 = coeff(2, q, e);
|
||||
// detJ J^{-1} DJ = adj(J) DJ
|
||||
y(i11,q,e) = w_detJ * (D1*A11*J11 + D2*A12*J21 + D3*A13*J31); // 1,1
|
||||
y(i12,q,e) = w_detJ * (D1*A11*J12 + D2*A12*J22 + D3*A13*J32); // 1,2
|
||||
y(i13,q,e) = w_detJ * (D1*A11*J13 + D2*A12*J23 + D3*A13*J33); // 1,3
|
||||
y(i21,q,e) = w_detJ * (D1*A21*J11 + D2*A22*J21 + D3*A23*J31); // 2,1
|
||||
y(i22,q,e) = w_detJ * (D1*A21*J12 + D2*A22*J22 + D3*A23*J32); // 2,2
|
||||
y(i23,q,e) = w_detJ * (D1*A21*J13 + D2*A22*J23 + D3*A23*J33); // 2,3
|
||||
y(i31,q,e) = w_detJ * (D1*A31*J11 + D2*A32*J21 + D3*A33*J31); // 3,1
|
||||
y(i32,q,e) = w_detJ * (D1*A31*J12 + D2*A32*J22 + D3*A33*J32); // 3,2
|
||||
y(i33,q,e) = w_detJ * (D1*A31*J13 + D2*A32*J23 + D3*A33*J33); // 3,3
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// PA H(curl) x H(div) mass assemble 2D kernel, with factor
|
||||
// dF^{-1} C dF for a vector or matrix coefficient C.
|
||||
// If transpose, use dF^T C dF^{-T} for H(div) x H(curl).
|
||||
void PAHcurlHdivSetup2D(const int Q1D,
|
||||
const int coeffDim,
|
||||
const int NE,
|
||||
const bool transpose,
|
||||
const Array<double> &_w,
|
||||
const Vector &j,
|
||||
Vector &_coeff,
|
||||
Vector &op)
|
||||
{
|
||||
const int NQ = Q1D*Q1D;
|
||||
const bool symmetric = (coeffDim != 4);
|
||||
auto W = _w.Read();
|
||||
auto J = Reshape(j.Read(), NQ, 2, 2, NE);
|
||||
auto coeff = Reshape(_coeff.Read(), coeffDim, NQ, NE);
|
||||
auto y = Reshape(op.Write(), 4, NQ, NE);
|
||||
|
||||
const int i11 = 0;
|
||||
const int i12 = transpose ? 2 : 1;
|
||||
const int i21 = transpose ? 1 : 2;
|
||||
const int i22 = 3;
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
{
|
||||
const double J11 = J(q,0,0,e);
|
||||
const double J21 = J(q,1,0,e);
|
||||
const double J12 = J(q,0,1,e);
|
||||
const double J22 = J(q,1,1,e);
|
||||
const double w_detJ = W[q] / (J11*J22) - (J21*J12);
|
||||
|
||||
if (coeffDim == 3 || coeffDim == 4) // Matrix coefficient version
|
||||
{
|
||||
// First compute entries of R = MJ
|
||||
const double M11 = coeff(i11, q, e);
|
||||
const double M12 = (!symmetric) ? coeff(i12, q, e) : coeff(1, q, e);
|
||||
const double M21 = (!symmetric) ? coeff(i21, q, e) : M12;
|
||||
const double M22 = (!symmetric) ? coeff(i22, q, e) : coeff(2, q, e);
|
||||
|
||||
const double R11 = M11*J11 + M12*J21;
|
||||
const double R12 = M11*J12 + M12*J22;
|
||||
const double R21 = M21*J11 + M22*J21;
|
||||
const double R22 = M21*J12 + M22*J22;
|
||||
|
||||
// Now set y to J^{-1} R
|
||||
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
|
||||
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
|
||||
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
|
||||
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
|
||||
}
|
||||
else if (coeffDim == 2) // Vector coefficient version
|
||||
{
|
||||
const double D1 = coeff(0, q, e);
|
||||
const double D2 = coeff(1, q, e);
|
||||
const double R11 = D1*J11;
|
||||
const double R12 = D1*J12;
|
||||
const double R21 = D2*J21;
|
||||
const double R22 = D2*J22;
|
||||
y(i11,q,e) = w_detJ * ( J22*R11 - J12*R21); // 1,1
|
||||
y(i12,q,e) = w_detJ * ( J22*R12 - J12*R22); // 1,2
|
||||
y(i21,q,e) = w_detJ * (-J21*R11 + J11*R21); // 2,1
|
||||
y(i22,q,e) = w_detJ * (-J21*R12 + J11*R22); // 2,2
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Mass operator for H(curl) and H(div) functions, using Piola transformations
|
||||
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
|
||||
void PAHcurlHdivMassApply3D(const int D1D,
|
||||
const int D1Dtest,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool scalarCoeff,
|
||||
const bool trialHcurl,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 3;
|
||||
|
||||
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(_Bot.Read(), D1Dtest-1, Q1D);
|
||||
auto Bct = Reshape(_Bct.Read(), D1Dtest, Q1D);
|
||||
auto op = Reshape(_op.Read(), scalarCoeff ? 1 : 9, Q1D, Q1D, Q1D, NE);
|
||||
auto x = Reshape(_x.Read(), 3*(D1D-1)*D1D*(trialHcurl ? D1D : D1D-1), NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 3*(D1Dtest-1)*D1Dtest*
|
||||
(trialHcurl ? D1Dtest-1 : D1Dtest), NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
mass[qz][qy][qx][c] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z trial components
|
||||
{
|
||||
const int D1Dz = trialHcurl ? ((c == 2) ? D1D - 1 : D1D) :
|
||||
((c == 2) ? D1D : D1D - 1);
|
||||
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
|
||||
((c == 1) ? D1D : D1D - 1);
|
||||
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
|
||||
((c == 0) ? D1D : D1D - 1);
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
double massXY[MAX_Q1D][MAX_Q1D];
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massXY[qy][qx] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double massX[MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massX[qx] = 0.0;
|
||||
}
|
||||
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
const double t = x(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
|
||||
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
|
||||
}
|
||||
}
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
|
||||
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double wx = massX[qx];
|
||||
massXY[qy][qx] += wx * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
const double wz = trialHcurl ? ((c == 2) ? Bo(qz,dz) : Bc(qz,dz)) :
|
||||
((c == 2) ? Bc(qz,dz) : Bo(qz,dz));
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osc += D1Dx * D1Dy * D1Dz;
|
||||
} // loop (c) over components
|
||||
|
||||
// Apply D operator.
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double O11 = op(0,qx,qy,qz,e);
|
||||
const double O12 = scalarCoeff ? 0.0 : op(1,qx,qy,qz,e);
|
||||
const double O13 = scalarCoeff ? 0.0 : op(2,qx,qy,qz,e);
|
||||
const double O21 = scalarCoeff ? 0.0 : op(3,qx,qy,qz,e);
|
||||
const double O22 = scalarCoeff ? O11 : op(4,qx,qy,qz,e);
|
||||
const double O23 = scalarCoeff ? 0.0 : op(5,qx,qy,qz,e);
|
||||
const double O31 = scalarCoeff ? 0.0 : op(6,qx,qy,qz,e);
|
||||
const double O32 = scalarCoeff ? 0.0 : op(7,qx,qy,qz,e);
|
||||
const double O33 = scalarCoeff ? O11 : op(8,qx,qy,qz,e);
|
||||
const double massX = mass[qz][qy][qx][0];
|
||||
const double massY = mass[qz][qy][qx][1];
|
||||
const double massZ = mass[qz][qy][qx][2];
|
||||
mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
|
||||
mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
|
||||
mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int qz = 0; qz < Q1D; ++qz)
|
||||
{
|
||||
double massXY[HDIV_MAX_D1D][HDIV_MAX_D1D];
|
||||
|
||||
osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y, z test components
|
||||
{
|
||||
const int D1Dz = trialHcurl ? ((c == 2) ? D1Dtest : D1Dtest - 1) :
|
||||
((c == 2) ? D1Dtest - 1 : D1Dtest);
|
||||
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
|
||||
((c == 1) ? D1Dtest - 1 : D1Dtest);
|
||||
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
|
||||
((c == 0) ? D1Dtest - 1 : D1Dtest);
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] = 0.0;
|
||||
}
|
||||
}
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double massX[HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] += mass[qz][qy][qx][c] * (trialHcurl ?
|
||||
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
|
||||
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
|
||||
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massXY[dy][dx] += massX[dx] * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int dz = 0; dz < D1Dz; ++dz)
|
||||
{
|
||||
const double wz = trialHcurl ? ((c == 2) ? Bct(dz,qz) : Bot(dz,qz)) :
|
||||
((c == 2) ? Bot(dz,qz) : Bct(dz,qz));
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
|
||||
massXY[dy][dx] * wz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osc += D1Dx * D1Dy * D1Dz;
|
||||
} // loop c
|
||||
} // loop qz
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
// Mass operator for H(curl) and H(div) functions, using Piola transformations
|
||||
// u = dF^{-T} \hat{u} in H(curl), v = (1 / det dF) dF \hat{v} in H(div).
|
||||
void PAHcurlHdivMassApply2D(const int D1D,
|
||||
const int D1Dtest,
|
||||
const int Q1D,
|
||||
const int NE,
|
||||
const bool scalarCoeff,
|
||||
const bool trialHcurl,
|
||||
const Array<double> &_Bo,
|
||||
const Array<double> &_Bc,
|
||||
const Array<double> &_Bot,
|
||||
const Array<double> &_Bct,
|
||||
const Vector &_op,
|
||||
const Vector &_x,
|
||||
Vector &_y)
|
||||
{
|
||||
constexpr static int MAX_D1D = HCURL_MAX_D1D;
|
||||
constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
|
||||
|
||||
MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D");
|
||||
MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D");
|
||||
constexpr static int VDIM = 2;
|
||||
|
||||
auto Bo = Reshape(_Bo.Read(), Q1D, D1D-1);
|
||||
auto Bc = Reshape(_Bc.Read(), Q1D, D1D);
|
||||
auto Bot = Reshape(_Bot.Read(), D1Dtest-1, Q1D);
|
||||
auto Bct = Reshape(_Bct.Read(), D1Dtest, Q1D);
|
||||
auto op = Reshape(_op.Read(), scalarCoeff ? 1 : 4, Q1D, Q1D, NE);
|
||||
auto x = Reshape(_x.Read(), 2*(D1D-1)*D1D, NE);
|
||||
auto y = Reshape(_y.ReadWrite(), 2*(D1Dtest-1)*D1Dtest, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
double mass[MAX_Q1D][MAX_Q1D][VDIM];
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
for (int c = 0; c < VDIM; ++c)
|
||||
{
|
||||
mass[qy][qx][c] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y trial components
|
||||
{
|
||||
const int D1Dy = trialHcurl ? ((c == 1) ? D1D - 1 : D1D) :
|
||||
((c == 1) ? D1D : D1D - 1);
|
||||
const int D1Dx = trialHcurl ? ((c == 0) ? D1D - 1 : D1D) :
|
||||
((c == 0) ? D1D : D1D - 1);
|
||||
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
double massX[MAX_Q1D];
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massX[qx] = 0.0;
|
||||
}
|
||||
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
const double t = x(dx + (dy * D1Dx) + osc, e);
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
massX[qx] += t * (trialHcurl ? ((c == 0) ? Bo(qx,dx) : Bc(qx,dx)) :
|
||||
((c == 0) ? Bc(qx,dx) : Bo(qx,dx)));
|
||||
}
|
||||
}
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
const double wy = trialHcurl ? ((c == 1) ? Bo(qy,dy) : Bc(qy,dy)) :
|
||||
((c == 1) ? Bc(qy,dy) : Bo(qy,dy));
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
mass[qy][qx][c] += massX[qx] * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osc += D1Dx * D1Dy;
|
||||
} // loop (c) over components
|
||||
|
||||
// Apply D operator.
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
const double O11 = op(0,qx,qy,e);
|
||||
const double O12 = scalarCoeff ? 0.0 : op(1,qx,qy,e);
|
||||
const double O21 = scalarCoeff ? 0.0 : op(2,qx,qy,e);
|
||||
const double O22 = scalarCoeff ? O11 : op(3,qx,qy,e);
|
||||
const double massX = mass[qy][qx][0];
|
||||
const double massY = mass[qy][qx][1];
|
||||
mass[qy][qx][0] = (O11*massX)+(O12*massY);
|
||||
mass[qy][qx][1] = (O21*massX)+(O22*massY);
|
||||
}
|
||||
}
|
||||
|
||||
osc = 0;
|
||||
for (int c = 0; c < VDIM; ++c) // loop over x, y test components
|
||||
{
|
||||
const int D1Dy = trialHcurl ? ((c == 1) ? D1Dtest : D1Dtest - 1) :
|
||||
((c == 1) ? D1Dtest - 1 : D1Dtest);
|
||||
const int D1Dx = trialHcurl ? ((c == 0) ? D1Dtest : D1Dtest - 1) :
|
||||
((c == 0) ? D1Dtest - 1 : D1Dtest);
|
||||
|
||||
for (int qy = 0; qy < Q1D; ++qy)
|
||||
{
|
||||
double massX[HDIV_MAX_D1D];
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] = 0.0;
|
||||
}
|
||||
for (int qx = 0; qx < Q1D; ++qx)
|
||||
{
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
massX[dx] += mass[qy][qx][c] * (trialHcurl ?
|
||||
((c == 0) ? Bct(dx,qx) : Bot(dx,qx)) :
|
||||
((c == 0) ? Bot(dx,qx) : Bct(dx,qx)));
|
||||
}
|
||||
}
|
||||
for (int dy = 0; dy < D1Dy; ++dy)
|
||||
{
|
||||
const double wy = trialHcurl ? ((c == 1) ? Bct(dy,qy) : Bot(dy,qy)) :
|
||||
((c == 1) ? Bot(dy,qy) : Bct(dy,qy));
|
||||
for (int dx = 0; dx < D1Dx; ++dx)
|
||||
{
|
||||
y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
osc += D1Dx * D1Dy;
|
||||
} // loop c
|
||||
}); // end of element loop
|
||||
}
|
||||
|
||||
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fel = fes.GetFE(0);
|
||||
AssemblePA(fes, fes);
|
||||
}
|
||||
|
||||
const VectorTensorFiniteElement *el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(fel);
|
||||
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
const FiniteElementSpace &test_fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const VectorTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
|
||||
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const VectorTensorFiniteElement *test_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
|
||||
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
const int dims = el->GetDim();
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
|
||||
@@ -164,36 +721,101 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
dim = mesh->Dimension();
|
||||
MFEM_VERIFY(dim == 2 || dim == 3, "");
|
||||
|
||||
ne = fes.GetNE();
|
||||
ne = trial_fes.GetNE();
|
||||
MFEM_VERIFY(ne == test_fes.GetNE(),
|
||||
"Different meshes for test and trial spaces");
|
||||
geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
|
||||
mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
|
||||
mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
|
||||
dofs1D = mapsC->ndof;
|
||||
quad1D = mapsC->nqpt;
|
||||
|
||||
mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
mapsOtest = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
|
||||
dofs1Dtest = mapsCtest->ndof;
|
||||
|
||||
MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
|
||||
|
||||
pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
|
||||
trial_fetype = trial_el->GetDerivType();
|
||||
test_fetype = test_el->GetDerivType();
|
||||
|
||||
const int coeffDim = VQ ? VQ->GetVDim() : 1;
|
||||
const int MQsymmDim = MQ ? (MQ->GetWidth() * (MQ->GetWidth() + 1)) / 2 : 0;
|
||||
const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0;
|
||||
const int MQdim = MQ ? (MQ->IsSymmetric() ? MQsymmDim : MQfullDim) : 0;
|
||||
const int coeffDim = MQ ? MQdim : (VQ ? VQ->GetVDim() : 1);
|
||||
|
||||
symmetric = MQ ? MQ->IsSymmetric() : true;
|
||||
|
||||
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
|
||||
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
|
||||
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
|
||||
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
|
||||
|
||||
if ((trial_curl && test_div) || (trial_div && test_curl))
|
||||
pa_data.SetSize((coeffDim == 1 ? 1 : dim*dim) * nq * ne,
|
||||
Device::GetMemoryType());
|
||||
else
|
||||
pa_data.SetSize((symmetric ? symmDims : MQfullDim) * nq * ne,
|
||||
Device::GetMemoryType());
|
||||
|
||||
Vector coeff(coeffDim * ne * nq);
|
||||
coeff = 1.0;
|
||||
auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
|
||||
if (Q || VQ)
|
||||
if (Q || VQ || MQ)
|
||||
{
|
||||
Vector D(VQ ? coeffDim : 0);
|
||||
DenseMatrix M;
|
||||
Vector Msymm;
|
||||
if (MQ)
|
||||
{
|
||||
if (symmetric)
|
||||
{
|
||||
Msymm.SetSize(MQsymmDim);
|
||||
}
|
||||
else
|
||||
{
|
||||
M.SetSize(dim);
|
||||
}
|
||||
}
|
||||
|
||||
if (VQ)
|
||||
{
|
||||
MFEM_VERIFY(coeffDim == dim, "");
|
||||
}
|
||||
if (MQ)
|
||||
{
|
||||
MFEM_VERIFY(coeffDim == MQdim, "");
|
||||
MFEM_VERIFY(MQ->GetHeight() == dim && MQ->GetWidth() == dim, "");
|
||||
}
|
||||
|
||||
for (int e=0; e<ne; ++e)
|
||||
{
|
||||
ElementTransformation *tr = mesh->GetElementTransformation(e);
|
||||
for (int p=0; p<nq; ++p)
|
||||
{
|
||||
if (VQ)
|
||||
if (MQ)
|
||||
{
|
||||
if (MQ->IsSymmetric())
|
||||
{
|
||||
MQ->EvalSymmetric(Msymm, *tr, ir->IntPoint(p));
|
||||
|
||||
for (int i=0; i<MQsymmDim; ++i)
|
||||
{
|
||||
coeffh(i, p, e) = Msymm[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MQ->Eval(M, *tr, ir->IntPoint(p));
|
||||
|
||||
for (int i=0; i<dim; ++i)
|
||||
for (int j=0; j<dim; ++j)
|
||||
{
|
||||
coeffh(j+(i*dim), p, e) = M(i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (VQ)
|
||||
{
|
||||
VQ->Eval(D, *tr, ir->IntPoint(p));
|
||||
for (int i=0; i<coeffDim; ++i)
|
||||
@@ -209,28 +831,44 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
}
|
||||
}
|
||||
|
||||
fetype = el->GetDerivType();
|
||||
|
||||
if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 3)
|
||||
if (trial_curl && test_curl && dim == 3)
|
||||
{
|
||||
PAHcurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (el->GetDerivType() == mfem::FiniteElement::CURL && dim == 2)
|
||||
else if (trial_curl && test_curl && dim == 2)
|
||||
{
|
||||
PAHcurlSetup2D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 3)
|
||||
else if (trial_div && test_div && dim == 3)
|
||||
{
|
||||
PAHdivSetup3D(quad1D, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (el->GetDerivType() == mfem::FiniteElement::DIV && dim == 2)
|
||||
else if (trial_div && test_div && dim == 2)
|
||||
{
|
||||
PAHdivSetup2D(quad1D, ne, ir->GetWeights(), geom->J,
|
||||
coeff, pa_data);
|
||||
}
|
||||
else if (((trial_curl && test_div) || (trial_div && test_curl)) &&
|
||||
test_fel->GetOrder() == trial_fel->GetOrder())
|
||||
{
|
||||
if (coeffDim == 1)
|
||||
{
|
||||
PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool tr = (trial_div && test_curl);
|
||||
if (dim == 3)
|
||||
PAHcurlHdivSetup3D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
|
||||
geom->J, coeff, pa_data);
|
||||
else
|
||||
PAHcurlHdivSetup2D(quad1D, coeffDim, ne, tr, ir->GetWeights(),
|
||||
geom->J, coeff, pa_data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
@@ -241,12 +879,13 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
{
|
||||
if (dim == 3)
|
||||
{
|
||||
if (fetype == mfem::FiniteElement::CURL)
|
||||
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
|
||||
{
|
||||
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne,
|
||||
PAHcurlMassAssembleDiagonal3D(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
}
|
||||
else if (fetype == mfem::FiniteElement::DIV)
|
||||
else if (trial_fetype == mfem::FiniteElement::DIV &&
|
||||
test_fetype == trial_fetype)
|
||||
{
|
||||
PAHdivMassAssembleDiagonal3D(dofs1D, quad1D, ne,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
@@ -258,12 +897,13 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fetype == mfem::FiniteElement::CURL)
|
||||
if (trial_fetype == mfem::FiniteElement::CURL && test_fetype == trial_fetype)
|
||||
{
|
||||
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne,
|
||||
PAHcurlMassAssembleDiagonal2D(dofs1D, quad1D, ne, symmetric,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
}
|
||||
else if (fetype == mfem::FiniteElement::DIV)
|
||||
else if (trial_fetype == mfem::FiniteElement::DIV &&
|
||||
test_fetype == trial_fetype)
|
||||
{
|
||||
PAHdivMassAssembleDiagonal2D(dofs1D, quad1D, ne,
|
||||
mapsO->B, mapsC->B, pa_data, diag);
|
||||
@@ -277,18 +917,37 @@ void VectorFEMassIntegrator::AssembleDiagonalPA(Vector& diag)
|
||||
|
||||
void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
{
|
||||
const bool trial_curl = (trial_fetype == mfem::FiniteElement::CURL);
|
||||
const bool trial_div = (trial_fetype == mfem::FiniteElement::DIV);
|
||||
const bool test_curl = (test_fetype == mfem::FiniteElement::CURL);
|
||||
const bool test_div = (test_fetype == mfem::FiniteElement::DIV);
|
||||
|
||||
if (dim == 3)
|
||||
{
|
||||
if (fetype == mfem::FiniteElement::CURL)
|
||||
if (trial_curl && test_curl)
|
||||
{
|
||||
PAHcurlMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
PAHcurlMassApply3D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
|
||||
mapsO->Bt, mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
else if (fetype == mfem::FiniteElement::DIV)
|
||||
else if (trial_div && test_div)
|
||||
{
|
||||
PAHdivMassApply3D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
else if (trial_curl && test_div)
|
||||
{
|
||||
const bool scalarCoeff = !(VQ || MQ);
|
||||
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
|
||||
true, mapsO->B, mapsC->B, mapsOtest->Bt,
|
||||
mapsCtest->Bt, pa_data, x, y);
|
||||
}
|
||||
else if (trial_div && test_curl)
|
||||
{
|
||||
const bool scalarCoeff = !(VQ || MQ);
|
||||
PAHcurlHdivMassApply3D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
|
||||
false, mapsO->B, mapsC->B, mapsOtest->Bt,
|
||||
mapsCtest->Bt, pa_data, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
@@ -296,16 +955,23 @@ void VectorFEMassIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fetype == mfem::FiniteElement::CURL)
|
||||
if (trial_curl && test_curl)
|
||||
{
|
||||
PAHcurlMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
PAHcurlMassApply2D(dofs1D, quad1D, ne, symmetric, mapsO->B, mapsC->B,
|
||||
mapsO->Bt, mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
else if (fetype == mfem::FiniteElement::DIV)
|
||||
else if (trial_div && test_div)
|
||||
{
|
||||
PAHdivMassApply2D(dofs1D, quad1D, ne, mapsO->B, mapsC->B, mapsO->Bt,
|
||||
mapsC->Bt, pa_data, x, y);
|
||||
}
|
||||
else if ((trial_curl && test_div) || (trial_div && test_curl))
|
||||
{
|
||||
const bool scalarCoeff = !(VQ || MQ);
|
||||
PAHcurlHdivMassApply2D(dofs1D, dofs1Dtest, quad1D, ne, scalarCoeff,
|
||||
trial_curl, mapsO->B, mapsC->B, mapsOtest->Bt,
|
||||
mapsCtest->Bt, pa_data, x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("Unknown kernel.");
|
||||
|
||||
@@ -319,6 +319,31 @@ void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
MFEM_VERIFY(symmetric && height == width && height < 4 && SymmFunction,
|
||||
"MatrixFunctionCoefficient is not symmetric");
|
||||
|
||||
double x[3];
|
||||
Vector transip(x, 3);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
K.SetSize((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
|
||||
|
||||
if (SymmFunction)
|
||||
{
|
||||
(*SymmFunction)(transip, K);
|
||||
}
|
||||
|
||||
if (Q)
|
||||
{
|
||||
K *= Q->Eval(T, ip, GetTime());
|
||||
}
|
||||
}
|
||||
|
||||
MatrixArrayCoefficient::MatrixArrayCoefficient (int dim)
|
||||
: MatrixCoefficient (dim)
|
||||
{
|
||||
|
||||
+34
-2
@@ -695,13 +695,16 @@ class MatrixCoefficient
|
||||
protected:
|
||||
int height, width;
|
||||
double time;
|
||||
bool symmetric;
|
||||
|
||||
public:
|
||||
/// Construct a dim x dim matrix coefficient.
|
||||
explicit MatrixCoefficient(int dim) { height = width = dim; time = 0.; }
|
||||
explicit MatrixCoefficient(int dim, bool symm=false)
|
||||
{ height = width = dim; time = 0.; symmetric = symm; }
|
||||
|
||||
/// Construct a h x w matrix coefficient.
|
||||
MatrixCoefficient(int h, int w) : height(h), width(w), time(0.) { }
|
||||
MatrixCoefficient(int h, int w, bool symm=false) :
|
||||
height(h), width(w), time(0.), symmetric(symm) { }
|
||||
|
||||
/// Set the time for time dependent coefficients
|
||||
void SetTime(double t) { time = t; }
|
||||
@@ -718,6 +721,9 @@ public:
|
||||
/// For backward compatibility get the width of the matrix.
|
||||
int GetVDim() const { return width; }
|
||||
|
||||
void SetSymmetric(bool s) { symmetric = s; }
|
||||
bool IsSymmetric() const { return symmetric; }
|
||||
|
||||
/** @brief Evaluate the matrix coefficient in the element described by @a T
|
||||
at the point @a ip, storing the result in @a K. */
|
||||
/** @note When this method is called, the caller must make sure that the
|
||||
@@ -726,6 +732,15 @@ public:
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip) = 0;
|
||||
|
||||
/** @brief Evaluate the upper triangular entries of the matrix coefficient
|
||||
in the symmetric case, similarly to Eval. Matrix entry (i,j) is stored
|
||||
in K[j - i + os_i] for 0 <= i <= j < width, os_0 = 0,
|
||||
os_{i+1} = os_i + width - i. That is, K = {M(0,0), ..., M(0,w-1),
|
||||
M(1,1), ..., M(1,w-1), ..., M(w-1,w-1) with w = width. */
|
||||
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{ mfem_error("MatrixCoefficient::EvalSymmetric"); }
|
||||
|
||||
virtual ~MatrixCoefficient() { }
|
||||
};
|
||||
|
||||
@@ -753,6 +768,7 @@ class MatrixFunctionCoefficient : public MatrixCoefficient
|
||||
{
|
||||
private:
|
||||
void (*Function)(const Vector &, DenseMatrix &);
|
||||
void (*SymmFunction)(const Vector &, Vector &);
|
||||
void (*TDFunction)(const Vector &, double, DenseMatrix &);
|
||||
Coefficient *Q;
|
||||
DenseMatrix mat;
|
||||
@@ -790,10 +806,26 @@ public:
|
||||
mat.SetSize(0);
|
||||
}
|
||||
|
||||
/// Construct a symmetric square matrix coefficient from a C-function
|
||||
/// defining a vector function used by EvalSymmetric
|
||||
MatrixFunctionCoefficient(int dim, void (*F)(const Vector &, Vector &),
|
||||
Coefficient *q = NULL)
|
||||
: MatrixCoefficient(dim, true), Q(q)
|
||||
{
|
||||
SymmFunction = F;
|
||||
Function = NULL;
|
||||
TDFunction = NULL;
|
||||
mat.SetSize(0);
|
||||
}
|
||||
|
||||
/// Evaluate the matrix coefficient at @a ip.
|
||||
virtual void Eval(DenseMatrix &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
/// Evaluate the symmetric matrix coefficient at @a ip.
|
||||
virtual void EvalSymmetric(Vector &K, ElementTransformation &T,
|
||||
const IntegrationPoint &ip);
|
||||
|
||||
virtual ~MatrixFunctionCoefficient() { }
|
||||
};
|
||||
|
||||
|
||||
+17
-3
@@ -77,6 +77,9 @@ public:
|
||||
|
||||
ElementTransformation();
|
||||
|
||||
/** @brief Force the reevaluation of the Jacobian in the next call. */
|
||||
void Reset() { EvalState = 0; }
|
||||
|
||||
/** @brief Set the integration point @a ip that weights and Jacobians will
|
||||
be evaluated at. */
|
||||
void SetIntPoint(const IntegrationPoint *ip)
|
||||
@@ -357,9 +360,17 @@ private:
|
||||
// Evaluate the Hessian of the transformation at the IntPoint and store it
|
||||
// in d2Fdx2.
|
||||
virtual const DenseMatrix &EvalHessian();
|
||||
|
||||
public:
|
||||
IsoparametricTransformation() : FElem(NULL) {}
|
||||
|
||||
/// Set the element that will be used to compute the transformations
|
||||
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
|
||||
void SetFE(const FiniteElement *FE)
|
||||
{
|
||||
MFEM_ASSERT(FE != NULL, "Must provide a valid FiniteElement object!");
|
||||
EvalState = (FE != FElem) ? 0 : EvalState;
|
||||
FElem = FE; geom = FE->GetGeomType();
|
||||
}
|
||||
|
||||
/// Get the current element used to compute the transformations
|
||||
const FiniteElement* GetFE() const { return FElem; }
|
||||
@@ -374,12 +385,15 @@ public:
|
||||
the column-vector of all basis functions evaluated at \f$ \hat x \f$ .
|
||||
The columns of @a P represent the control points in physical space
|
||||
defining the transformation. */
|
||||
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; }
|
||||
void SetPointMat(const DenseMatrix &pm) { PointMat = pm; EvalState = 0; }
|
||||
|
||||
/// Return the stored point matrix.
|
||||
const DenseMatrix &GetPointMat() const { return PointMat; }
|
||||
|
||||
/// Write access to the stored point matrix. Use with caution.
|
||||
/// @brief Write access to the stored point matrix. Use with caution.
|
||||
/** If the point matrix is altered using this member function the Reset
|
||||
function should also be called to force the reevaluation of the
|
||||
Jacobian, etc.. */
|
||||
DenseMatrix &GetPointMat() { return PointMat; }
|
||||
|
||||
/// Set the FiniteElement Geometry for the reference elements being used.
|
||||
|
||||
+167
@@ -7034,6 +7034,95 @@ void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d) const
|
||||
}
|
||||
}
|
||||
|
||||
void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d,
|
||||
Vector &d2) const
|
||||
{
|
||||
MFEM_VERIFY(etype == Barycentric,
|
||||
"Basis::Eval with second order derivatives not implemented for"
|
||||
" etype = " << etype);
|
||||
switch (etype)
|
||||
{
|
||||
case ChangeOfBasis:
|
||||
{
|
||||
CalcBasis(Ai.Width() - 1, y, x, w);
|
||||
Ai.Mult(x, u);
|
||||
Ai.Mult(w, d);
|
||||
// set d2 (not implemented yet)
|
||||
break;
|
||||
}
|
||||
case Barycentric:
|
||||
{
|
||||
int i, k, p = x.Size() - 1;
|
||||
double l, lp, lp2, lk, sk, si, sk2;
|
||||
|
||||
if (p == 0)
|
||||
{
|
||||
u(0) = 1.0;
|
||||
d(0) = 0.0;
|
||||
d2(0) = 0.0;
|
||||
return;
|
||||
}
|
||||
|
||||
lk = 1.0;
|
||||
for (k = 0; k < p; k++)
|
||||
{
|
||||
if (y >= (x(k) + x(k+1))/2)
|
||||
{
|
||||
lk *= y - x(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = k+1; i <= p; i++)
|
||||
{
|
||||
lk *= y - x(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
l = lk * (y - x(k));
|
||||
|
||||
sk = 0.0;
|
||||
sk2 = 0.0;
|
||||
for (i = 0; i < k; i++)
|
||||
{
|
||||
si = 1.0/(y - x(i));
|
||||
sk += si;
|
||||
sk2 -= si * si;
|
||||
u(i) = l * si * w(i);
|
||||
}
|
||||
u(k) = lk * w(k);
|
||||
for (i++; i <= p; i++)
|
||||
{
|
||||
si = 1.0/(y - x(i));
|
||||
sk += si;
|
||||
sk2 -= si * si;
|
||||
u(i) = l * si * w(i);
|
||||
}
|
||||
lp = l * sk + lk;
|
||||
lp2 = lp * sk + l * sk2 + sk * lk;
|
||||
|
||||
for (i = 0; i < k; i++)
|
||||
{
|
||||
d(i) = (lp * w(i) - u(i))/(y - x(i));
|
||||
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
|
||||
}
|
||||
d(k) = sk * u(k);
|
||||
d2(k) = sk2 * u(k) + sk * d(k);
|
||||
for (i++; i <= p; i++)
|
||||
{
|
||||
d(i) = (lp * w(i) - u(i))/(y - x(i));
|
||||
d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Positive:
|
||||
CalcBernstein(x.Size() - 1, y, u, d);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
const int *Poly_1D::Binom(const int p)
|
||||
{
|
||||
if (binom.NumCols() <= p)
|
||||
@@ -7589,6 +7678,7 @@ H1_SegmentElement::H1_SegmentElement(const int p, const int btype)
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p+1);
|
||||
dshape_x.SetSize(p+1);
|
||||
d2shape_x.SetSize(p+1);
|
||||
#endif
|
||||
|
||||
Nodes.IntPoint(0).x = cp[0];
|
||||
@@ -7637,6 +7727,25 @@ void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), dshape_x(p+1), d2shape_x(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
|
||||
Hessian(0,0) = d2shape_x(0);
|
||||
Hessian(1,0) = d2shape_x(p);
|
||||
for (int i = 1; i < p; i++)
|
||||
{
|
||||
Hessian(i+1,0) = d2shape_x(i);
|
||||
}
|
||||
}
|
||||
|
||||
void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
@@ -7677,6 +7786,8 @@ H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype)
|
||||
shape_y.SetSize(p1);
|
||||
dshape_x.SetSize(p1);
|
||||
dshape_y.SetSize(p1);
|
||||
d2shape_x.SetSize(p1);
|
||||
d2shape_y.SetSize(p1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
@@ -7730,6 +7841,30 @@ void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1),
|
||||
d2shape_x(p+1), d2shape_y(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
|
||||
|
||||
for (int o = 0, j = 0; j <= p; j++)
|
||||
{
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j);
|
||||
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j);
|
||||
Hessian(dof_map[o],2) = shape_x(i)*d2shape_y(j); o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
@@ -7793,6 +7928,9 @@ H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype)
|
||||
dshape_x.SetSize(p1);
|
||||
dshape_y.SetSize(p1);
|
||||
dshape_z.SetSize(p1);
|
||||
d2shape_x.SetSize(p1);
|
||||
d2shape_y.SetSize(p1);
|
||||
d2shape_z.SetSize(p1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
@@ -7849,6 +7987,35 @@ void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p+1), shape_y(p+1), shape_z(p+1);
|
||||
Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1);
|
||||
Vector d2shape_x(p+1), d2shape_y(p+1), ds2hape_z(p+1);
|
||||
#endif
|
||||
|
||||
basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x);
|
||||
basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y);
|
||||
basis1d.Eval(ip.z, shape_z, dshape_z, d2shape_z);
|
||||
|
||||
for (int o = 0, k = 0; k <= p; k++)
|
||||
for (int j = 0; j <= p; j++)
|
||||
for (int i = 0; i <= p; i++)
|
||||
{
|
||||
Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],2) = dshape_x(i)* shape_y(j)* dshape_z(k);
|
||||
Hessian(dof_map[o],3) = shape_x(i)*d2shape_y(j)* shape_z(k);
|
||||
Hessian(dof_map[o],4) = shape_x(i)* dshape_y(j)* dshape_z(k);
|
||||
Hessian(dof_map[o],5) = shape_x(i)* shape_y(j)*d2shape_z(k);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
|
||||
void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
+12
-4
@@ -446,7 +446,7 @@ public:
|
||||
/** Each row of the result DenseMatrix @a Hessian contains upper triangular
|
||||
part of the Hessian of one shape function.
|
||||
The order in 2D is {u_xx, u_xy, u_yy}.
|
||||
The size (#dof x (#dim (#dim-1)/2) of @a Hessian must be set in advance.*/
|
||||
The size (#dof x (#dim (#dim+1)/2) of @a Hessian must be set in advance.*/
|
||||
virtual void CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
|
||||
@@ -1850,6 +1850,7 @@ public:
|
||||
Basis(const int p, const double *nodes, EvalType etype = Barycentric);
|
||||
void Eval(const double x, Vector &u) const;
|
||||
void Eval(const double x, Vector &u, Vector &d) const;
|
||||
void Eval(const double x, Vector &u, Vector &d, Vector &d2) const;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -2100,7 +2101,7 @@ class H1_SegmentElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, dshape_x;
|
||||
mutable Vector shape_x, dshape_x, d2shape_x;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2109,6 +2110,8 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
@@ -2118,7 +2121,7 @@ class H1_QuadrilateralElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y;
|
||||
mutable Vector shape_x, shape_y, dshape_x, dshape_y, d2shape_x, d2shape_y;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2128,6 +2131,8 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
@@ -2137,7 +2142,8 @@ class H1_HexahedronElement : public NodalTensorFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z;
|
||||
mutable Vector shape_x, shape_y, shape_z, dshape_x, dshape_y, dshape_z,
|
||||
d2shape_x, d2shape_y, d2shape_z;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -2146,6 +2152,8 @@ public:
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &Hessian) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ void QuadratureInterpolator::Eval2D(
|
||||
const int nq = maps.nqpt;
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int NMAX = NQ > ND ? NQ : ND;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
MFEM_VERIFY(ND <= MAX_ND2D, "");
|
||||
MFEM_VERIFY(NQ <= MAX_NQ2D, "");
|
||||
@@ -72,22 +73,24 @@ void QuadratureInterpolator::Eval2D(
|
||||
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
|
||||
auto der = Reshape(q_der.Write(), NQ, VDIM, 2, NE);
|
||||
auto det = Reshape(q_det.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
|
||||
{
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int max_ND = T_ND ? T_ND : MAX_ND2D;
|
||||
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM2D;
|
||||
double s_E[max_VDIM*max_ND];
|
||||
for (int d = 0; d < ND; d++)
|
||||
MFEM_SHARED double s_E[max_VDIM*max_ND];
|
||||
MFEM_FOREACH_THREAD(d, x, ND)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
s_E[c+d*VDIM] = E(d,c,e);
|
||||
}
|
||||
}
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(q, x, NQ)
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
@@ -150,6 +153,7 @@ void QuadratureInterpolator::Eval3D(
|
||||
const int nq = maps.nqpt;
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int NMAX = NQ > ND ? NQ : ND;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
MFEM_VERIFY(ND <= MAX_ND3D, "");
|
||||
MFEM_VERIFY(NQ <= MAX_NQ3D, "");
|
||||
@@ -160,22 +164,24 @@ void QuadratureInterpolator::Eval3D(
|
||||
auto val = Reshape(q_val.Write(), NQ, VDIM, NE);
|
||||
auto der = Reshape(q_der.Write(), NQ, VDIM, 3, NE);
|
||||
auto det = Reshape(q_det.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
|
||||
{
|
||||
const int ND = T_ND ? T_ND : nd;
|
||||
const int NQ = T_NQ ? T_NQ : nq;
|
||||
const int VDIM = T_VDIM ? T_VDIM : vdim;
|
||||
constexpr int max_ND = T_ND ? T_ND : MAX_ND3D;
|
||||
constexpr int max_VDIM = T_VDIM ? T_VDIM : MAX_VDIM3D;
|
||||
double s_E[max_VDIM*max_ND];
|
||||
for (int d = 0; d < ND; d++)
|
||||
MFEM_SHARED double s_E[max_VDIM*max_ND];
|
||||
MFEM_FOREACH_THREAD(d, x, ND)
|
||||
{
|
||||
for (int c = 0; c < VDIM; c++)
|
||||
{
|
||||
s_E[c+d*VDIM] = E(d,c,e);
|
||||
}
|
||||
}
|
||||
for (int q = 0; q < NQ; ++q)
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(q, x, NQ)
|
||||
{
|
||||
if (eval_flags & VALUES)
|
||||
{
|
||||
|
||||
+46
-48
@@ -1968,11 +1968,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
Jpt.SetSize(dim);
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(el);
|
||||
const IntegrationRule &ir = EnergyIntegrationRule(el);
|
||||
|
||||
energy = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
DenseTensor Jtr(dim, dim, ir.GetNPoints());
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
|
||||
|
||||
// Limited case.
|
||||
Vector shape, p, p0, d_vals;
|
||||
@@ -1989,11 +1989,11 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
nodes0->GetSubVector(pos_dofs, pos0V);
|
||||
if (lim_dist)
|
||||
{
|
||||
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
|
||||
lim_dist->GetValues(T.ElementNo, ir, d_vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
|
||||
d_vals.SetSize(ir.GetNPoints()); d_vals = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2019,13 +2019,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
Vector zeta_q, zeta0_q;
|
||||
if (adaptive_limiting)
|
||||
{
|
||||
zeta->GetValues(T.ElementNo, *ir, zeta_q);
|
||||
zeta_0->GetValues(T.ElementNo, *ir, zeta0_q);
|
||||
zeta->GetValues(T.ElementNo, ir, zeta_q);
|
||||
zeta_0->GetValues(T.ElementNo, ir, zeta0_q);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
const DenseMatrix &Jtr_i = Jtr(i);
|
||||
metric->SetTargetJacobian(Jtr_i);
|
||||
CalcInverse(Jtr_i, Jrt);
|
||||
@@ -2105,14 +2105,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
elvect.SetSize(dof*dim);
|
||||
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
const IntegrationRule &ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir.GetNPoints();
|
||||
|
||||
elvect = 0.0;
|
||||
Vector weights(nqp);
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
DenseTensor dJtr(dim, dim, dim*nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
|
||||
|
||||
// Limited case.
|
||||
DenseMatrix pos0;
|
||||
@@ -2129,7 +2129,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
nodes0->GetSubVector(pos_dofs, pos0V);
|
||||
if (lim_dist)
|
||||
{
|
||||
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
|
||||
lim_dist->GetValues(T.ElementNo, ir, d_vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2149,7 +2149,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
|
||||
if (exact_action)
|
||||
{
|
||||
targetC->ComputeElementTargetsGradient(*ir, elfun, *Tpr, dJtr);
|
||||
targetC->ComputeElementTargetsGradient(ir, elfun, *Tpr, dJtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2159,7 +2159,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
const DenseMatrix &Jtr_q = Jtr(q);
|
||||
metric->SetTargetJacobian(Jtr_q);
|
||||
CalcInverse(Jtr_q, Jrt);
|
||||
@@ -2186,7 +2186,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
DenseMatrix dwdx(dim);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
const DenseMatrix &dJtr_q = dJtr(q + d*ir->GetNPoints());
|
||||
const DenseMatrix &dJtr_q = dJtr(q + d * nqp);
|
||||
Mult(Jrt, dJtr_q, dwdx );
|
||||
d_detW_dx(d) = dwdx.Trace();
|
||||
}
|
||||
@@ -2221,7 +2221,7 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
}
|
||||
}
|
||||
|
||||
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, *ir, PMatO); }
|
||||
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, ir, PMatO); }
|
||||
|
||||
delete Tpr;
|
||||
}
|
||||
@@ -2240,13 +2240,13 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
elmat.SetSize(dof*dim);
|
||||
|
||||
const IntegrationRule *ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
const IntegrationRule &ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir.GetNPoints();
|
||||
|
||||
elmat = 0.0;
|
||||
Vector weights(nqp);
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
|
||||
|
||||
// Limited case.
|
||||
DenseMatrix pos0, grad_grad;
|
||||
@@ -2263,7 +2263,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
nodes0->GetSubVector(pos_dofs, pos0V);
|
||||
if (lim_dist)
|
||||
{
|
||||
lim_dist->GetValues(T.ElementNo, *ir, d_vals);
|
||||
lim_dist->GetValues(T.ElementNo, ir, d_vals);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2285,7 +2285,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
const DenseMatrix &Jtr_q = Jtr(q);
|
||||
metric->SetTargetJacobian(Jtr_q);
|
||||
CalcInverse(Jtr_q, Jrt);
|
||||
@@ -2302,7 +2302,6 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
|
||||
// TODO: derivatives of adaptivity-based targets.
|
||||
|
||||
// TODO optimize by symmetry.
|
||||
if (coeff0)
|
||||
{
|
||||
el.CalcShape(ip, shape);
|
||||
@@ -2328,7 +2327,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
}
|
||||
}
|
||||
|
||||
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, *ir, elmat); }
|
||||
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, ir, elmat); }
|
||||
|
||||
delete Tpr;
|
||||
}
|
||||
@@ -2499,10 +2498,10 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
|
||||
// Contributions from adaptive limiting (exact derivatives).
|
||||
if (zeta)
|
||||
{
|
||||
const IntegrationRule *ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
const IntegrationRule &ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir.GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
|
||||
|
||||
IsoparametricTransformation Tpr;
|
||||
Tpr.SetFE(&el);
|
||||
@@ -2514,11 +2513,11 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
|
||||
Vector weights(nqp);
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
|
||||
weights(q) = ir.IntPoint(q).weight * Jtr(q).Det();
|
||||
}
|
||||
|
||||
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
||||
AssembleElemVecAdaptLim(el, weights, Tpr, *ir, PMatO);
|
||||
AssembleElemVecAdaptLim(el, weights, Tpr, ir, PMatO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2595,10 +2594,10 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
|
||||
// Contributions from adaptive limiting.
|
||||
if (zeta)
|
||||
{
|
||||
const IntegrationRule *ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
const IntegrationRule &ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir.GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, ir, elfun, Jtr);
|
||||
|
||||
IsoparametricTransformation Tpr;
|
||||
Tpr.SetFE(&el);
|
||||
@@ -2610,10 +2609,10 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
|
||||
Vector weights(nqp);
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
|
||||
weights(q) = ir.IntPoint(q).weight * Jtr(q).Det();
|
||||
}
|
||||
|
||||
AssembleElemGradAdaptLim(el, weights, Tpr, *ir, elmat);
|
||||
AssembleElemGradAdaptLim(el, weights, Tpr, ir, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2643,33 +2642,32 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
|
||||
Array<int> vdofs;
|
||||
Vector x_vals;
|
||||
const FiniteElementSpace* const fes = x.FESpace();
|
||||
const FiniteElement *fe = fes->GetFE(0);
|
||||
|
||||
const int dof = fes->GetFE(0)->GetDof(), dim = fes->GetFE(0)->GetDim();
|
||||
|
||||
DSh.SetSize(dof, dim);
|
||||
const int dim = fes->GetMesh()->Dimension();
|
||||
Jrt.SetSize(dim);
|
||||
Jpr.SetSize(dim);
|
||||
Jpt.SetSize(dim);
|
||||
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
|
||||
const int nqp = ir->GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
|
||||
metric_energy = 0.0;
|
||||
lim_energy = 0.0;
|
||||
for (int i = 0; i < fes->GetNE(); i++)
|
||||
{
|
||||
fe = fes->GetFE(i);
|
||||
const FiniteElement *fe = fes->GetFE(i);
|
||||
const IntegrationRule &ir = EnergyIntegrationRule(*fe);
|
||||
const int nqp = ir.GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
const int dof = fe->GetDof();
|
||||
DSh.SetSize(dof, dim);
|
||||
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
x.GetSubVector(vdofs, x_vals);
|
||||
PMatI.UseExternalData(x_vals.GetData(), dof, dim);
|
||||
|
||||
targetC->ComputeElementTargets(i, *fe, *ir, x_vals, Jtr);
|
||||
targetC->ComputeElementTargets(i, *fe, ir, x_vals, Jtr);
|
||||
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
metric->SetTargetJacobian(Jtr(q));
|
||||
CalcInverse(Jtr(q), Jrt);
|
||||
const double weight = ip.weight * Jtr(q).Det();
|
||||
@@ -2693,9 +2691,9 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
const FiniteElementSpace &fes)
|
||||
{
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
|
||||
const IntegrationRule &ir = EnergyIntegrationRule(*fe);
|
||||
const int NE = fes.GetMesh()->GetNE(), dim = fe->GetDim(),
|
||||
dof = fe->GetDof(), nsp = ir->GetNPoints();
|
||||
dof = fe->GetDof(), nsp = ir.GetNPoints();
|
||||
|
||||
Array<int> xdofs(dof * dim);
|
||||
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
|
||||
@@ -2712,7 +2710,7 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
detv_sum = 0.;
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes.GetFE(i)->CalcDShape(ir->IntPoint(j), dshape);
|
||||
fes.GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
detv_sum += std::fabs(Jpr.Det());
|
||||
}
|
||||
|
||||
+22
-6
@@ -890,6 +890,10 @@ protected:
|
||||
TMOP_QualityMetric *metric; // not owned
|
||||
const TargetConstructor *targetC; // not owned
|
||||
|
||||
// Custom integration rules.
|
||||
IntegrationRules *IntegRules;
|
||||
int integ_order;
|
||||
|
||||
// Weight Coefficient multiplying the quality metric term.
|
||||
Coefficient *coeff1; // not owned, if NULL -> coeff1 is 1.
|
||||
// Normalization factor for the metric term.
|
||||
@@ -988,17 +992,21 @@ protected:
|
||||
nodes0 = NULL; coeff0 = NULL; lim_dist = NULL; lim_func = NULL;
|
||||
}
|
||||
|
||||
const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const
|
||||
const IntegrationRule &EnergyIntegrationRule(const FiniteElement &el) const
|
||||
{
|
||||
return (IntRule) ? IntRule
|
||||
/* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3));
|
||||
if (IntegRules)
|
||||
{
|
||||
return IntegRules->Get(el.GetGeomType(), integ_order);
|
||||
}
|
||||
return (IntRule) ? *IntRule
|
||||
/* */ : IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3);
|
||||
}
|
||||
const IntegrationRule *ActionIntegrationRule(const FiniteElement &el) const
|
||||
const IntegrationRule &ActionIntegrationRule(const FiniteElement &el) const
|
||||
{
|
||||
// TODO the energy most likely needs less integration points.
|
||||
return EnergyIntegrationRule(el);
|
||||
}
|
||||
const IntegrationRule *GradientIntegrationRule(const FiniteElement &el) const
|
||||
const IntegrationRule &GradientIntegrationRule(const FiniteElement &el) const
|
||||
{
|
||||
// TODO the action and energy most likely need less integration points.
|
||||
return EnergyIntegrationRule(el);
|
||||
@@ -1008,7 +1016,7 @@ public:
|
||||
/** @param[in] m TMOP_QualityMetric that will be integrated (not owned).
|
||||
@param[in] tc Target-matrix construction algorithm to use (not owned). */
|
||||
TMOP_Integrator(TMOP_QualityMetric *m, TargetConstructor *tc)
|
||||
: metric(m), targetC(tc),
|
||||
: metric(m), targetC(tc), IntegRules(NULL), integ_order(-1),
|
||||
coeff1(NULL), metric_normal(1.0),
|
||||
nodes0(NULL), coeff0(NULL),
|
||||
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
|
||||
@@ -1019,6 +1027,14 @@ public:
|
||||
|
||||
~TMOP_Integrator();
|
||||
|
||||
/// Prescribe a set of integration rules; relevant for mixed meshes.
|
||||
/** This function has priority over SetIntRule(), if both are called. */
|
||||
void SetIntegrationRules(IntegrationRules &irules, int order)
|
||||
{
|
||||
IntegRules = &irules;
|
||||
integ_order = order;
|
||||
}
|
||||
|
||||
/// Sets a scaling Coefficient for the quality metric term of the integrator.
|
||||
/** With this addition, the integrator becomes
|
||||
@f$ \int w1 W(Jpt) dx @f$.
|
||||
|
||||
+29
-15
@@ -176,8 +176,8 @@ SerialAdvectorCGOper::SerialAdvectorCGOper(const Vector &x_start,
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
M.Assemble(0);
|
||||
M.Finalize(0);
|
||||
}
|
||||
|
||||
void SerialAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
@@ -220,8 +220,8 @@ ParAdvectorCGOper::ParAdvectorCGOper(const Vector &x_start,
|
||||
|
||||
MassIntegrator *Minteg = new MassIntegrator;
|
||||
M.AddDomainIntegrator(Minteg);
|
||||
M.Assemble();
|
||||
M.Finalize();
|
||||
M.Assemble(0);
|
||||
M.Finalize(0);
|
||||
}
|
||||
|
||||
void ParAdvectorCGOper::Mult(const Vector &ind, Vector &di_dt) const
|
||||
@@ -353,13 +353,12 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
energy_in = nlf->GetEnergy(x);
|
||||
}
|
||||
|
||||
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetFE(0)->GetDim(),
|
||||
dof = fes->GetFE(0)->GetDof(), nsp = ir.GetNPoints();
|
||||
Array<int> xdofs(dof * dim);
|
||||
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
Vector x_out_loc(fes->GetVSize());
|
||||
const int NE = fes->GetMesh()->GetNE(), dim = fes->GetMesh()->Dimension();
|
||||
Array<int> xdofs;
|
||||
DenseMatrix Jpr(dim);
|
||||
|
||||
// Get the local prolongation of the solution vector.
|
||||
Vector x_out_loc(fes->GetVSize());
|
||||
if (serial)
|
||||
{
|
||||
const SparseMatrix *cP = fes->GetConformingProlongation();
|
||||
@@ -373,15 +372,23 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check if the starting mesh (given by x) is inverted.
|
||||
// Note that x hasn't been modified by the Newton update yet.
|
||||
double min_detJ = infinity();
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
const int dof = fes->GetFE(i)->GetDof();
|
||||
DenseMatrix dshape(dof, dim), pos(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
|
||||
const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i));
|
||||
const int nsp = irule.GetNPoints();
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
min_detJ = std::min(min_detJ, Jpr.Det());
|
||||
}
|
||||
@@ -394,18 +401,18 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
p_nlf->ParFESpace()->GetComm());
|
||||
}
|
||||
#endif
|
||||
bool untangling = false;
|
||||
if (min_detJ_all <= 0) { untangling = true; }
|
||||
const bool untangling = (min_detJ_all <= 0) ? true : false;
|
||||
|
||||
const bool have_b = (b.Size() == Height());
|
||||
|
||||
Vector x_out(x.Size());
|
||||
bool x_out_ok = false;
|
||||
double scale = 1.0, energy_out = 0.0;
|
||||
double norm0 = Norm(r);
|
||||
const double norm0 = Norm(r);
|
||||
|
||||
const double detJ_factor = (solver_type == 1) ? 0.25 : 0.5;
|
||||
|
||||
// Perform the line search.
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
add(x, -scale, c, x_out);
|
||||
@@ -429,11 +436,18 @@ double TMOPNewtonSolver::ComputeScalingFactor(const Vector &x,
|
||||
int jac_ok = 1;
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
const int dof = fes->GetFE(i)->GetDof();
|
||||
DenseMatrix dshape(dof, dim), pos(dof, dim);
|
||||
Vector posV(pos.Data(), dof * dim);
|
||||
|
||||
fes->GetElementVDofs(i, xdofs);
|
||||
x_out_loc.GetSubVector(xdofs, posV);
|
||||
|
||||
const IntegrationRule &irule = GetIntegrationRule(*fes->GetFE(i));
|
||||
const int nsp = irule.GetNPoints();
|
||||
for (int j = 0; j < nsp; j++)
|
||||
{
|
||||
fes->GetFE(i)->CalcDShape(ir.IntPoint(j), dshape);
|
||||
fes->GetFE(i)->CalcDShape(irule.IntPoint(j), dshape);
|
||||
MultAtB(pos, dshape, Jpr);
|
||||
if (Jpr.Det() <= 0.0) { jac_ok = 0; goto break2; }
|
||||
}
|
||||
|
||||
+25
-2
@@ -118,16 +118,39 @@ protected:
|
||||
|
||||
// Quadrature points that are checked for negative Jacobians etc.
|
||||
const IntegrationRule &ir;
|
||||
// These fields are relevant for mixed meshes.
|
||||
IntegrationRules *IntegRules;
|
||||
int integ_order;
|
||||
|
||||
const IntegrationRule &GetIntegrationRule(const FiniteElement &el) const
|
||||
{
|
||||
if (IntegRules)
|
||||
{
|
||||
return IntegRules->Get(el.GetGeomType(), integ_order);
|
||||
}
|
||||
return ir;
|
||||
}
|
||||
|
||||
void UpdateDiscreteTC(const TMOP_Integrator &ti, const Vector &x_new) const;
|
||||
|
||||
public:
|
||||
#ifdef MFEM_USE_MPI
|
||||
TMOPNewtonSolver(MPI_Comm comm, const IntegrationRule &irule, int type = 0)
|
||||
: LBFGSSolver(comm), solver_type(type), parallel(true), ir(irule) { }
|
||||
: LBFGSSolver(comm), solver_type(type), parallel(true),
|
||||
ir(irule), IntegRules(NULL), integ_order(-1) { }
|
||||
#endif
|
||||
TMOPNewtonSolver(const IntegrationRule &irule, int type = 0)
|
||||
: LBFGSSolver(), solver_type(type), parallel(false), ir(irule) { }
|
||||
: LBFGSSolver(), solver_type(type), parallel(false),
|
||||
ir(irule), IntegRules(NULL), integ_order(-1) { }
|
||||
|
||||
/// Prescribe a set of integration rules; relevant for mixed meshes.
|
||||
/** If called, this function has priority over the IntegrationRule given to
|
||||
the constructor of the class. */
|
||||
void SetIntegrationRules(IntegrationRules &irules, int order)
|
||||
{
|
||||
IntegRules = &irules;
|
||||
integ_order = order;
|
||||
}
|
||||
|
||||
virtual double ComputeScalingFactor(const Vector &x, const Vector &b) const;
|
||||
|
||||
|
||||
@@ -1048,6 +1048,36 @@ HYPRE_Int HypreParMatrix::MultTranspose(HypreParVector & x, HypreParVector & y,
|
||||
return hypre_ParCSRMatrixMatvecT(a, A, x, b, y);
|
||||
}
|
||||
|
||||
void HypreParMatrix::AbsMult(double a, const Vector &x,
|
||||
double b, Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
|
||||
<< ", expected size = " << Width());
|
||||
MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
|
||||
<< ", expected size = " << Height());
|
||||
|
||||
auto x_data = x.HostRead();
|
||||
auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
|
||||
|
||||
internal::hypre_ParCSRMatrixAbsMatvec(A, a, const_cast<double*>(x_data),
|
||||
b, y_data);
|
||||
}
|
||||
|
||||
void HypreParMatrix::AbsMultTranspose(double a, const Vector &x,
|
||||
double b, Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
|
||||
<< ", expected size = " << Height());
|
||||
MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
|
||||
<< ", expected size = " << Width());
|
||||
|
||||
auto x_data = x.HostRead();
|
||||
auto y_data = (b == 0.0) ? y.HostWrite() : y.HostReadWrite();
|
||||
|
||||
internal::hypre_ParCSRMatrixAbsMatvecT(A, a, const_cast<double*>(x_data),
|
||||
b, y_data);
|
||||
}
|
||||
|
||||
HypreParMatrix* HypreParMatrix::LeftDiagMult(const SparseMatrix &D,
|
||||
HYPRE_Int* row_starts) const
|
||||
{
|
||||
|
||||
@@ -446,6 +446,12 @@ public:
|
||||
virtual void MultTranspose(const Vector &x, Vector &y) const
|
||||
{ MultTranspose(1.0, x, 0.0, y); }
|
||||
|
||||
/// Computes y = a * |A| * x + b * y, using entry-wise absolute values of matrix A
|
||||
void AbsMult(double a, const Vector &x, double b, Vector &y) const;
|
||||
|
||||
/// Computes y = a * |At| * x + b * y, using entry-wise absolute values of the transpose of matrix A
|
||||
void AbsMultTranspose(double a, const Vector &x, double b, Vector &y) const;
|
||||
|
||||
/** The "Boolean" analog of y = alpha * A * x + beta * y, where elements in
|
||||
the sparsity pattern of the matrix are treated as "true". */
|
||||
void BooleanMult(int alpha, const int *x, int beta, int *y)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "hypre_parcsr.hpp"
|
||||
#include <limits>
|
||||
#include <cmath>
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -977,6 +978,196 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
|
||||
}
|
||||
}
|
||||
|
||||
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
|
||||
void hypre_CSRMatrixAbsMatvec(hypre_CSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y)
|
||||
{
|
||||
HYPRE_Real *A_data = hypre_CSRMatrixData(A);
|
||||
HYPRE_Int *A_i = hypre_CSRMatrixI(A);
|
||||
HYPRE_Int *A_j = hypre_CSRMatrixJ(A);
|
||||
HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A);
|
||||
|
||||
HYPRE_Int *A_rownnz = hypre_CSRMatrixRownnz(A);
|
||||
HYPRE_Int num_rownnz = hypre_CSRMatrixNumRownnz(A);
|
||||
|
||||
HYPRE_Real *x_data = x;
|
||||
HYPRE_Real *y_data = y;
|
||||
|
||||
HYPRE_Real temp, tempx;
|
||||
|
||||
HYPRE_Int i, jj;
|
||||
|
||||
HYPRE_Int m;
|
||||
|
||||
HYPRE_Real xpar=0.7;
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Do (alpha == 0.0) computation - RDF: USE MACHINE EPS
|
||||
*-----------------------------------------------------------------------*/
|
||||
|
||||
if (alpha == 0.0)
|
||||
{
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
y_data[i] *= beta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* y = (beta/alpha)*y
|
||||
*-----------------------------------------------------------------------*/
|
||||
|
||||
temp = beta / alpha;
|
||||
|
||||
if (temp != 1.0)
|
||||
{
|
||||
if (temp == 0.0)
|
||||
{
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
y_data[i] = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
y_data[i] *= temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* y += abs(A)*x
|
||||
*-----------------------------------------------------------------*/
|
||||
|
||||
/* use rownnz pointer to do the abs(A)*x multiplication
|
||||
when num_rownnz is smaller than num_rows */
|
||||
|
||||
if (num_rownnz < xpar*(num_rows))
|
||||
{
|
||||
for (i = 0; i < num_rownnz; i++)
|
||||
{
|
||||
m = A_rownnz[i];
|
||||
|
||||
tempx = 0;
|
||||
for (jj = A_i[m]; jj < A_i[m+1]; jj++)
|
||||
{
|
||||
tempx += std::abs(A_data[jj])*x_data[A_j[jj]];
|
||||
}
|
||||
y_data[m] += tempx;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
tempx = 0;
|
||||
for (jj = A_i[i]; jj < A_i[i+1]; jj++)
|
||||
{
|
||||
tempx += std::abs(A_data[jj])*x_data[A_j[jj]];
|
||||
}
|
||||
y_data[i] += tempx;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* y = alpha*y
|
||||
*-----------------------------------------------------------------*/
|
||||
|
||||
if (alpha != 1.0)
|
||||
{
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
y_data[i] *= alpha;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Based on hypre_CSRMatrixMatvecT in hypre's csr_matvec.c */
|
||||
void hypre_CSRMatrixAbsMatvecT(hypre_CSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y)
|
||||
{
|
||||
HYPRE_Real *A_data = hypre_CSRMatrixData(A);
|
||||
HYPRE_Int *A_i = hypre_CSRMatrixI(A);
|
||||
HYPRE_Int *A_j = hypre_CSRMatrixJ(A);
|
||||
HYPRE_Int num_rows = hypre_CSRMatrixNumRows(A);
|
||||
HYPRE_Int num_cols = hypre_CSRMatrixNumCols(A);
|
||||
|
||||
HYPRE_Real *x_data = x;
|
||||
HYPRE_Real *y_data = y;
|
||||
|
||||
HYPRE_Int i, j, jj;
|
||||
|
||||
HYPRE_Real temp;
|
||||
|
||||
if (alpha == 0.0)
|
||||
{
|
||||
for (i = 0; i < num_cols; i++)
|
||||
{
|
||||
y_data[i] *= beta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* y = (beta/alpha)*y
|
||||
*-----------------------------------------------------------------------*/
|
||||
|
||||
temp = beta / alpha;
|
||||
|
||||
if (temp != 1.0)
|
||||
{
|
||||
if (temp == 0.0)
|
||||
{
|
||||
for (i = 0; i < num_cols; i++)
|
||||
{
|
||||
y_data[i] = 0.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < num_cols; i++)
|
||||
{
|
||||
y_data[i] *= temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* y += abs(A)^T*x
|
||||
*-----------------------------------------------------------------*/
|
||||
|
||||
for (i = 0; i < num_rows; i++)
|
||||
{
|
||||
for (jj = A_i[i]; jj < A_i[i+1]; jj++)
|
||||
{
|
||||
j = A_j[jj];
|
||||
y_data[j] += std::abs(A_data[jj]) * x_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* y = alpha*y
|
||||
*-----------------------------------------------------------------*/
|
||||
|
||||
if (alpha != 1.0)
|
||||
{
|
||||
for (i = 0; i < num_cols; i++)
|
||||
{
|
||||
y_data[i] *= alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
|
||||
void hypre_CSRMatrixBooleanMatvec(hypre_CSRMatrix *A,
|
||||
HYPRE_Bool alpha,
|
||||
@@ -1236,6 +1427,143 @@ hypre_ParCSRCommHandleCreate_bool(HYPRE_Int job,
|
||||
return comm_handle;
|
||||
}
|
||||
|
||||
/* Based on hypre_ParCSRMatrixMatvec in par_csr_matvec.c */
|
||||
void hypre_ParCSRMatrixAbsMatvec(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y)
|
||||
{
|
||||
hypre_ParCSRCommHandle *comm_handle;
|
||||
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A);
|
||||
hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
|
||||
hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
|
||||
|
||||
HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(offd);
|
||||
HYPRE_Int num_sends, i, j, index;
|
||||
|
||||
HYPRE_Real *x_tmp, *x_buf;
|
||||
|
||||
x_tmp = mfem_hypre_CTAlloc(HYPRE_Real, num_cols_offd);
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* If there exists no CommPkg for A, a CommPkg is generated using
|
||||
* equally load balanced partitionings
|
||||
*--------------------------------------------------------------------*/
|
||||
if (!comm_pkg)
|
||||
{
|
||||
hypre_MatvecCommPkgCreate(A);
|
||||
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
|
||||
}
|
||||
|
||||
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
|
||||
x_buf = mfem_hypre_CTAlloc(
|
||||
HYPRE_Real, hypre_ParCSRCommPkgSendMapStart(comm_pkg, num_sends));
|
||||
|
||||
index = 0;
|
||||
for (i = 0; i < num_sends; i++)
|
||||
{
|
||||
j = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
|
||||
for ( ; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
|
||||
{
|
||||
x_buf[index++] = x[hypre_ParCSRCommPkgSendMapElmt(comm_pkg, j)];
|
||||
}
|
||||
}
|
||||
|
||||
comm_handle = hypre_ParCSRCommHandleCreate(1, comm_pkg, x_buf, x_tmp);
|
||||
|
||||
hypre_CSRMatrixAbsMatvec(diag, alpha, x, beta, y);
|
||||
|
||||
hypre_ParCSRCommHandleDestroy(comm_handle);
|
||||
|
||||
if (num_cols_offd)
|
||||
{
|
||||
hypre_CSRMatrixAbsMatvec(offd, alpha, x_tmp, 1.0, y);
|
||||
}
|
||||
|
||||
mfem_hypre_TFree(x_buf);
|
||||
mfem_hypre_TFree(x_tmp);
|
||||
}
|
||||
|
||||
/* Based on hypre_ParCSRMatrixMatvecT in par_csr_matvec.c */
|
||||
void hypre_ParCSRMatrixAbsMatvecT(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y)
|
||||
{
|
||||
hypre_ParCSRCommHandle *comm_handle;
|
||||
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(A);
|
||||
hypre_CSRMatrix *diag = hypre_ParCSRMatrixDiag(A);
|
||||
hypre_CSRMatrix *offd = hypre_ParCSRMatrixOffd(A);
|
||||
HYPRE_Real *y_tmp;
|
||||
HYPRE_Real *y_buf;
|
||||
|
||||
HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(offd);
|
||||
|
||||
HYPRE_Int i, j, jj, end, num_sends;
|
||||
|
||||
y_tmp = mfem_hypre_TAlloc(HYPRE_Real, num_cols_offd);
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* If there exists no CommPkg for A, a CommPkg is generated using
|
||||
* equally load balanced partitionings
|
||||
*--------------------------------------------------------------------*/
|
||||
if (!comm_pkg)
|
||||
{
|
||||
hypre_MatvecCommPkgCreate(A);
|
||||
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
|
||||
}
|
||||
|
||||
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
|
||||
y_buf = mfem_hypre_CTAlloc(
|
||||
HYPRE_Real, hypre_ParCSRCommPkgSendMapStart(comm_pkg, num_sends));
|
||||
|
||||
if (num_cols_offd)
|
||||
{
|
||||
#if MFEM_HYPRE_VERSION >= 21100
|
||||
if (A->offdT)
|
||||
{
|
||||
// offdT is optional. Used only if it's present.
|
||||
hypre_CSRMatrixAbsMatvec(A->offdT, alpha, x, 0., y_tmp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hypre_CSRMatrixAbsMatvecT(offd, alpha, x, 0., y_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
comm_handle = hypre_ParCSRCommHandleCreate(2, comm_pkg, y_tmp, y_buf);
|
||||
|
||||
#if MFEM_HYPRE_VERSION >= 21100
|
||||
if (A->diagT)
|
||||
{
|
||||
// diagT is optional. Used only if it's present.
|
||||
hypre_CSRMatrixAbsMatvec(A->diagT, alpha, x, beta, y);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hypre_CSRMatrixAbsMatvecT(diag, alpha, x, beta, y);
|
||||
}
|
||||
|
||||
hypre_ParCSRCommHandleDestroy(comm_handle);
|
||||
|
||||
for (i = 0; i < num_sends; i++)
|
||||
{
|
||||
end = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1);
|
||||
for (j = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i); j < end; j++)
|
||||
{
|
||||
jj = hypre_ParCSRCommPkgSendMapElmt(comm_pkg, j);
|
||||
y[jj] += y_buf[j];
|
||||
}
|
||||
}
|
||||
|
||||
mfem_hypre_TFree(y_buf);
|
||||
mfem_hypre_TFree(y_tmp);
|
||||
}
|
||||
|
||||
/* Based on hypre_ParCSRMatrixMatvec in par_csr_matvec.c */
|
||||
void hypre_ParCSRMatrixBooleanMatvec(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Bool alpha,
|
||||
|
||||
@@ -118,6 +118,34 @@ void hypre_ParCSRMatrixSplit(hypre_ParCSRMatrix *A,
|
||||
typedef int HYPRE_Bool;
|
||||
#define HYPRE_MPI_BOOL MPI_INT
|
||||
|
||||
/// Computes y = alpha * |A| * x + beta * y, using entry-wise absolute values of matrix A
|
||||
void hypre_CSRMatrixAbsMatvec(hypre_CSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y);
|
||||
|
||||
/// Computes y = alpha * |At| * x + beta * y, using entry-wise absolute values of the transpose of matrix A
|
||||
void hypre_CSRMatrixAbsMatvecT(hypre_CSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y);
|
||||
|
||||
/// Computes y = alpha * |A| * x + beta * y, using entry-wise absolute values of matrix A
|
||||
void hypre_ParCSRMatrixAbsMatvec(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y);
|
||||
|
||||
/// Computes y = alpha * |At| * x + beta * y, using entry-wise absolute values of the transpose of matrix A
|
||||
void hypre_ParCSRMatrixAbsMatvecT(hypre_ParCSRMatrix *A,
|
||||
HYPRE_Real alpha,
|
||||
HYPRE_Real *x,
|
||||
HYPRE_Real beta,
|
||||
HYPRE_Real *y);
|
||||
|
||||
/** The "Boolean" analog of y = alpha * A * x + beta * y, where elements in the
|
||||
sparsity pattern of the CSR matrix A are treated as "true". */
|
||||
void hypre_CSRMatrixBooleanMatvec(hypre_CSRMatrix *A,
|
||||
|
||||
@@ -2665,6 +2665,42 @@ void BlockILU::Mult(const Vector &b, Vector &x) const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ResidualBCMonitor::MonitorResidual(
|
||||
int it, double norm, const Vector &r, bool final)
|
||||
{
|
||||
if (!ess_dofs_list) { return; }
|
||||
|
||||
double bc_norm_squared = 0.0;
|
||||
r.HostRead();
|
||||
ess_dofs_list->HostRead();
|
||||
for (int i = 0; i < ess_dofs_list->Size(); i++)
|
||||
{
|
||||
const double r_entry = r((*ess_dofs_list)[i]);
|
||||
bc_norm_squared += r_entry*r_entry;
|
||||
}
|
||||
bool print = true;
|
||||
#ifdef MFEM_USE_MPI
|
||||
MPI_Comm comm = iter_solver->GetComm();
|
||||
if (comm != MPI_COMM_NULL)
|
||||
{
|
||||
double glob_bc_norm_squared = 0.0;
|
||||
MPI_Reduce(&bc_norm_squared, &glob_bc_norm_squared, 1, MPI_DOUBLE,
|
||||
MPI_SUM, 0, comm);
|
||||
bc_norm_squared = glob_bc_norm_squared;
|
||||
int rank;
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
print = (rank == 0);
|
||||
}
|
||||
#endif
|
||||
if ((it == 0 || final || bc_norm_squared > 0.0) && print)
|
||||
{
|
||||
mfem::out << " ResidualBCMonitor : b.c. residual norm = "
|
||||
<< sqrt(bc_norm_squared) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef MFEM_USE_SUITESPARSE
|
||||
|
||||
void UMFPackSolver::Init()
|
||||
@@ -2936,4 +2972,36 @@ KLUSolver::~KLUSolver()
|
||||
|
||||
#endif // MFEM_USE_SUITESPARSE
|
||||
|
||||
IncompleteCholesky::IncompleteCholesky(SparseMatrix &A_) : A(&A_)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->IncompleteCholeskySetup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void IncompleteCholesky::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->IncompleteCholeskyMult(b, x);
|
||||
#else
|
||||
x = b;
|
||||
#endif
|
||||
}
|
||||
|
||||
ILUcusparse::ILUcusparse(SparseMatrix &A_) : A(&A_)
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->ILUSetup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILUcusparse::Mult(const Vector &b, Vector &x) const
|
||||
{
|
||||
#ifdef MFEM_USE_CUDA
|
||||
A->ILUMult(b, x);
|
||||
#else
|
||||
x = b;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+60
-2
@@ -33,8 +33,12 @@ class BilinearForm;
|
||||
/// Abstract base class for an iterative solver monitor
|
||||
class IterativeSolverMonitor
|
||||
{
|
||||
protected:
|
||||
/// The last IterativeSolver to which this monitor was attached.
|
||||
const class IterativeSolver *iter_solver;
|
||||
|
||||
public:
|
||||
IterativeSolverMonitor() {}
|
||||
IterativeSolverMonitor() : iter_solver(nullptr) {}
|
||||
|
||||
virtual ~IterativeSolverMonitor() {}
|
||||
|
||||
@@ -49,6 +53,11 @@ public:
|
||||
bool final)
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief This method is invoked by ItertiveSolver::SetMonitor, informing
|
||||
the monitor which IterativeSolver is using it. */
|
||||
void SetIterativeSolver(const IterativeSolver &solver)
|
||||
{ iter_solver = &solver; }
|
||||
};
|
||||
|
||||
/// Abstract base class for iterative solver
|
||||
@@ -100,7 +109,15 @@ public:
|
||||
virtual void SetOperator(const Operator &op);
|
||||
|
||||
/// Set the iterative solver monitor
|
||||
void SetMonitor(IterativeSolverMonitor &m) { monitor = &m; }
|
||||
void SetMonitor(IterativeSolverMonitor &m)
|
||||
{ monitor = &m; m.SetIterativeSolver(*this); }
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
/** @brief Return the associated MPI communicator, or MPI_COMM_NULL if no
|
||||
communicator is set. */
|
||||
MPI_Comm GetComm() const
|
||||
{ return dot_prod_type == 0 ? MPI_COMM_NULL : comm; }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -689,6 +706,25 @@ private:
|
||||
mutable Array<int> ipiv;
|
||||
};
|
||||
|
||||
|
||||
/// Monitor that checks whether the residual is zero at a given set of dofs.
|
||||
/** This monitor is useful for checking if the initial guess, rhs, operator, and
|
||||
preconditioner are properly setup for solving in the subspace with imposed
|
||||
essential boundary conditions. */
|
||||
class ResidualBCMonitor : public IterativeSolverMonitor
|
||||
{
|
||||
protected:
|
||||
const Array<int> *ess_dofs_list; ///< Not owned
|
||||
|
||||
public:
|
||||
ResidualBCMonitor(const Array<int> &ess_dofs_list_)
|
||||
: ess_dofs_list(&ess_dofs_list_) { }
|
||||
|
||||
void MonitorResidual(int it, double norm, const Vector &r,
|
||||
bool final) override;
|
||||
};
|
||||
|
||||
|
||||
#ifdef MFEM_USE_SUITESPARSE
|
||||
|
||||
/// Direct sparse solver using UMFPACK
|
||||
@@ -763,6 +799,28 @@ public:
|
||||
|
||||
#endif // MFEM_USE_SUITESPARSE
|
||||
|
||||
class IncompleteCholesky : public IterativeSolver
|
||||
{
|
||||
private:
|
||||
SparseMatrix *A;
|
||||
|
||||
public:
|
||||
IncompleteCholesky(SparseMatrix &A_);
|
||||
|
||||
virtual void Mult(const Vector &b, Vector &x) const;
|
||||
};
|
||||
|
||||
class ILUcusparse : public IterativeSolver
|
||||
{
|
||||
private:
|
||||
SparseMatrix *A;
|
||||
|
||||
public:
|
||||
ILUcusparse(SparseMatrix &A_);
|
||||
|
||||
virtual void Mult(const Vector &b, Vector &x) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // MFEM_SOLVERS
|
||||
|
||||
+529
-8
@@ -28,6 +28,25 @@ namespace mfem
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
int SparseMatrix::SparseMatrixCount = 0;
|
||||
cusparseHandle_t SparseMatrix::handle;
|
||||
size_t SparseMatrix::bufferSize = 0;
|
||||
void * SparseMatrix::dBuffer = nullptr;
|
||||
#endif
|
||||
|
||||
void SparseMatrix::InitCuSparse()
|
||||
{
|
||||
// Initialize cuSPARSE library
|
||||
#ifdef MFEM_USE_CUDA
|
||||
SparseMatrixCount++;
|
||||
if (SparseMatrixCount == 1 && Device::Allows(Backend::CUDA_MASK))
|
||||
{
|
||||
cusparseCreate(&handle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(int nrows, int ncols)
|
||||
: AbstractSparseMatrix(nrows, (ncols >= 0) ? ncols : nrows),
|
||||
Rows(new RowNode *[nrows]),
|
||||
@@ -50,6 +69,8 @@ SparseMatrix::SparseMatrix(int nrows, int ncols)
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
NodesMem = new RowNodeAlloc;
|
||||
#endif
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n)
|
||||
@@ -67,6 +88,8 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n)
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
NodesMem = NULL;
|
||||
#endif
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n,
|
||||
@@ -98,6 +121,8 @@ SparseMatrix::SparseMatrix(int *i, int *j, double *data, int m, int n,
|
||||
A[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
|
||||
@@ -119,6 +144,8 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
|
||||
{
|
||||
I[i] = i * rowsize;
|
||||
}
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
@@ -184,6 +211,8 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
ColPtrNode = NULL;
|
||||
At = NULL;
|
||||
isSorted = mat.isSorted;
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(const Vector &v)
|
||||
@@ -211,6 +240,8 @@ SparseMatrix::SparseMatrix(const Vector &v)
|
||||
J[r] = r;
|
||||
A[r] = v[r];
|
||||
}
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix& SparseMatrix::operator=(const SparseMatrix &rhs)
|
||||
@@ -250,6 +281,16 @@ void SparseMatrix::SetEmpty()
|
||||
NodesMem = NULL;
|
||||
#endif
|
||||
isSorted = false;
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (initBuffers)
|
||||
{
|
||||
cusparseDestroySpMat(matA_descr);
|
||||
cusparseDestroyDnVec(vecX_descr);
|
||||
cusparseDestroyDnVec(vecY_descr);
|
||||
initBuffers = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int SparseMatrix::RowSize(const int i) const
|
||||
@@ -569,7 +610,7 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
|
||||
const double *xp = x.HostRead();
|
||||
double *yp = y.HostReadWrite();
|
||||
|
||||
// The matrix is not finalized, but multiplication is still possible
|
||||
// The matrix is not finalized, but multiplication is still possible
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
RowNode *row = Rows[i];
|
||||
@@ -592,16 +633,72 @@ void SparseMatrix::AddMult(const Vector &x, Vector &y, const double a) const
|
||||
auto d_A = Read(A, nnz);
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
MFEM_FORALL(i, height,
|
||||
|
||||
// Skip if matrix has no non-zeros
|
||||
if (nnz == 0) {return;}
|
||||
if (Device::Allows(Backend::CUDA_MASK) && useCuSparse)
|
||||
{
|
||||
double d = 0.0;
|
||||
const int end = d_I[i+1];
|
||||
for (int j = d_I[i]; j < end; j++)
|
||||
#ifdef MFEM_USE_CUDA
|
||||
const double alpha = a;
|
||||
const double beta = 1.0;
|
||||
|
||||
// Setup descriptors
|
||||
if (!initBuffers)
|
||||
{
|
||||
d += d_A[j] * d_x[d_J[j]];
|
||||
// Setup matrix descriptor
|
||||
cusparseCreateCsr(&matA_descr,Height(), Width(), J.Capacity(),
|
||||
const_cast<int *>(d_I),
|
||||
const_cast<int *>(d_J), const_cast<double *>(d_A), CUSPARSE_INDEX_32I,
|
||||
CUSPARSE_INDEX_32I, CUSPARSE_INDEX_BASE_ZERO, CUDA_R_64F);
|
||||
|
||||
// Create handles for input/output vectors
|
||||
cusparseCreateDnVec(&vecX_descr, x.Size(), const_cast<double *>(d_x),
|
||||
CUDA_R_64F);
|
||||
cusparseCreateDnVec(&vecY_descr, y.Size(), d_y, CUDA_R_64F);
|
||||
|
||||
initBuffers = true;
|
||||
}
|
||||
d_y[i] += a * d;
|
||||
});
|
||||
|
||||
// Allocate kernel space. Buffer is shared between different sparsemats
|
||||
size_t newBufferSize = 0;
|
||||
cusparseSpMV_bufferSize(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha,
|
||||
matA_descr,
|
||||
vecX_descr, &beta, vecY_descr, CUDA_R_64F,
|
||||
CUSPARSE_CSRMV_ALG1, &newBufferSize);
|
||||
|
||||
// Check if we need to resize
|
||||
if (newBufferSize > bufferSize)
|
||||
{
|
||||
bufferSize = newBufferSize;
|
||||
if (dBuffer != NULL) { CuMemFree(dBuffer); }
|
||||
CuMemAlloc(&dBuffer, bufferSize);
|
||||
}
|
||||
|
||||
// Update input/output vectors
|
||||
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
|
||||
cusparseDnVecSetValues(vecY_descr, d_y);
|
||||
|
||||
// Y = alpha A * X + beta * Y
|
||||
cusparseSpMV(handle, CUSPARSE_OPERATION_NON_TRANSPOSE, &alpha, matA_descr,
|
||||
vecX_descr, &beta, vecY_descr, CUDA_R_64F, CUSPARSE_CSRMV_ALG1, dBuffer);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Native version
|
||||
MFEM_FORALL(i, height,
|
||||
{
|
||||
double d = 0.0;
|
||||
const int end = d_I[i+1];
|
||||
for (int j = d_I[i]; j < end; j++)
|
||||
{
|
||||
d += d_A[j] * d_x[d_J[j]];
|
||||
}
|
||||
d_y[i] += a * d;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
const double *Ap = A, *xp = x.GetData();
|
||||
double *yp = y.GetData();
|
||||
@@ -784,6 +881,101 @@ void SparseMatrix::BooleanMultTranspose(const Array<int> &x,
|
||||
}
|
||||
}
|
||||
|
||||
void SparseMatrix::AbsMult(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(width == x.Size(), "Input vector size (" << x.Size()
|
||||
<< ") must match matrix width (" << width << ")");
|
||||
MFEM_ASSERT(height == y.Size(), "Output vector size (" << y.Size()
|
||||
<< ") must match matrix height (" << height << ")");
|
||||
|
||||
if (Finalized()) { y.UseDevice(true); }
|
||||
y = 0.0;
|
||||
|
||||
if (!Finalized())
|
||||
{
|
||||
const double *xp = x.HostRead();
|
||||
double *yp = y.HostReadWrite();
|
||||
|
||||
// The matrix is not finalized, but multiplication is still possible
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
RowNode *row = Rows[i];
|
||||
double b = 0.0;
|
||||
for ( ; row != NULL; row = row->Prev)
|
||||
{
|
||||
b += std::abs(row->Value) * xp[row->Column];
|
||||
}
|
||||
*yp += b;
|
||||
yp++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
auto d_I = Read(I, height+1);
|
||||
auto d_J = Read(J, nnz);
|
||||
auto d_A = Read(A, nnz);
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
MFEM_FORALL(i, height,
|
||||
{
|
||||
double d = 0.0;
|
||||
const int end = d_I[i+1];
|
||||
for (int j = d_I[i]; j < end; j++)
|
||||
{
|
||||
d += std::abs(d_A[j]) * d_x[d_J[j]];
|
||||
}
|
||||
d_y[i] += d;
|
||||
});
|
||||
}
|
||||
|
||||
void SparseMatrix::AbsMultTranspose(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(height == x.Size(), "Input vector size (" << x.Size()
|
||||
<< ") must match matrix height (" << height << ")");
|
||||
MFEM_ASSERT(width == y.Size(), "Output vector size (" << y.Size()
|
||||
<< ") must match matrix width (" << width << ")");
|
||||
|
||||
y = 0.0;
|
||||
|
||||
if (!Finalized())
|
||||
{
|
||||
double *yp = y.GetData();
|
||||
// The matrix is not finalized, but multiplication is still possible
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
RowNode *row = Rows[i];
|
||||
double b = x(i);
|
||||
for ( ; row != NULL; row = row->Prev)
|
||||
{
|
||||
yp[row->Column] += fabs(row->Value) * b;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (At)
|
||||
{
|
||||
At->AbsMult(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_VERIFY(Device::IsDisabled(), "transpose action on device is not "
|
||||
"enabled; see BuildTranspose() for details.");
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
const double xi = x[i];
|
||||
const int end = I[i+1];
|
||||
for (int j = I[i]; j < end; j++)
|
||||
{
|
||||
const int Jj = J[j];
|
||||
y[Jj] += std::abs(A[j]) * xi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double SparseMatrix::InnerProduct(const Vector &x, const Vector &y) const
|
||||
{
|
||||
MFEM_ASSERT(x.Size() == Width(), "x.Size() = " << x.Size()
|
||||
@@ -2962,6 +3154,16 @@ void SparseMatrix::Destroy()
|
||||
delete NodesMem;
|
||||
#endif
|
||||
delete At;
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (initBuffers)
|
||||
{
|
||||
cusparseDestroySpMat(matA_descr);
|
||||
cusparseDestroyDnVec(vecX_descr);
|
||||
cusparseDestroyDnVec(vecY_descr);
|
||||
initBuffers = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int SparseMatrix::ActualWidth() const
|
||||
@@ -3697,4 +3899,323 @@ void SparseMatrix::Swap(SparseMatrix &other)
|
||||
mfem::Swap(isSorted, other.isSorted);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
void SparseMatrix::IncompleteCholeskyMult(const Vector &x, Vector &y) const
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
y = x;
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(initCholesky, "Setup not done");
|
||||
|
||||
const double alpha = 1.0;
|
||||
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
int64_t m = height;
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
|
||||
cusparseDnVecSetValues(vecY_descr, d_y);
|
||||
cusparseDnVecSetValues(vecZ_descr, d_z);
|
||||
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
|
||||
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
|
||||
// Solve L*z = x
|
||||
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
|
||||
d_x, d_z, policy_L, pBuffer);
|
||||
|
||||
// Solve L'*y = z
|
||||
cusparseDcsrsv2_solve(handle, trans_Lt, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_Lt,
|
||||
d_z, d_y, policy_Lt, pBuffer);
|
||||
}
|
||||
|
||||
void SparseMatrix::IncompleteCholeskySetup()
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!initILU && !initCholesky, "");
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
//MFEM_VERIFY(I[0] == 0, "cusparse thinks this is not zero based");
|
||||
|
||||
csric02Info_t info_M = 0;
|
||||
int bufferSize_M;
|
||||
int pBufferSize_L;
|
||||
int pBufferSize_Lt;
|
||||
int pBufferSize;
|
||||
int structural_zero;
|
||||
int numerical_zero;
|
||||
|
||||
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_Lt = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_Lt = CUSPARSE_OPERATION_TRANSPOSE;
|
||||
|
||||
// step 1: create a descriptor which contains
|
||||
// - matrix M is base-0
|
||||
// - matrix L is base-0
|
||||
// - matrix L is lower triangular
|
||||
// - matrix L has non-unit diagonal
|
||||
cusparseCreateMatDescr(&descr_M);
|
||||
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
|
||||
cusparseCreateMatDescr(&descr_L);
|
||||
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
|
||||
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_NON_UNIT);
|
||||
|
||||
// step 2: create a empty info structure
|
||||
// we need one info for csric02 and two info's for csrsv2
|
||||
cusparseCreateCsric02Info(&info_M);
|
||||
cusparseCreateCsrsv2Info(&info_L);
|
||||
cusparseCreateCsrsv2Info(&info_Lt);
|
||||
|
||||
int64_t m = height;
|
||||
|
||||
// step 3: query how much memory used in csric02 and csrsv2, and allocate the buffer
|
||||
cusparseDcsric02_bufferSize(handle, m, nnz,
|
||||
descr_M, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, &bufferSize_M);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz,
|
||||
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_Lt, m, nnz,
|
||||
descr_L, const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_Lt,&pBufferSize_Lt);
|
||||
|
||||
pBufferSize = max(bufferSize_M, max(pBufferSize_L, pBufferSize_Lt));
|
||||
|
||||
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
|
||||
cudaMalloc((void**)&pBuffer, pBufferSize);
|
||||
|
||||
// step 4: perform analysis of incomplete Cholesky on M
|
||||
// perform analysis of triangular solve on L
|
||||
// perform analysis of triangular solve on L'
|
||||
// The lower triangular part of M has the same sparsity pattern as L, so
|
||||
// we can do analysis of csric02 and csrsv2 simultaneously.
|
||||
|
||||
cusparseDcsric02_analysis(handle, m, nnz, descr_M,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
|
||||
policy_M, pBuffer);
|
||||
status = cusparseXcsric02_zeroPivot(handle, info_M, &structural_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
|
||||
}
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_L, policy_L, pBuffer);
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_Lt, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_Lt, policy_Lt, pBuffer);
|
||||
|
||||
// step 5: M = L * L'
|
||||
cusparseDcsric02(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
|
||||
status = cusparseXcsric02_zeroPivot(handle, info_M, &numerical_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("L(%d,%d) is zero\n", numerical_zero, numerical_zero);
|
||||
}
|
||||
|
||||
vecZ.SetSize(height);
|
||||
vecZ = 0.0;
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
|
||||
|
||||
initCholesky = true;
|
||||
}
|
||||
|
||||
void SparseMatrix::ILUMult(const Vector &x, Vector &y) const
|
||||
{
|
||||
MFEM_VERIFY(initILU, "Setup not done");
|
||||
|
||||
const double alpha = 1.0;
|
||||
|
||||
auto d_x = x.Read();
|
||||
auto d_y = y.ReadWrite();
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
int64_t m = height;
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
cusparseDnVecSetValues(vecX_descr, const_cast<double *>(d_x));
|
||||
cusparseDnVecSetValues(vecY_descr, d_y);
|
||||
cusparseDnVecSetValues(vecZ_descr, d_z);
|
||||
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
|
||||
// Solve L*z = x
|
||||
cusparseDcsrsv2_solve(handle, trans_L, m, nnz, &alpha, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_L,
|
||||
d_x, d_z, policy_L, pBuffer);
|
||||
|
||||
// Solve U*y = z
|
||||
cusparseDcsrsv2_solve(handle, trans_U, m, nnz, &alpha, descr_U,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_U,
|
||||
d_z, d_y, policy_U, pBuffer);
|
||||
|
||||
// TODO: destructor
|
||||
}
|
||||
|
||||
void SparseMatrix::ILUSetup()
|
||||
{
|
||||
if (!(Device::Allows(Backend::CUDA_MASK) && useCuSparse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(!initILU && !initCholesky, "");
|
||||
|
||||
const int height = this->height;
|
||||
const int nnz = J.Capacity();
|
||||
|
||||
auto d_csrRowPtr = Read(I, height+1);
|
||||
auto d_csrColInd = Read(J, nnz);
|
||||
auto d_csrVal = Read(A, nnz);
|
||||
|
||||
csrilu02Info_t info_M = 0;
|
||||
int pBufferSize_M;
|
||||
int pBufferSize_L;
|
||||
int pBufferSize_U;
|
||||
int pBufferSize;
|
||||
int structural_zero;
|
||||
int numerical_zero;
|
||||
const cusparseSolvePolicy_t policy_M = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_L = CUSPARSE_SOLVE_POLICY_NO_LEVEL;
|
||||
const cusparseSolvePolicy_t policy_U = CUSPARSE_SOLVE_POLICY_USE_LEVEL;
|
||||
const cusparseOperation_t trans_L = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
const cusparseOperation_t trans_U = CUSPARSE_OPERATION_NON_TRANSPOSE;
|
||||
|
||||
// step 1: create a descriptor which contains
|
||||
// - matrix M is base-0
|
||||
// - matrix L is base-0
|
||||
// - matrix L is lower triangular
|
||||
// - matrix L has unit diagonal
|
||||
// - matrix U is base-0
|
||||
// - matrix U is upper triangular
|
||||
// - matrix U has non-unit diagonal
|
||||
cusparseCreateMatDescr(&descr_M);
|
||||
cusparseSetMatIndexBase(descr_M, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_M, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
|
||||
cusparseCreateMatDescr(&descr_L);
|
||||
cusparseSetMatIndexBase(descr_L, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_L, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_L, CUSPARSE_FILL_MODE_LOWER);
|
||||
cusparseSetMatDiagType(descr_L, CUSPARSE_DIAG_TYPE_UNIT);
|
||||
|
||||
cusparseCreateMatDescr(&descr_U);
|
||||
cusparseSetMatIndexBase(descr_U, CUSPARSE_INDEX_BASE_ZERO);
|
||||
cusparseSetMatType(descr_U, CUSPARSE_MATRIX_TYPE_GENERAL);
|
||||
cusparseSetMatFillMode(descr_U, CUSPARSE_FILL_MODE_UPPER);
|
||||
cusparseSetMatDiagType(descr_U, CUSPARSE_DIAG_TYPE_NON_UNIT);
|
||||
|
||||
// step 2: create a empty info structure
|
||||
// we need one info for csrilu02 and two info's for csrsv2
|
||||
cusparseCreateCsrilu02Info(&info_M);
|
||||
cusparseCreateCsrsv2Info(&info_L);
|
||||
cusparseCreateCsrsv2Info(&info_U);
|
||||
|
||||
// step 3: query how much memory used in csrilu02 and csrsv2, and allocate the buffer
|
||||
int64_t m = height;
|
||||
|
||||
cusparseDcsrilu02_bufferSize(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, &pBufferSize_M);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_L, m, nnz, descr_L,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_L, &pBufferSize_L);
|
||||
cusparseDcsrsv2_bufferSize(handle, trans_U, m, nnz, descr_U,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_U, &pBufferSize_U);
|
||||
|
||||
pBufferSize = max(pBufferSize_M, max(pBufferSize_L, pBufferSize_U));
|
||||
|
||||
// pBuffer returned by cudaMalloc is automatically aligned to 128 bytes.
|
||||
cudaMalloc((void**)&pBuffer, pBufferSize);
|
||||
|
||||
// step 4: perform analysis of incomplete Cholesky on M
|
||||
// perform analysis of triangular solve on L
|
||||
// perform analysis of triangular solve on U
|
||||
// The lower(upper) triangular part of M has the same sparsity pattern as L(U),
|
||||
// we can do analysis of csrilu0 and csrsv2 simultaneously.
|
||||
|
||||
cusparseDcsrilu02_analysis(handle, m, nnz, descr_M,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd, info_M,
|
||||
policy_M, pBuffer);
|
||||
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &structural_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("A(%d,%d) is missing\n", structural_zero, structural_zero);
|
||||
}
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_L, m, nnz, descr_L,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_L, policy_L, pBuffer);
|
||||
|
||||
cusparseDcsrsv2_analysis(handle, trans_U, m, nnz, descr_U,
|
||||
d_csrVal, d_csrRowPtr, d_csrColInd,
|
||||
info_U, policy_U, pBuffer); // bug?
|
||||
|
||||
// step 5: M = L * U
|
||||
cusparseDcsrilu02(handle, m, nnz, descr_M,
|
||||
const_cast<double *>(d_csrVal), const_cast<int *>(d_csrRowPtr),
|
||||
const_cast<int *>(d_csrColInd), info_M, policy_M, pBuffer);
|
||||
status = cusparseXcsrilu02_zeroPivot(handle, info_M, &numerical_zero);
|
||||
if (CUSPARSE_STATUS_ZERO_PIVOT == status)
|
||||
{
|
||||
printf("U(%d,%d) is zero\n", numerical_zero, numerical_zero);
|
||||
}
|
||||
|
||||
vecZ.SetSize(height);
|
||||
vecZ = 0.0;
|
||||
auto d_z = vecZ.ReadWrite();
|
||||
cusparseCreateDnVec(&vecZ_descr, vecZ.Size(), d_z, CUDA_R_64F);
|
||||
|
||||
initILU = true;
|
||||
|
||||
// TODO: destructor
|
||||
}
|
||||
#endif // MFEM_USE_CUDA
|
||||
|
||||
}
|
||||
|
||||
+76
-4
@@ -21,6 +21,12 @@
|
||||
#include "../general/globals.hpp"
|
||||
#include "densemat.hpp"
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
#include <cusparse.h>
|
||||
#include <library_types.h>
|
||||
#include "../general/cuda.hpp"
|
||||
#endif
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
@@ -80,9 +86,48 @@ protected:
|
||||
void Destroy(); // Delete all owned data
|
||||
void SetEmpty(); // Init all entries with empty values
|
||||
|
||||
bool useCuSparse{true}; // Use cuSPARSE if available
|
||||
|
||||
// Initialize cuSPARSE
|
||||
void InitCuSparse();
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
cusparseStatus_t status;
|
||||
static cusparseHandle_t handle;
|
||||
cusparseMatDescr_t descr=0;
|
||||
static size_t bufferSize;
|
||||
static void *dBuffer;
|
||||
mutable bool initBuffers{false};
|
||||
|
||||
static int SparseMatrixCount;
|
||||
mutable cusparseSpMatDescr_t matA_descr;
|
||||
mutable cusparseDnVecDescr_t vecX_descr;
|
||||
mutable cusparseDnVecDescr_t vecY_descr;
|
||||
mutable cusparseDnVecDescr_t vecZ_descr;
|
||||
mutable Vector vecZ;
|
||||
|
||||
cusparseMatDescr_t descr_M = 0;
|
||||
cusparseMatDescr_t descr_L = 0;
|
||||
cusparseMatDescr_t descr_U = 0;
|
||||
|
||||
csrsv2Info_t info_L = 0;
|
||||
csrsv2Info_t info_Lt = 0;
|
||||
csrsv2Info_t info_U = 0;
|
||||
|
||||
void *pBuffer = 0;
|
||||
|
||||
bool initILU = false;
|
||||
bool initCholesky = false;
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// Create an empty SparseMatrix.
|
||||
SparseMatrix() { SetEmpty(); }
|
||||
SparseMatrix()
|
||||
{
|
||||
SetEmpty();
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
/** @brief Create a sparse matrix with flexible sparsity structure using a
|
||||
row-wise linked list (LIL) format. */
|
||||
@@ -118,6 +163,8 @@ public:
|
||||
/// Create a SparseMatrix with diagonal @a v, i.e. A = Diag(v)
|
||||
SparseMatrix(const Vector & v);
|
||||
|
||||
// Runtime option to use cuSPARSE. Only valid when using a CUDA backend.
|
||||
void UseCuSparse(bool _useCuSparse = true) { useCuSparse = _useCuSparse;}
|
||||
|
||||
/// Assignment operator: deep copy
|
||||
SparseMatrix& operator=(const SparseMatrix &rhs);
|
||||
@@ -308,16 +355,22 @@ public:
|
||||
|
||||
/// y = A * x, treating all entries as booleans (zero=false, nonzero=true).
|
||||
/** The actual values stored in the data array, #A, are not used - this means
|
||||
and that all entries in the sparsity pattern are considered to be true by
|
||||
that all entries in the sparsity pattern are considered to be true by
|
||||
this method. */
|
||||
void BooleanMult(const Array<int> &x, Array<int> &y) const;
|
||||
|
||||
/// y = At * x, treating all entries as booleans (zero=false, nonzero=true).
|
||||
/** The actual values stored in the data array, #A, are not used - this means
|
||||
and that all entries in the sparsity pattern are considered to be true by
|
||||
that all entries in the sparsity pattern are considered to be true by
|
||||
this method. */
|
||||
void BooleanMultTranspose(const Array<int> &x, Array<int> &y) const;
|
||||
|
||||
/// y = |A| * x, using entry-wise absolute values of matrix A
|
||||
void AbsMult(const Vector &x, Vector &y) const;
|
||||
|
||||
/// y = |At| * x, using entry-wise absolute values of the transpose of matrix A
|
||||
void AbsMultTranspose(const Vector &x, Vector &y) const;
|
||||
|
||||
/// Compute y^t A x
|
||||
double InnerProduct(const Vector &x, const Vector &y) const;
|
||||
|
||||
@@ -572,8 +625,27 @@ public:
|
||||
|
||||
void Swap(SparseMatrix &other);
|
||||
|
||||
#ifdef MFEM_USE_CUDA
|
||||
void IncompleteCholeskySetup();
|
||||
void IncompleteCholeskyMult(const Vector &x, Vector &y) const;
|
||||
|
||||
void ILUSetup();
|
||||
void ILUMult(const Vector &x, Vector &y) const;
|
||||
#endif
|
||||
|
||||
/// Destroys sparse matrix.
|
||||
virtual ~SparseMatrix() { Destroy(); }
|
||||
virtual ~SparseMatrix()
|
||||
{
|
||||
Destroy();
|
||||
#ifdef MFEM_USE_CUDA
|
||||
if (handle && SparseMatrixCount==1 && Device::Allows(Backend::CUDA_MASK))
|
||||
{
|
||||
cusparseDestroy(handle);
|
||||
CuMemFree(dBuffer);
|
||||
}
|
||||
SparseMatrixCount--;
|
||||
#endif
|
||||
}
|
||||
|
||||
Type GetType() const { return MFEM_SPARSEMAT; }
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
set(SRCS
|
||||
element.cpp
|
||||
gmsh.cpp
|
||||
hexahedron.cpp
|
||||
mesh.cpp
|
||||
mesh_operators.cpp
|
||||
@@ -29,6 +30,7 @@ set(SRCS
|
||||
|
||||
set(HDRS
|
||||
element.hpp
|
||||
gmsh.hpp
|
||||
hexahedron.hpp
|
||||
mesh.hpp
|
||||
mesh_headers.hpp
|
||||
|
||||
+487
@@ -0,0 +1,487 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "gmsh.hpp"
|
||||
#include "vtk.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
int BarycentricToGmshTet(int *b, int ref)
|
||||
{
|
||||
int i = b[0];
|
||||
int j = b[1];
|
||||
int k = b[2];
|
||||
int l = b[3];
|
||||
bool ibdr = (i == 0);
|
||||
bool jbdr = (j == 0);
|
||||
bool kbdr = (k == 0);
|
||||
bool lbdr = (l == 0);
|
||||
if (ibdr && jbdr && kbdr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (jbdr && kbdr && lbdr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (ibdr && kbdr && lbdr)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (ibdr && jbdr && lbdr)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
int offset = 4;
|
||||
if (jbdr && kbdr) // Edge DOF on j == 0 and k == 0
|
||||
{
|
||||
return offset + i - 1;
|
||||
}
|
||||
else if (kbdr && lbdr) // Edge DOF on k == 0 and l == 0
|
||||
{
|
||||
return offset + ref - 1 + j - 1;
|
||||
}
|
||||
else if (ibdr && kbdr) // Edge DOF on i == 0 and k == 0
|
||||
{
|
||||
return offset + 2 * (ref - 1) + ref - j - 1;
|
||||
}
|
||||
else if (ibdr && jbdr) // Edge DOF on i == 0 and j == 0
|
||||
{
|
||||
return offset + 3 * (ref - 1) + ref - k - 1;
|
||||
}
|
||||
else if (ibdr && lbdr) // Edge DOF on i == 0 and l == 0
|
||||
{
|
||||
return offset + 4 * (ref - 1) + ref - k - 1;
|
||||
}
|
||||
else if (jbdr && lbdr) // Edge DOF on j == 0 and l == 0
|
||||
{
|
||||
return offset + 5 * (ref - 1) + ref - k - 1;
|
||||
}
|
||||
|
||||
// Recursive numbering for the faces
|
||||
offset += 6 * (ref - 1);
|
||||
if (kbdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = j-1;
|
||||
b_out[1] = i-1;
|
||||
b_out[2] = ref - i - j - 1;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
else if (jbdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = i-1;
|
||||
b_out[1] = k-1;
|
||||
b_out[2] = ref - i - k - 1;
|
||||
offset += (ref - 1) * (ref - 2) / 2;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
else if (ibdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = k-1;
|
||||
b_out[1] = j-1;
|
||||
b_out[2] = ref - j - k - 1;
|
||||
offset += (ref - 1) * (ref - 2);
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
else if (lbdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = ref-j-k-1;
|
||||
b_out[1] = j-1;
|
||||
b_out[2] = k-1;
|
||||
offset += 3 * (ref - 1) * (ref - 2) / 2;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
|
||||
// Recursive numbering for interior
|
||||
{
|
||||
int b_out[4];
|
||||
b_out[0] = i-1;
|
||||
b_out[1] = j-1;
|
||||
b_out[2] = k-1;
|
||||
b_out[3] = ref - i - j - k - 1;
|
||||
offset += 2 * (ref - 1) * (ref - 2);
|
||||
return offset + BarycentricToGmshTet(b_out, ref-4);
|
||||
}
|
||||
}
|
||||
|
||||
int CartesianToGmshQuad(int idx_in[], int ref)
|
||||
{
|
||||
int i = idx_in[0];
|
||||
int j = idx_in[1];
|
||||
// Do we lie on any of the edges
|
||||
bool ibdr = (i == 0 || i == ref);
|
||||
bool jbdr = (j == 0 || j == ref);
|
||||
if (ibdr && jbdr) // Vertex DOF
|
||||
{
|
||||
return (i ? (j ? 2 : 1) : (j ? 3 : 0));
|
||||
}
|
||||
int offset = 4;
|
||||
if (jbdr) // Edge DOF on j==0 or j==ref
|
||||
{
|
||||
return offset + (j ? 3*ref - 3 - i : i - 1);
|
||||
}
|
||||
else if (ibdr) // Edge DOF on i==0 or i==ref
|
||||
{
|
||||
return offset + (i ? ref - 1 + j - 1 : 4*ref - 4 - j);
|
||||
}
|
||||
else // Recursive numbering for interior
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = i-1;
|
||||
idx_out[1] = j-1;
|
||||
offset += 4 * (ref - 1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
}
|
||||
|
||||
int CartesianToGmshHex(int idx_in[], int ref)
|
||||
{
|
||||
int i = idx_in[0];
|
||||
int j = idx_in[1];
|
||||
int k = idx_in[2];
|
||||
// Do we lie on any of the edges
|
||||
bool ibdr = (i == 0 || i == ref);
|
||||
bool jbdr = (j == 0 || j == ref);
|
||||
bool kbdr = (k == 0 || k == ref);
|
||||
if (ibdr && jbdr && kbdr) // Vertex DOF
|
||||
{
|
||||
return (i ? (j ? (k ? 6 : 2) : (k ? 5 : 1)) :
|
||||
(j ? (k ? 7 : 3) : (k ? 4 : 0)));
|
||||
}
|
||||
int offset = 8;
|
||||
if (jbdr && kbdr) // Edge DOF on x-directed edge
|
||||
{
|
||||
return offset + (j ? (k ? 12*ref-12-i: 6*ref-6-i) :
|
||||
(k ? 8*ref-9+i: i-1));
|
||||
}
|
||||
else if (ibdr && kbdr) // Edge DOF on y-directed edge
|
||||
{
|
||||
return offset + (k ? (i ? 10*ref-11+j: 9*ref-10+j) :
|
||||
(i ? 3*ref-4+j: ref-2+j));
|
||||
}
|
||||
else if (ibdr && jbdr) // Edge DOF on z-directed edge
|
||||
{
|
||||
return offset + (i ? (j ? 6*ref-7+k: 4*ref-5+k) :
|
||||
(j ? 7*ref-8+k: 2*ref-3+k));
|
||||
}
|
||||
else if (ibdr) // Face DOF on x-directed face
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = i ? j-1 : k-1;
|
||||
idx_out[1] = i ? k-1 : j-1;
|
||||
offset += (12 + (i ? 3 : 2) * (ref - 1)) * (ref - 1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
else if (jbdr) // Face DOF on y-directed face
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = j ? ref-i-1 : i-1;
|
||||
idx_out[1] = j ? k-1 : k-1;
|
||||
offset += (12 + (j ? 4 : 1) * (ref - 1)) * (ref - 1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
else if (kbdr) // Face DOF on z-directed face
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = k ? i-1 : j-1;
|
||||
idx_out[1] = k ? j-1 : i-1;
|
||||
offset += (12 + (k ? 5 : 0) * (ref - 1)) * (ref - 1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
else // Recursive numbering for interior
|
||||
{
|
||||
int idx_out[3];
|
||||
idx_out[0] = i-1;
|
||||
idx_out[1] = j-1;
|
||||
idx_out[2] = k-1;
|
||||
|
||||
offset += (12 + 6 * (ref - 1)) * (ref - 1);
|
||||
return offset + CartesianToGmshHex(idx_out, ref-2);
|
||||
}
|
||||
}
|
||||
|
||||
int WedgeToGmshPri(int idx_in[], int ref)
|
||||
{
|
||||
int i = idx_in[0];
|
||||
int j = idx_in[1];
|
||||
int k = idx_in[2];
|
||||
int l = ref - i -j;
|
||||
bool ibdr = (i == 0);
|
||||
bool jbdr = (j == 0);
|
||||
bool kbdr = (k == 0 || k == ref);
|
||||
bool lbdr = (l == 0);
|
||||
if (ibdr && jbdr && kbdr)
|
||||
{
|
||||
return k ? 3 : 0;
|
||||
}
|
||||
else if (jbdr && lbdr && kbdr)
|
||||
{
|
||||
return k ? 4 : 1;
|
||||
}
|
||||
else if (ibdr && lbdr && kbdr)
|
||||
{
|
||||
return k ? 5 : 2;
|
||||
}
|
||||
int offset = 6;
|
||||
if (jbdr && kbdr)
|
||||
{
|
||||
return offset + (k ? 6 * (ref - 1) + i - 1: i - 1);
|
||||
}
|
||||
else if (ibdr && kbdr)
|
||||
{
|
||||
return offset + (k ? 7 * (ref -1) + j-1 : ref - 1 + j - 1);
|
||||
}
|
||||
else if (ibdr && jbdr)
|
||||
{
|
||||
return offset + 2 * (ref - 1) + k - 1;
|
||||
}
|
||||
else if (lbdr && kbdr)
|
||||
{
|
||||
return offset + (k ? 8 * (ref -1) + j - 1 : 3 * (ref - 1) + j - 1);
|
||||
}
|
||||
else if (jbdr && lbdr)
|
||||
{
|
||||
return offset + 4 * (ref - 1) + k - 1;
|
||||
}
|
||||
else if (ibdr && lbdr)
|
||||
{
|
||||
return offset + 5 * (ref - 1) + k - 1;
|
||||
}
|
||||
offset += 9 * (ref-1);
|
||||
if (kbdr) // Triangular faces at k=0 and k=ref
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = k ? i-1 : j-1;
|
||||
b_out[1] = k ? j-1 : i-1;
|
||||
b_out[2] = ref - i - j - 1;
|
||||
offset += k ? (ref-1)*(ref-2) / 2: 0;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
offset += (ref-1)*(ref-2);
|
||||
if (jbdr) // Quadrilateral face at j=0
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = i-1;
|
||||
idx_out[1] = k-1;
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
else if (ibdr) // Quadrilateral face at i=0
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = k-1;
|
||||
idx_out[1] = j-1;
|
||||
offset += (ref-1)*(ref-1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
else if (lbdr) // Quadrilateral face at l=ref-i-j=0
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = j-1;
|
||||
idx_out[1] = k-1;
|
||||
offset += 2*(ref-1)*(ref-1);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
offset += 3*(ref-1)*(ref-1);
|
||||
// The Gmsh Prism interiors are a tensor product of segments of order ref-2
|
||||
// and triangles of order ref-3
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = i-1;
|
||||
b_out[1] = j-1;
|
||||
b_out[2] = ref - i - j - 1;
|
||||
int ot = BarycentricToVTKTriangle(b_out, ref-3);
|
||||
int os = (k==1) ? 0 : (k == ref-1 ? 1 : k);
|
||||
return offset + (ref-1) * ot + os;
|
||||
}
|
||||
}
|
||||
|
||||
int CartesianToGmshPyramid(int idx_in[], int ref)
|
||||
{
|
||||
int i = idx_in[0];
|
||||
int j = idx_in[1];
|
||||
int k = idx_in[2];
|
||||
// Do we lie on any of the edges
|
||||
bool ibdr = (i == 0 || i == ref-k);
|
||||
bool jbdr = (j == 0 || j == ref-k);
|
||||
bool kbdr = (k == 0);
|
||||
if (ibdr && jbdr && kbdr)
|
||||
{
|
||||
return i ? (j ? 2 : 1): (j ? 3 : 0);
|
||||
}
|
||||
else if (k == ref)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
int offset = 5;
|
||||
if (jbdr && kbdr)
|
||||
{
|
||||
return offset + (j ? (6 * ref - 6 - i) : (i - 1));
|
||||
}
|
||||
else if (ibdr && kbdr)
|
||||
{
|
||||
return offset + (i ? (3 * ref - 4 + j) : (ref - 2 + j));
|
||||
}
|
||||
else if (ibdr && jbdr)
|
||||
{
|
||||
return offset + (i ? (j ? 6 : 4) : (j ? 7 : 2 )) * (ref-1) + k - 1;
|
||||
}
|
||||
offset += 8*(ref-1);
|
||||
if (jbdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = j ? ref - i - k - 1 : i - 1;
|
||||
b_out[1] = k - 1;
|
||||
b_out[2] = (j ? i - 1 : ref - i - k - 1);
|
||||
offset += (j ? 3 : 0) * (ref - 1) * (ref - 2) / 2;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
else if (ibdr)
|
||||
{
|
||||
int b_out[3];
|
||||
b_out[0] = i ? j - 1: ref - j - k - 1;
|
||||
b_out[1] = k - 1;
|
||||
b_out[2] = (i ? ref - j - k - 1: j - 1);
|
||||
offset += (i ? 2 : 1) * (ref - 1) * (ref - 2) / 2;
|
||||
return offset + BarycentricToVTKTriangle(b_out, ref-3);
|
||||
}
|
||||
else if (kbdr)
|
||||
{
|
||||
int idx_out[2];
|
||||
idx_out[0] = k ? i-1 : j-1;
|
||||
idx_out[1] = k ? j-1 : i-1;
|
||||
offset += 2 * (ref - 1) * (ref - 2);
|
||||
return offset + CartesianToGmshQuad(idx_out, ref-2);
|
||||
}
|
||||
offset += (2 * (ref - 2) + (ref - 1)) * (ref - 1) ;
|
||||
{
|
||||
int idx_out[3];
|
||||
idx_out[0] = i-1;
|
||||
idx_out[1] = j-1;
|
||||
idx_out[2] = k-1;
|
||||
return offset + CartesianToGmshPyramid(idx_out, ref-3);
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOSegmentMapping(int order, int *map)
|
||||
{
|
||||
map[0] = 0;
|
||||
map[order] = 1;
|
||||
for (int i=1; i<order; i++)
|
||||
{
|
||||
map[i] = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOTriangleMapping(int order, int *map)
|
||||
{
|
||||
int b[3];
|
||||
int o = 0;
|
||||
for (b[1]=0; b[1]<=order; ++b[1])
|
||||
{
|
||||
for (b[0]=0; b[0]<=order-b[1]; ++b[0])
|
||||
{
|
||||
b[2] = order - b[0] - b[1];
|
||||
map[o] = BarycentricToVTKTriangle(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOQuadrilateralMapping(int order, int *map)
|
||||
{
|
||||
int b[2];
|
||||
int o = 0;
|
||||
for (b[1]=0; b[1]<=order; b[1]++)
|
||||
{
|
||||
for (b[0]=0; b[0]<=order; b[0]++)
|
||||
{
|
||||
map[o] = CartesianToGmshQuad(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOTetrahedronMapping(int order, int *map)
|
||||
{
|
||||
int b[4];
|
||||
int o = 0;
|
||||
for (b[2]=0; b[2]<=order; ++b[2])
|
||||
{
|
||||
|
||||
for (b[1]=0; b[1]<=order-b[2]; ++b[1])
|
||||
{
|
||||
for (b[0]=0; b[0]<=order-b[1]-b[2]; ++b[0])
|
||||
{
|
||||
b[3] = order - b[0] - b[1] - b[2];
|
||||
map[o] = BarycentricToGmshTet(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOHexahedronMapping(int order, int *map)
|
||||
{
|
||||
int b[3];
|
||||
int o = 0;
|
||||
for (b[2]=0; b[2]<=order; b[2]++)
|
||||
{
|
||||
for (b[1]=0; b[1]<=order; b[1]++)
|
||||
{
|
||||
for (b[0]=0; b[0]<=order; b[0]++)
|
||||
{
|
||||
map[o] = CartesianToGmshHex(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOWedgeMapping(int order, int *map)
|
||||
{
|
||||
int b[3];
|
||||
int o = 0;
|
||||
for (b[2]=0; b[2]<=order; b[2]++)
|
||||
{
|
||||
for (b[1]=0; b[1]<=order; b[1]++)
|
||||
{
|
||||
for (b[0]=0; b[0]<=order - b[1]; b[0]++)
|
||||
{
|
||||
map[o] = WedgeToGmshPri(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GmshHOPyramidMapping(int order, int *map)
|
||||
{
|
||||
int b[3];
|
||||
int o = 0;
|
||||
for (b[2]=0; b[2]<=order; b[2]++)
|
||||
{
|
||||
for (b[1]=0; b[1]<=order - b[2]; b[1]++)
|
||||
{
|
||||
for (b[0]=0; b[0]<=order - b[2]; b[0]++)
|
||||
{
|
||||
map[o] = CartesianToGmshPyramid(b, order);
|
||||
o++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#ifndef MFEM_GMSH
|
||||
#define MFEM_GMSH
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Helpers for reading high order elements in Gmsh format
|
||||
|
||||
/** @name Gmsh High-Order Vertex Mappings
|
||||
|
||||
These functions generate the mappings needed to translate the order of
|
||||
Gmsh's high-order vertices into MFEM's L2 degree of freedom ordering. The
|
||||
mapping is defined so that MFEM_DoF[i] = Gmsh_Vert[map[i]]. The @a map
|
||||
array must already be allocated with the proper number of entries for the
|
||||
element type at the given element @a order.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Segment
|
||||
void GmshHOSegmentMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Triangle
|
||||
void GmshHOTriangleMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Quadrilateral
|
||||
void GmshHOQuadrilateralMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Tetrahedron
|
||||
void GmshHOTetrahedronMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Hexahedron
|
||||
void GmshHOHexahedronMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Wedge
|
||||
void GmshHOWedgeMapping(int order, int *map);
|
||||
|
||||
/// @brief Generate Gmsh vertex mapping for a Pyramid
|
||||
void GmshHOPyramidMapping(int order, int *map);
|
||||
|
||||
///@}
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
@@ -338,6 +338,7 @@ void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
|
||||
ElTr->Attribute = GetAttribute(i);
|
||||
ElTr->ElementNo = i;
|
||||
ElTr->ElementType = ElementTransformation::ELEMENT;
|
||||
ElTr->Reset();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
GetPointMatrix(i, ElTr->GetPointMat());
|
||||
@@ -370,6 +371,7 @@ void Mesh::GetElementTransformation(int i, const Vector &nodes,
|
||||
ElTr->ElementNo = i;
|
||||
ElTr->ElementType = ElementTransformation::ELEMENT;
|
||||
DenseMatrix &pm = ElTr->GetPointMat();
|
||||
ElTr->Reset();
|
||||
nodes.HostRead();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
@@ -424,6 +426,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
|
||||
ElTr->ElementNo = i; // boundary element number
|
||||
ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
|
||||
DenseMatrix &pm = ElTr->GetPointMat();
|
||||
ElTr->Reset();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
GetBdrPointMatrix(i, pm);
|
||||
@@ -480,6 +483,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
|
||||
FTr->ElementNo = FaceNo;
|
||||
FTr->ElementType = ElementTransformation::FACE;
|
||||
DenseMatrix &pm = FTr->GetPointMat();
|
||||
FTr->Reset();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
const int *v = (Dim == 1) ? &FaceNo : faces[FaceNo]->GetVertices();
|
||||
@@ -562,6 +566,7 @@ void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
|
||||
EdTr->ElementNo = EdgeNo;
|
||||
EdTr->ElementType = ElementTransformation::EDGE;
|
||||
DenseMatrix &pm = EdTr->GetPointMat();
|
||||
EdTr->Reset();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
Array<int> v;
|
||||
@@ -614,6 +619,7 @@ void Mesh::GetLocalPtToSegTransformation(
|
||||
{
|
||||
const IntegrationRule *SegVert;
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&PointFE);
|
||||
SegVert = Geometries.GetVertices(Geometry::SEGMENT);
|
||||
@@ -629,6 +635,7 @@ void Mesh::GetLocalSegToTriTransformation(
|
||||
const int *tv, *so;
|
||||
const IntegrationRule *TriVert;
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&SegmentFE);
|
||||
tv = tri_t::Edges[i/64]; // (i/64) is the local face no. in the triangle
|
||||
@@ -648,6 +655,7 @@ void Mesh::GetLocalSegToQuadTransformation(
|
||||
const int *qv, *so;
|
||||
const IntegrationRule *QuadVert;
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&SegmentFE);
|
||||
qv = quad_t::Edges[i/64]; // (i/64) is the local face no. in the quad
|
||||
@@ -665,6 +673,7 @@ void Mesh::GetLocalTriToTetTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&TriangleFE);
|
||||
// (i/64) is the local face no. in the tet
|
||||
@@ -688,6 +697,7 @@ void Mesh::GetLocalTriToWdgTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&TriangleFE);
|
||||
// (i/64) is the local face no. in the pri
|
||||
@@ -713,6 +723,7 @@ void Mesh::GetLocalQuadToHexTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&QuadrilateralFE);
|
||||
// (i/64) is the local face no. in the hex
|
||||
@@ -734,6 +745,7 @@ void Mesh::GetLocalQuadToWdgTransformation(
|
||||
IsoparametricTransformation &Transf, int i)
|
||||
{
|
||||
DenseMatrix &locpm = Transf.GetPointMat();
|
||||
Transf.Reset();
|
||||
|
||||
Transf.SetFE(&QuadrilateralFE);
|
||||
// (i/64) is the local face no. in the pri
|
||||
|
||||
+823
-109
File diff suppressed because it is too large
Load Diff
@@ -1691,6 +1691,7 @@ void ParMesh::GetFaceNbrElementTransformation(
|
||||
ElTr->Attribute = elem->GetAttribute();
|
||||
ElTr->ElementNo = NumOfElements + i;
|
||||
ElTr->ElementType = ElementTransformation::ELEMENT;
|
||||
ElTr->Reset();
|
||||
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
@@ -2370,6 +2371,7 @@ void ParMesh::GetGhostFaceTransformation(
|
||||
{
|
||||
// calculate composition of FETr->Loc1 and FETr->Elem1
|
||||
DenseMatrix &face_pm = FETr->GetPointMat();
|
||||
FETr->Reset();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm);
|
||||
|
||||
@@ -37,6 +37,8 @@ void CreateVTKElementConnectivity(Array<int> &con, Geometry::Type geom,
|
||||
void WriteVTKEncodedCompressed(std::ostream &out, const void *bytes,
|
||||
uint32_t nbytes, int compression_level);
|
||||
|
||||
int BarycentricToVTKTriangle(int *b, int ref);
|
||||
|
||||
const char *VTKByteOrder();
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
using namespace mfem;
|
||||
using namespace std;
|
||||
|
||||
// This tranformation can be applied to a mesh with the 't' menu option.
|
||||
// This transformation can be applied to a mesh with the 't' menu option.
|
||||
void transformation(const Vector &p, Vector &v)
|
||||
{
|
||||
// simple shear transformation
|
||||
@@ -72,6 +72,28 @@ double region(const Vector &p)
|
||||
return std::max(std::max(x - 0.25, -y), y - 1.0);
|
||||
}
|
||||
|
||||
// The projection of this function can be plotted with the 'l' menu option
|
||||
double f(const Vector &p)
|
||||
{
|
||||
double x = p(0);
|
||||
double y = p.Size() > 1 ? p(1) : 0.0;
|
||||
double z = p.Size() > 2 ? p(2) : 0.0;
|
||||
|
||||
if (1)
|
||||
{
|
||||
// torus in the xy-plane
|
||||
const double r_big = 2.0;
|
||||
const double r_small = 1.0;
|
||||
return hypot(r_big - hypot(x, y), z) - r_small;
|
||||
}
|
||||
if (0)
|
||||
{
|
||||
// sphere at the origin:
|
||||
const double r = 1.0;
|
||||
return hypot(hypot(x, y), z) - r;
|
||||
}
|
||||
}
|
||||
|
||||
Mesh *read_par_mesh(int np, const char *mesh_prefix)
|
||||
{
|
||||
Mesh *mesh;
|
||||
@@ -329,6 +351,7 @@ int main (int argc, char *argv[])
|
||||
"e) View elements\n"
|
||||
"h) View element sizes, h\n"
|
||||
"k) View element ratios, kappa\n"
|
||||
"l) Plot a function\n"
|
||||
"x) Print sub-element stats\n"
|
||||
"f) Find physical point in reference space\n"
|
||||
"p) Generate a partitioning\n"
|
||||
@@ -667,7 +690,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// These are the cases that open a new GLVis window
|
||||
// These are most of the cases that open a new GLVis window
|
||||
if (mk == 'm' || mk == 'b' || mk == 'e' || mk == 'v' || mk == 'h' ||
|
||||
mk == 'k' || mk == 'p')
|
||||
{
|
||||
@@ -980,6 +1003,43 @@ int main (int argc, char *argv[])
|
||||
delete bdr_attr_fespace;
|
||||
}
|
||||
|
||||
if (mk == 'l')
|
||||
{
|
||||
// Project and plot the function 'f'
|
||||
int p;
|
||||
FiniteElementCollection *fec = NULL;
|
||||
cout << "Enter projection space order: " << flush;
|
||||
cin >> p;
|
||||
if (p >= 1)
|
||||
{
|
||||
fec = new H1_FECollection(p, mesh->Dimension(),
|
||||
BasisType::GaussLobatto);
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new DG_FECollection(-p, mesh->Dimension(),
|
||||
BasisType::GaussLegendre);
|
||||
}
|
||||
FiniteElementSpace fes(mesh, fec);
|
||||
GridFunction level(&fes);
|
||||
FunctionCoefficient coeff(f);
|
||||
level.ProjectCoefficient(coeff);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
if (sol_sock.is_open())
|
||||
{
|
||||
sol_sock.precision(14);
|
||||
sol_sock << "solution\n" << *mesh << level << flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unable to connect to "
|
||||
<< vishost << ':' << visport << endl;
|
||||
}
|
||||
delete fec;
|
||||
}
|
||||
|
||||
if (mk == 'S')
|
||||
{
|
||||
const char mesh_file[] = "mesh-explorer.mesh";
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
//
|
||||
// Adapted discrete size:
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor
|
||||
// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
|
||||
// mesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
|
||||
// Adapted discrete size+aspect_ratio:
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
|
||||
// mesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
|
||||
@@ -75,6 +76,8 @@
|
||||
// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10
|
||||
// ICF combo shape + size (rings, slow convergence):
|
||||
// mesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1
|
||||
// Mixed tet / cube / hex mesh with limiting:
|
||||
// mesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
|
||||
// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
|
||||
// * mesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd
|
||||
// 2D non-conforming shape and equal size:
|
||||
@@ -546,23 +549,36 @@ int main(int argc, char *argv[])
|
||||
if (fdscheme) { he_nlf_integ->EnableFiniteDifferences(x); }
|
||||
he_nlf_integ->SetExactActionFlag(exactaction);
|
||||
|
||||
// 12. Setup the quadrature rule for the non-linear form integrator.
|
||||
const IntegrationRule *ir = NULL;
|
||||
const int geom_type = fespace->GetFE(0)->GetGeomType();
|
||||
// Setup the quadrature rules for the TMOP integrator.
|
||||
IntegrationRules *irules = NULL;
|
||||
switch (quad_type)
|
||||
{
|
||||
case 1: ir = &IntRulesLo.Get(geom_type, quad_order); break;
|
||||
case 2: ir = &IntRules.Get(geom_type, quad_order); break;
|
||||
case 3: ir = &IntRulesCU.Get(geom_type, quad_order); break;
|
||||
default: cout << "Unknown quad_type: " << quad_type << endl;
|
||||
delete he_nlf_integ; return 3;
|
||||
case 1: irules = &IntRulesLo; break;
|
||||
case 2: irules = &IntRules; break;
|
||||
case 3: irules = &IntRulesCU; break;
|
||||
default: cout << "Unknown quad_type: " << quad_type << endl; return 3;
|
||||
}
|
||||
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
|
||||
if (dim == 2)
|
||||
{
|
||||
cout << "Triangle quadrature points: "
|
||||
<< irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
|
||||
<< "\nQuadrilateral quadrature points: "
|
||||
<< irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
|
||||
}
|
||||
if (dim == 3)
|
||||
{
|
||||
cout << "Tetrahedron quadrature points: "
|
||||
<< irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
|
||||
<< "\nHexahedron quadrature points: "
|
||||
<< irules->Get(Geometry::CUBE, quad_order).GetNPoints()
|
||||
<< "\nPrism quadrature points: "
|
||||
<< irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
|
||||
}
|
||||
cout << "Quadrature points per cell: " << ir->GetNPoints() << endl;
|
||||
he_nlf_integ->SetIntegrationRule(*ir);
|
||||
|
||||
if (normalization) { he_nlf_integ->EnableNormalization(x0); }
|
||||
|
||||
// 13. Limit the node movement.
|
||||
// Limit the node movement.
|
||||
// The limiting distances can be given by a general function of space.
|
||||
GridFunction dist(fespace);
|
||||
dist = 1.0;
|
||||
@@ -600,7 +616,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 14. Setup the final NonlinearForm (which defines the integral of interest,
|
||||
// 12. Setup the final NonlinearForm (which defines the integral of interest,
|
||||
// its first and second derivatives). Here we can use a combination of
|
||||
// metrics, i.e., optimize the sum of two integrals, where both are
|
||||
// scaled by used-defined space-dependent weights. Note that there are no
|
||||
@@ -612,6 +628,7 @@ int main(int argc, char *argv[])
|
||||
TargetConstructor *target_c2 = NULL;
|
||||
FunctionCoefficient coeff2(weight_fun);
|
||||
|
||||
// Explicit combination of metrics.
|
||||
if (combomet > 0)
|
||||
{
|
||||
// First metric.
|
||||
@@ -631,7 +648,7 @@ int main(int argc, char *argv[])
|
||||
he_nlf_integ2->SetCoefficient(coeff2);
|
||||
}
|
||||
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c); }
|
||||
he_nlf_integ2->SetIntegrationRule(*ir);
|
||||
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
|
||||
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
|
||||
he_nlf_integ2->SetExactActionFlag(exactaction);
|
||||
|
||||
@@ -647,14 +664,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
const double init_energy = a.GetGridFunctionEnergy(x);
|
||||
|
||||
// 15. Visualize the starting mesh and metric values.
|
||||
// Visualize the starting mesh and metric values.
|
||||
// Note that for combinations of metrics, this only shows the first metric.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Initial metric values";
|
||||
vis_tmop_metric_s(mesh_poly_deg, *metric, *target_c, *mesh, title, 0);
|
||||
}
|
||||
|
||||
// 16. Fix all boundary nodes, or fix only a given component depending on the
|
||||
// 13. Fix all boundary nodes, or fix only a given component depending on the
|
||||
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
|
||||
// fixed x/y/z components of the node. Attribute 4 corresponds to an
|
||||
// entirely fixed node. Other boundary attributes do not affect the node
|
||||
@@ -667,10 +685,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
const int nd = fespace->GetBE(0)->GetDof();
|
||||
int n = 0;
|
||||
for (int i = 0; i < mesh->GetNBE(); i++)
|
||||
{
|
||||
const int nd = fespace->GetBE(i)->GetDof();
|
||||
const int attr = mesh->GetBdrElement(i)->GetAttribute();
|
||||
MFEM_VERIFY(!(dim == 2 && attr == 3),
|
||||
"Boundary attribute 3 must be used only for 3D meshes. "
|
||||
@@ -683,6 +701,7 @@ int main(int argc, char *argv[])
|
||||
n = 0;
|
||||
for (int i = 0; i < mesh->GetNBE(); i++)
|
||||
{
|
||||
const int nd = fespace->GetBE(i)->GetDof();
|
||||
const int attr = mesh->GetBdrElement(i)->GetAttribute();
|
||||
fespace->GetBdrElementVDofs(i, vdofs);
|
||||
if (attr == 1) // Fix x components.
|
||||
@@ -709,7 +728,7 @@ int main(int argc, char *argv[])
|
||||
a.SetEssentialVDofs(ess_vdofs);
|
||||
}
|
||||
|
||||
// 17. As we use the Newton method to solve the resulting nonlinear system,
|
||||
// 14. As we use the Newton method to solve the resulting nonlinear system,
|
||||
// here we setup the linear solver for the system's Jacobian.
|
||||
Solver *S = NULL;
|
||||
const double linsol_rtol = 1e-12;
|
||||
@@ -736,15 +755,17 @@ int main(int argc, char *argv[])
|
||||
S = minres;
|
||||
}
|
||||
|
||||
// 18. Compute the minimum det(J) of the starting mesh.
|
||||
// Compute the minimum det(J) of the starting mesh.
|
||||
tauval = infinity();
|
||||
const int NE = mesh->GetNE();
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
const IntegrationRule &ir =
|
||||
irules->Get(fespace->GetFE(i)->GetGeomType(), quad_order);
|
||||
ElementTransformation *transf = mesh->GetElementTransformation(i);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
for (int j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
transf->SetIntPoint(&ir->IntPoint(j));
|
||||
transf->SetIntPoint(&ir.IntPoint(j));
|
||||
tauval = min(tauval, transf->Jacobian().Det());
|
||||
}
|
||||
}
|
||||
@@ -752,7 +773,11 @@ int main(int argc, char *argv[])
|
||||
tauval -= 0.01 * h0.Min(); // Slightly below minJ0 to avoid div by 0.
|
||||
|
||||
// Perform the nonlinear optimization.
|
||||
TMOPNewtonSolver solver(*ir, solver_type);
|
||||
const IntegrationRule &ir =
|
||||
irules->Get(fespace->GetFE(0)->GetGeomType(), quad_order);
|
||||
TMOPNewtonSolver solver(ir, solver_type);
|
||||
// Provide all integration rules in case of a mixed mesh.
|
||||
solver.SetIntegrationRules(*irules, quad_order);
|
||||
if (solver_type == 0)
|
||||
{
|
||||
// Specify linear solver when we use a Newton-based solver.
|
||||
@@ -770,7 +795,7 @@ int main(int argc, char *argv[])
|
||||
cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n";
|
||||
}
|
||||
|
||||
// 20. Save the optimized mesh to a file. This output can be viewed later
|
||||
// 15. Save the optimized mesh to a file. This output can be viewed later
|
||||
// using GLVis: "glvis -m optimized.mesh".
|
||||
{
|
||||
ofstream mesh_ofs("optimized.mesh");
|
||||
@@ -778,7 +803,7 @@ int main(int argc, char *argv[])
|
||||
mesh->Print(mesh_ofs);
|
||||
}
|
||||
|
||||
// 21. Compute the amount of energy decrease.
|
||||
// 16. Compute the amount of energy decrease.
|
||||
const double fin_energy = a.GetGridFunctionEnergy(x);
|
||||
double metric_part = fin_energy;
|
||||
if (lim_const > 0.0 || adapt_lim_const > 0.0)
|
||||
@@ -798,7 +823,7 @@ int main(int argc, char *argv[])
|
||||
cout << "The strain energy decreased by: " << setprecision(12)
|
||||
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
|
||||
|
||||
// 22. Visualize the final mesh and metric values.
|
||||
// 17. Visualize the final mesh and metric values.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Final metric values";
|
||||
@@ -812,7 +837,7 @@ int main(int argc, char *argv[])
|
||||
600, 600, 300, 300);
|
||||
}
|
||||
|
||||
// 23. Visualize the mesh displacement.
|
||||
// 18. Visualize the mesh displacement.
|
||||
if (visualization)
|
||||
{
|
||||
x0 -= x;
|
||||
@@ -827,7 +852,7 @@ int main(int argc, char *argv[])
|
||||
<< "keys jRmclA" << endl;
|
||||
}
|
||||
|
||||
// 24. Free the used memory.
|
||||
// 19. Free the used memory.
|
||||
delete S;
|
||||
delete target_c2;
|
||||
delete metric2;
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
//
|
||||
// Adapted discrete size:
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 2 -nor
|
||||
// Adapted discrete size; explicit combo of metrics; mixed tri/quad mesh:
|
||||
// mpirun -np 4 pmesh-optimizer -m ../../data/square-mixed.mesh -o 2 -rs 2 -mid 2 -tid 5 -ni 200 -bnd -qo 6 -cmb 2 -nor
|
||||
// Adapted discrete size+aspect_ratio:
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100
|
||||
// mpirun -np 4 pmesh-optimizer -m square01.mesh -o 2 -rs 2 -mid 7 -tid 6 -ni 100 -qo 6 -ex -st 1 -nor
|
||||
@@ -75,6 +76,8 @@
|
||||
// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 100 -ls 2 -li 100 -bnd -qt 1 -qo 8 -lc 10
|
||||
// ICF combo shape + size (rings, slow convergence):
|
||||
// mpirun -np 4 pmesh-optimizer -o 3 -rs 0 -mid 1 -tid 1 -ni 1000 -ls 2 -li 100 -bnd -qt 1 -qo 8 -cmb 1
|
||||
// Mixed tet / cube / hex mesh with limiting:
|
||||
// mpirun -np 4 pmesh-optimizer -m ../../data/fichera-mixed-p2.mesh -o 4 -rs 1 -mid 301 -tid 1 -fix-bnd -qo 6 -nor -lc 0.25
|
||||
// 3D pinched sphere shape (the mesh is in the mfem/data GitHub repository):
|
||||
// * mpirun -np 4 pmesh-optimizer -m ../../../mfem_data/ball-pert.mesh -o 4 -rs 0 -mid 303 -tid 1 -ni 20 -ls 2 -li 500 -fix-bnd
|
||||
// 2D non-conforming shape and equal size:
|
||||
@@ -482,11 +485,10 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
double volume_all, volume_ind_all;
|
||||
int NE_ALL;
|
||||
MPI_Allreduce(&volume, &volume_all, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
|
||||
MPI_Allreduce(&volume_ind, &volume_ind_all, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
MPI_Allreduce(&NE, &NE_ALL, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
|
||||
const int NE_ALL = pmesh->GetGlobalNE();
|
||||
|
||||
const double avg_zone_size = volume_all / NE_ALL;
|
||||
|
||||
@@ -586,25 +588,38 @@ int main (int argc, char *argv[])
|
||||
if (fdscheme) { he_nlf_integ->EnableFiniteDifferences(x); }
|
||||
he_nlf_integ->SetExactActionFlag(exactaction);
|
||||
|
||||
// 13. Setup the quadrature rule for the non-linear form integrator.
|
||||
const IntegrationRule *ir = NULL;
|
||||
const int geom_type = pfespace->GetFE(0)->GetGeomType();
|
||||
// Setup the quadrature rules for the TMOP integrator.
|
||||
IntegrationRules *irules = NULL;
|
||||
switch (quad_type)
|
||||
{
|
||||
case 1: ir = &IntRulesLo.Get(geom_type, quad_order); break;
|
||||
case 2: ir = &IntRules.Get(geom_type, quad_order); break;
|
||||
case 3: ir = &IntRulesCU.Get(geom_type, quad_order); break;
|
||||
case 1: irules = &IntRulesLo; break;
|
||||
case 2: irules = &IntRules; break;
|
||||
case 3: irules = &IntRulesCU; break;
|
||||
default:
|
||||
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
|
||||
return 3;
|
||||
}
|
||||
if (myid == 0)
|
||||
{ cout << "Quadrature points per cell: " << ir->GetNPoints() << endl; }
|
||||
he_nlf_integ->SetIntegrationRule(*ir);
|
||||
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
|
||||
if (myid == 0 && dim == 2)
|
||||
{
|
||||
cout << "Triangle quadrature points: "
|
||||
<< irules->Get(Geometry::TRIANGLE, quad_order).GetNPoints()
|
||||
<< "\nQuadrilateral quadrature points: "
|
||||
<< irules->Get(Geometry::SQUARE, quad_order).GetNPoints() << endl;
|
||||
}
|
||||
if (myid == 0 && dim == 3)
|
||||
{
|
||||
cout << "Tetrahedron quadrature points: "
|
||||
<< irules->Get(Geometry::TETRAHEDRON, quad_order).GetNPoints()
|
||||
<< "\nHexahedron quadrature points: "
|
||||
<< irules->Get(Geometry::CUBE, quad_order).GetNPoints()
|
||||
<< "\nPrism quadrature points: "
|
||||
<< irules->Get(Geometry::PRISM, quad_order).GetNPoints() << endl;
|
||||
}
|
||||
|
||||
if (normalization) { he_nlf_integ->ParEnableNormalization(x0); }
|
||||
|
||||
// 14. Limit the node movement.
|
||||
// Limit the node movement.
|
||||
// The limiting distances can be given by a general function of space.
|
||||
ParGridFunction dist(pfespace);
|
||||
dist = 1.0;
|
||||
@@ -642,7 +657,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Setup the final NonlinearForm (which defines the integral of interest,
|
||||
// 13. Setup the final NonlinearForm (which defines the integral of interest,
|
||||
// its first and second derivatives). Here we can use a combination of
|
||||
// metrics, i.e., optimize the sum of two integrals, where both are
|
||||
// scaled by used-defined space-dependent weights. Note that there are
|
||||
@@ -654,6 +669,7 @@ int main (int argc, char *argv[])
|
||||
TargetConstructor *target_c2 = NULL;
|
||||
FunctionCoefficient coeff2(weight_fun);
|
||||
|
||||
// Explicit combination of metrics.
|
||||
if (combomet > 0)
|
||||
{
|
||||
// First metric.
|
||||
@@ -673,7 +689,7 @@ int main (int argc, char *argv[])
|
||||
he_nlf_integ2->SetCoefficient(coeff2);
|
||||
}
|
||||
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c); }
|
||||
he_nlf_integ2->SetIntegrationRule(*ir);
|
||||
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
|
||||
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
|
||||
he_nlf_integ2->SetExactActionFlag(exactaction);
|
||||
|
||||
@@ -689,14 +705,15 @@ int main (int argc, char *argv[])
|
||||
|
||||
const double init_energy = a.GetParGridFunctionEnergy(x);
|
||||
|
||||
// 16. Visualize the starting mesh and metric values.
|
||||
// Visualize the starting mesh and metric values.
|
||||
// Note that for combinations of metrics, this only shows the first metric.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Initial metric values";
|
||||
vis_tmop_metric_p(mesh_poly_deg, *metric, *target_c, *pmesh, title, 0);
|
||||
}
|
||||
|
||||
// 17. Fix all boundary nodes, or fix only a given component depending on the
|
||||
// 14. Fix all boundary nodes, or fix only a given component depending on the
|
||||
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
|
||||
// fixed x/y/z components of the node. Attribute 4 corresponds to an
|
||||
// entirely fixed node. Other boundary attributes do not affect the node
|
||||
@@ -709,10 +726,10 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
const int nd = pfespace->GetBE(0)->GetDof();
|
||||
int n = 0;
|
||||
for (int i = 0; i < pmesh->GetNBE(); i++)
|
||||
{
|
||||
const int nd = pfespace->GetBE(i)->GetDof();
|
||||
const int attr = pmesh->GetBdrElement(i)->GetAttribute();
|
||||
MFEM_VERIFY(!(dim == 2 && attr == 3),
|
||||
"Boundary attribute 3 must be used only for 3D meshes. "
|
||||
@@ -725,6 +742,7 @@ int main (int argc, char *argv[])
|
||||
n = 0;
|
||||
for (int i = 0; i < pmesh->GetNBE(); i++)
|
||||
{
|
||||
const int nd = pfespace->GetBE(i)->GetDof();
|
||||
const int attr = pmesh->GetBdrElement(i)->GetAttribute();
|
||||
pfespace->GetBdrElementVDofs(i, vdofs);
|
||||
if (attr == 1) // Fix x components.
|
||||
@@ -751,7 +769,7 @@ int main (int argc, char *argv[])
|
||||
a.SetEssentialVDofs(ess_vdofs);
|
||||
}
|
||||
|
||||
// 18. As we use the Newton method to solve the resulting nonlinear system,
|
||||
// 15. As we use the Newton method to solve the resulting nonlinear system,
|
||||
// here we setup the linear solver for the system's Jacobian.
|
||||
Solver *S = NULL;
|
||||
const double linsol_rtol = 1e-12;
|
||||
@@ -778,15 +796,17 @@ int main (int argc, char *argv[])
|
||||
S = minres;
|
||||
}
|
||||
|
||||
// 19. Compute the minimum det(J) of the starting mesh.
|
||||
// Compute the minimum det(J) of the starting mesh.
|
||||
tauval = infinity();
|
||||
const int NE = pmesh->GetNE();
|
||||
for (int i = 0; i < NE; i++)
|
||||
{
|
||||
const IntegrationRule &ir =
|
||||
irules->Get(pfespace->GetFE(i)->GetGeomType(), quad_order);
|
||||
ElementTransformation *transf = pmesh->GetElementTransformation(i);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
for (int j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
transf->SetIntPoint(&ir->IntPoint(j));
|
||||
transf->SetIntPoint(&ir.IntPoint(j));
|
||||
tauval = min(tauval, transf->Jacobian().Det());
|
||||
}
|
||||
}
|
||||
@@ -800,7 +820,11 @@ int main (int argc, char *argv[])
|
||||
tauval -= 0.01 * h0min_all; // Slightly below minJ0 to avoid div by 0.
|
||||
|
||||
// Perform the nonlinear optimization.
|
||||
TMOPNewtonSolver solver(pfespace->GetComm(), *ir, solver_type);
|
||||
const IntegrationRule &ir =
|
||||
irules->Get(pfespace->GetFE(0)->GetGeomType(), quad_order);
|
||||
TMOPNewtonSolver solver(pfespace->GetComm(), ir, solver_type);
|
||||
// Provide all integration rules in case of a mixed mesh.
|
||||
solver.SetIntegrationRules(*irules, quad_order);
|
||||
if (solver_type == 0)
|
||||
{
|
||||
// Specify linear solver when we use a Newton-based solver.
|
||||
@@ -818,7 +842,7 @@ int main (int argc, char *argv[])
|
||||
cout << "Nonlinear solver: rtol = " << solver_rtol << " not achieved.\n";
|
||||
}
|
||||
|
||||
// 21. Save the optimized mesh to a file. This output can be viewed later
|
||||
// 16. Save the optimized mesh to a file. This output can be viewed later
|
||||
// using GLVis: "glvis -m optimized -np num_mpi_tasks".
|
||||
{
|
||||
ostringstream mesh_name;
|
||||
@@ -828,7 +852,7 @@ int main (int argc, char *argv[])
|
||||
pmesh->PrintAsOne(mesh_ofs);
|
||||
}
|
||||
|
||||
// 22. Compute the amount of energy decrease.
|
||||
// 17. Compute the amount of energy decrease.
|
||||
const double fin_energy = a.GetParGridFunctionEnergy(x);
|
||||
double metric_part = fin_energy;
|
||||
if (lim_const > 0.0 || adapt_lim_const > 0.0)
|
||||
@@ -851,7 +875,7 @@ int main (int argc, char *argv[])
|
||||
<< (init_energy - fin_energy) * 100.0 / init_energy << " %." << endl;
|
||||
}
|
||||
|
||||
// 23. Visualize the final mesh and metric values.
|
||||
// 18. Visualize the final mesh and metric values.
|
||||
if (visualization)
|
||||
{
|
||||
char title[] = "Final metric values";
|
||||
@@ -865,7 +889,7 @@ int main (int argc, char *argv[])
|
||||
600, 600, 300, 300);
|
||||
}
|
||||
|
||||
// 23. Visualize the mesh displacement.
|
||||
// 19. Visualize the mesh displacement.
|
||||
if (visualization)
|
||||
{
|
||||
x0 -= x;
|
||||
@@ -886,7 +910,7 @@ int main (int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// 24. Free the used memory.
|
||||
// 20. Free the used memory.
|
||||
delete S;
|
||||
delete target_c2;
|
||||
delete metric2;
|
||||
|
||||
@@ -20,9 +20,10 @@ sub usage {
|
||||
printf STDOUT <<EOF;
|
||||
|
||||
$0 [-h|--help]
|
||||
$0 {mfem_dir}
|
||||
$0 [-b <branch>] {mfem_dir}
|
||||
|
||||
where: {mfem_dir} is the MFEM source directory [default value: ../..]
|
||||
-b <branch> is the branch to check [default: HEAD]
|
||||
-h|--help prints this usage information and exits
|
||||
|
||||
This script checks if the current branch history, defined as the commits that
|
||||
@@ -37,16 +38,14 @@ EOF
|
||||
}
|
||||
|
||||
my $mfem_dir = "../..";
|
||||
|
||||
if (scalar @ARGV > 2) {
|
||||
printf STDERR "Error: too many command line arguments\n";
|
||||
usage 1;
|
||||
}
|
||||
my $branch = "HEAD";
|
||||
|
||||
while (my $opt = shift) {
|
||||
if ($opt) {
|
||||
if ($opt eq "-h" || $opt eq "--help") {
|
||||
usage 0;
|
||||
} elsif ($opt eq "-b") {
|
||||
$branch = shift;
|
||||
} else {
|
||||
$mfem_dir = $opt;
|
||||
}
|
||||
@@ -73,7 +72,7 @@ my $max_branch_kb = 1000;
|
||||
my $status = 0; # Return code
|
||||
|
||||
# Get SHA hash of all commits in this branch
|
||||
my @commits = split /\n/, `git log --pretty=format:%H master..HEAD`;
|
||||
my @commits = split /\n/, `git log --pretty=format:%H master..$branch`;
|
||||
|
||||
# Check if total number of commits in this branch exceeds the maximum allowable
|
||||
my $ncommits = scalar @commits;
|
||||
@@ -104,7 +103,7 @@ sub formatSize {
|
||||
# Loop over each commit in this branch, and check for large diffs
|
||||
my $total_size = 0;
|
||||
foreach my $sha (@commits) {
|
||||
my @blobs = `git diff-tree -r --no-commit-id $sha`;
|
||||
my @blobs = `git diff-tree -r -c --root --no-commit-id $sha`;
|
||||
my $nfiles_changed = scalar @blobs;
|
||||
if ($nfiles_changed > $commit_max_files_changed) {
|
||||
printf STDERR
|
||||
@@ -117,23 +116,53 @@ foreach my $sha (@commits) {
|
||||
my $commit_size = 0;
|
||||
foreach my $blob (@blobs) {
|
||||
my @blob_split = (split /\s/, $blob);
|
||||
my $src = @blob_split[2];
|
||||
my $dst = @blob_split[3];
|
||||
my $mode = @blob_split[4];
|
||||
my $fname = @blob_split[5];
|
||||
|
||||
my $nfields = scalar @blob_split;
|
||||
my $fname = "(no-filename)";
|
||||
my $blob_size = 0;
|
||||
# File was added
|
||||
if ($mode eq "A") { $blob_size += int(`git cat-file -s $dst`); }
|
||||
# File was copied
|
||||
elsif ($mode =~ m/C\d*/) { $blob_size += int(`git cat-file -s $dst`); }
|
||||
elsif ($mode eq "D") { }
|
||||
# File was modified, use the gzip'ed diff as a proxy of the required git storage
|
||||
elsif ($mode =~ m/M\d*/) { $blob_size += int(`git diff -U0 --binary $src $dst | gzip -c | wc -c`); }
|
||||
elsif ($mode =~ m/R\d*/) { }
|
||||
elsif ($mode eq "T") { }
|
||||
elsif ($mode eq "U") { }
|
||||
else { die "Unknown git status letter." }
|
||||
|
||||
if ($nfields == 6) {
|
||||
# 0 or 1 parents
|
||||
my $src = @blob_split[2];
|
||||
my $dst = @blob_split[3];
|
||||
my $mode = @blob_split[4];
|
||||
$fname = @blob_split[5];
|
||||
# File was added
|
||||
if ($mode eq "A") { $blob_size += int(`git cat-file -s $dst`); }
|
||||
# File was copied
|
||||
elsif ($mode =~ m/C\d*/) { $blob_size += int(`git cat-file -s $dst`); }
|
||||
elsif ($mode eq "D") { }
|
||||
# File was modified, use the gzip'ed diff as a proxy of the required git storage
|
||||
elsif ($mode =~ m/M\d*/) { $blob_size += int(`git diff -U0 --binary $src $dst | gzip -c | wc -c`); }
|
||||
elsif ($mode =~ m/R\d*/) { }
|
||||
elsif ($mode eq "T") { }
|
||||
elsif ($mode eq "U") { }
|
||||
else { die "Unknown git status letter." }
|
||||
} elsif ($nfields == 8) {
|
||||
# 2 parents
|
||||
my $src1 = @blob_split[3];
|
||||
my $src2 = @blob_split[4];
|
||||
my $dst = @blob_split[5];
|
||||
my $mode = @blob_split[6];
|
||||
$fname = @blob_split[7];
|
||||
if ($mode eq "AA") {
|
||||
# File was added
|
||||
$blob_size += int(`git cat-file -s $dst`); }
|
||||
elsif ($mode eq "DD") { }
|
||||
elsif ($mode eq "MM") {
|
||||
# File was modified, use the gzip'ed diff as a proxy of the required git
|
||||
# storage
|
||||
my $sz1 = int(`git diff -U0 --binary $src1 $dst | gzip -c | wc -c`);
|
||||
my $sz2 = int(`git diff -U0 --binary $src2 $dst | gzip -c | wc -c`);
|
||||
$blob_size += $sz1 < $sz2 ? $sz1 : $sz2; }
|
||||
elsif ($mode eq "AM") {
|
||||
my $sz2 = int(`git diff -U0 --binary $src2 $dst | gzip -c | wc -c`);
|
||||
$blob_size += $sz2; }
|
||||
elsif ($mode eq "MA") {
|
||||
my $sz1 = int(`git diff -U0 --binary $src1 $dst | gzip -c | wc -c`);
|
||||
$blob_size += $sz1; }
|
||||
else { die "Unknown git status letter: $mode, commit: $sha, file: $fname.\n\t" }
|
||||
}
|
||||
|
||||
if ($blob_size > $max_blob_kb*1024) {
|
||||
$status = 1;
|
||||
printf STDERR "\033[31mLarge change of size %s in file %s.\033[0m\n", formatSize($blob_size), $fname;
|
||||
@@ -155,6 +184,7 @@ if ($total_size > $max_branch_kb*1024) {
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
printf STDERR "\033[36mBranch $branch has errors.\033[0m\n";
|
||||
chdir $cur_dir;
|
||||
my $testname = basename $0;
|
||||
open(my $f, '>', "$testname.msg");
|
||||
|
||||
@@ -25,7 +25,9 @@ set(UNIT_TESTS_SRCS
|
||||
linalg/test_ilu.cpp
|
||||
linalg/test_matrix_block.cpp
|
||||
linalg/test_matrix_dense.cpp
|
||||
linalg/test_matrix_hypre.cpp
|
||||
linalg/test_matrix_rectangular.cpp
|
||||
linalg/test_matrix_sparse.cpp
|
||||
linalg/test_matrix_square.cpp
|
||||
linalg/test_ode.cpp
|
||||
linalg/test_ode2.cpp
|
||||
@@ -33,6 +35,7 @@ set(UNIT_TESTS_SRCS
|
||||
linalg/test_cg_indefinite.cpp
|
||||
linalg/test_vector.cpp
|
||||
mesh/test_mesh.cpp
|
||||
mesh/test_ncmesh.cpp
|
||||
fem/test_1d_bilininteg.cpp
|
||||
fem/test_2d_bilininteg.cpp
|
||||
fem/test_3d_bilininteg.cpp
|
||||
|
||||
@@ -17,9 +17,107 @@ using namespace mfem;
|
||||
namespace assemblediagonalpa
|
||||
{
|
||||
|
||||
int dimension;
|
||||
|
||||
double coeffFunction(const Vector& x)
|
||||
{
|
||||
if (dimension == 2)
|
||||
{
|
||||
return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) + 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return sin(8.0 * M_PI * x[0]) * cos(6.0 * M_PI * x[1]) *
|
||||
sin(4.0 * M_PI * x[2]) +
|
||||
2.0;
|
||||
}
|
||||
}
|
||||
|
||||
void vectorCoeffFunction(const Vector & x, Vector & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension > 1)
|
||||
{
|
||||
f[0] = sin(M_PI * x[1]);
|
||||
f[1] = sin(2.5 * M_PI * x[0]);
|
||||
}
|
||||
if (dimension == 3)
|
||||
{
|
||||
f[2] = sin(6.1 * M_PI * x[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void asymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(1,0) = cos(1.3 * M_PI * x[1]); // 2,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f(1,0) = cos(M_PI * x[0]); // 2,1
|
||||
f(1,1) = 1.1 + sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f(2,0) = sin(1.5 * M_PI * x[1]); // 3,1
|
||||
f(2,1) = cos(2.9 * M_PI * x[0]); // 3,2
|
||||
f(2,2) = 1.1 + sin(6.1 * M_PI * x[2]); // 3,3
|
||||
}
|
||||
}
|
||||
|
||||
void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
f(1,0) = f(0,1);
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f(0,0) = sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3
|
||||
f(1,0) = f(0,1);
|
||||
f(2,0) = f(0,2);
|
||||
f(2,1) = f(1,2);
|
||||
}
|
||||
}
|
||||
|
||||
void symmetricMatrixCoeffFunction(const Vector & x, Vector & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f[0] = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f[0] = sin(M_PI * x[1]); // 1,1
|
||||
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f[2] = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f[3] = sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f[4] = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f[5] = sin(6.1 * M_PI * x[2]); // 3,3
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("massdiag")
|
||||
{
|
||||
for (int dimension = 2; dimension < 4; ++dimension)
|
||||
for (dimension = 2; dimension < 4; ++dimension)
|
||||
{
|
||||
for (int ne = 1; ne < 3; ++ne)
|
||||
{
|
||||
@@ -67,7 +165,7 @@ TEST_CASE("massdiag")
|
||||
|
||||
TEST_CASE("diffusiondiag")
|
||||
{
|
||||
for (int dimension = 2; dimension < 4; ++dimension)
|
||||
for (dimension = 2; dimension < 4; ++dimension)
|
||||
{
|
||||
for (int ne = 1; ne < 3; ++ne)
|
||||
{
|
||||
@@ -199,81 +297,139 @@ TEST_CASE("Vector Diffusion Diagonal PA",
|
||||
|
||||
TEST_CASE("Hcurl/Hdiv diagonal PA")
|
||||
{
|
||||
for (int dimension = 2; dimension < 4; ++dimension)
|
||||
for (dimension = 2; dimension < 4; ++dimension)
|
||||
{
|
||||
for (int spaceType = 0; spaceType < 2; ++spaceType)
|
||||
for (int integrator = 0; integrator < 2; ++integrator)
|
||||
for (int coeffType = 0; coeffType < 5; ++coeffType)
|
||||
{
|
||||
const int numSpaces = (coeffType == 0) ? 2 : 1;
|
||||
const int numIntegrators = (coeffType == 0) ? 2 : 1;
|
||||
|
||||
Coefficient* coeff = nullptr;
|
||||
VectorCoefficient* vcoeff = nullptr;
|
||||
MatrixCoefficient* mcoeff = nullptr;
|
||||
MatrixCoefficient* smcoeff = nullptr;
|
||||
if (coeffType == 0)
|
||||
{
|
||||
for (int ne = 1; ne < 3; ++ne)
|
||||
coeff = new ConstantCoefficient(12.34);
|
||||
}
|
||||
else if (coeffType == 1)
|
||||
{
|
||||
coeff = new FunctionCoefficient(&coeffFunction);
|
||||
}
|
||||
else if (coeffType == 2)
|
||||
{
|
||||
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
|
||||
}
|
||||
else if (coeffType == 3)
|
||||
{
|
||||
mcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&fullSymmetricMatrixCoeffFunction);
|
||||
smcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&symmetricMatrixCoeffFunction);
|
||||
}
|
||||
else if (coeffType == 4)
|
||||
{
|
||||
mcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&asymmetricMatrixCoeffFunction);
|
||||
smcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&asymmetricMatrixCoeffFunction);
|
||||
}
|
||||
|
||||
for (int spaceType = 0; spaceType < numSpaces; ++spaceType)
|
||||
{
|
||||
for (int integrator = 0; integrator < numIntegrators; ++integrator)
|
||||
{
|
||||
if (spaceType == 0)
|
||||
std::cout << "Testing " << dimension <<
|
||||
"D partial assembly H(curl) diagonal for integrator " << integrator << ": "
|
||||
<< std::pow(ne, dimension) << " elements." << std::endl;
|
||||
else
|
||||
std::cout << "Testing " << dimension <<
|
||||
"D partial assembly H(div) diagonal for integrator " << integrator << ": "
|
||||
<< std::pow(ne, dimension) << " elements." << std::endl;
|
||||
|
||||
for (int order = 1; order < 4; ++order)
|
||||
for (int ne = 1; ne < 3; ++ne)
|
||||
{
|
||||
Mesh * mesh;
|
||||
if (dimension == 2)
|
||||
{
|
||||
mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
}
|
||||
if (spaceType == 0)
|
||||
std::cout << "Testing " << dimension <<
|
||||
"D partial assembly H(curl) diagonal for integrator " << integrator
|
||||
<< " and coeffType " << coeffType << ": "
|
||||
<< std::pow(ne, dimension) << " elements." << std::endl;
|
||||
else
|
||||
{
|
||||
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
}
|
||||
std::cout << "Testing " << dimension <<
|
||||
"D partial assembly H(div) diagonal for integrator " << integrator
|
||||
<< " and coeffType " << coeffType << ": "
|
||||
<< std::pow(ne, dimension) << " elements." << std::endl;
|
||||
|
||||
FiniteElementCollection* fec = (spaceType == 0) ?
|
||||
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
|
||||
(FiniteElementCollection*) new RT_FECollection(order, dimension);
|
||||
|
||||
FiniteElementSpace fespace(mesh, fec);
|
||||
BilinearForm paform(&fespace);
|
||||
BilinearForm faform(&fespace);
|
||||
ConstantCoefficient one(1.0);
|
||||
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
if (integrator == 0)
|
||||
for (int order = 1; order < 4; ++order)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(one));
|
||||
faform.AddDomainIntegrator(new VectorFEMassIntegrator(one));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spaceType == 0)
|
||||
Mesh * mesh;
|
||||
if (dimension == 2)
|
||||
{
|
||||
paform.AddDomainIntegrator(new CurlCurlIntegrator(one));
|
||||
faform.AddDomainIntegrator(new CurlCurlIntegrator(one));
|
||||
mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new DivDivIntegrator(one));
|
||||
faform.AddDomainIntegrator(new DivDivIntegrator(one));
|
||||
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
FiniteElementCollection* fec = (spaceType == 0) ?
|
||||
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
|
||||
(FiniteElementCollection*) new RT_FECollection(order, dimension);
|
||||
|
||||
FiniteElementSpace fespace(mesh, fec);
|
||||
BilinearForm paform(&fespace);
|
||||
BilinearForm faform(&fespace);
|
||||
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
if (integrator == 0)
|
||||
{
|
||||
if (coeffType >= 3)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
|
||||
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
|
||||
}
|
||||
else if (coeffType == 2)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
faform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spaceType == 0)
|
||||
{
|
||||
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff));
|
||||
faform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff));
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff));
|
||||
faform.AddDomainIntegrator(new DivDivIntegrator(*coeff));
|
||||
}
|
||||
}
|
||||
paform.Assemble();
|
||||
Vector pa_diag(fespace.GetVSize());
|
||||
paform.AssembleDiagonal(pa_diag);
|
||||
|
||||
faform.Assemble();
|
||||
faform.Finalize();
|
||||
Vector assembly_diag(fespace.GetVSize());
|
||||
faform.SpMat().GetDiag(assembly_diag);
|
||||
|
||||
assembly_diag -= pa_diag;
|
||||
double error = assembly_diag.Norml2();
|
||||
std::cout << " order: " << order << ", error norm: " << error << std::endl;
|
||||
REQUIRE(assembly_diag.Norml2() < 1.e-11);
|
||||
|
||||
delete mesh;
|
||||
delete fec;
|
||||
}
|
||||
paform.Assemble();
|
||||
Vector pa_diag(fespace.GetVSize());
|
||||
paform.AssembleDiagonal(pa_diag);
|
||||
} // ne
|
||||
} // integrator
|
||||
} // spaceType
|
||||
|
||||
faform.Assemble();
|
||||
faform.Finalize();
|
||||
Vector assembly_diag(fespace.GetVSize());
|
||||
faform.SpMat().GetDiag(assembly_diag);
|
||||
|
||||
assembly_diag -= pa_diag;
|
||||
double error = assembly_diag.Norml2();
|
||||
std::cout << " order: " << order << ", error norm: " << error << std::endl;
|
||||
REQUIRE(assembly_diag.Norml2() < 1.e-12);
|
||||
|
||||
delete mesh;
|
||||
delete fec;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete coeff;
|
||||
delete vcoeff;
|
||||
delete mcoeff;
|
||||
delete smcoeff;
|
||||
} // coeffType
|
||||
} // dimension
|
||||
}
|
||||
|
||||
} // namespace assemblediagonalpa
|
||||
|
||||
@@ -48,7 +48,6 @@ void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
|
||||
const AssemblyLevel assembly)
|
||||
{
|
||||
mesh.EnsureNodes();
|
||||
mesh.SetCurvature(mesh.GetNodalFESpace()->GetOrder(0));
|
||||
int dim = mesh.Dimension();
|
||||
|
||||
FiniteElementCollection *fec;
|
||||
@@ -107,13 +106,77 @@ void test_assembly_level(Mesh &&mesh, int order, bool dg, const int pb,
|
||||
|
||||
TEST_CASE("Assembly Levels", "[AssemblyLevel]")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
SECTION("Continuous Galerkin")
|
||||
{
|
||||
for (int pb : {0, 1, 2})
|
||||
const bool dg = false;
|
||||
SECTION("2D")
|
||||
{
|
||||
for (bool dg : {true, false})
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
SECTION("2D")
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
for (int order : {2, 3, 4})
|
||||
{
|
||||
test_assembly_level(Mesh("../../data/inline-quad.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
test_assembly_level(Mesh("../../data/periodic-hexagon.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
test_assembly_level(Mesh("../../data/star-q3.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("3D")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
int order = 2;
|
||||
test_assembly_level(Mesh("../../data/inline-hex.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("AMR 2D")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
for (int order : {2, 3, 4})
|
||||
{
|
||||
test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
|
||||
order, false, 0, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("AMR 3D")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
int order = 2;
|
||||
test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
|
||||
order, false, 0, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Discontinuous Galerkin")
|
||||
{
|
||||
const bool dg = true;
|
||||
SECTION("2D")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
for (int order : {2, 3, 4})
|
||||
{
|
||||
@@ -125,32 +188,24 @@ TEST_CASE("Assembly Levels", "[AssemblyLevel]")
|
||||
order, dg, pb, assembly);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("3D")
|
||||
{
|
||||
int order = 2;
|
||||
test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
}
|
||||
}
|
||||
|
||||
// Test AMR cases (DG not implemented)
|
||||
SECTION("AMR 2D")
|
||||
}
|
||||
SECTION("3D")
|
||||
{
|
||||
for (AssemblyLevel assembly : {AssemblyLevel::PARTIAL,AssemblyLevel::ELEMENT,AssemblyLevel::FULL})
|
||||
{
|
||||
for (int order : {2, 3, 4})
|
||||
for (int pb : {0, 1, 2})
|
||||
{
|
||||
test_assembly_level(Mesh("../../data/amr-quad.mesh", 1, 1),
|
||||
order, false, 0, assembly);
|
||||
for (bool dg : {true, false})
|
||||
{
|
||||
int order = 2;
|
||||
test_assembly_level(Mesh("../../data/periodic-cube.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
test_assembly_level(Mesh("../../data/fichera-q3.mesh", 1, 1),
|
||||
order, dg, pb, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("AMR 3D")
|
||||
{
|
||||
int order = 2;
|
||||
test_assembly_level(Mesh("../../data/fichera-amr.mesh", 1, 1),
|
||||
order, false, 0, assembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // test case
|
||||
|
||||
@@ -59,6 +59,74 @@ double linearFunction(const Vector & x)
|
||||
}
|
||||
}
|
||||
|
||||
void asymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(1,0) = cos(1.3 * M_PI * x[1]); // 2,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f(1,0) = cos(M_PI * x[0]); // 2,1
|
||||
f(1,1) = 1.1 + sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f(2,0) = sin(1.5 * M_PI * x[1]); // 3,1
|
||||
f(2,1) = cos(2.9 * M_PI * x[0]); // 3,2
|
||||
f(2,2) = 1.1 + sin(6.1 * M_PI * x[2]); // 3,3
|
||||
}
|
||||
}
|
||||
|
||||
void fullSymmetricMatrixCoeffFunction(const Vector & x, DenseMatrix & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f(0,0) = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(1,1) = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
f(1,0) = f(0,1);
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f(0,0) = sin(M_PI * x[1]); // 1,1
|
||||
f(0,1) = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f(0,2) = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f(1,1) = sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f(1,2) = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f(2,2) = sin(6.1 * M_PI * x[2]); // 3,3
|
||||
f(1,0) = f(0,1);
|
||||
f(2,0) = f(0,2);
|
||||
f(2,1) = f(1,2);
|
||||
}
|
||||
}
|
||||
|
||||
void symmetricMatrixCoeffFunction(const Vector & x, Vector & f)
|
||||
{
|
||||
f = 0.0;
|
||||
if (dimension == 2)
|
||||
{
|
||||
f[0] = 1.1 + sin(M_PI * x[1]); // 1,1
|
||||
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f[2] = 1.1 + sin(4.9 * M_PI * x[0]); // 2,2
|
||||
}
|
||||
else if (dimension == 3)
|
||||
{
|
||||
f[0] = sin(M_PI * x[1]); // 1,1
|
||||
f[1] = cos(2.5 * M_PI * x[0]); // 1,2
|
||||
f[2] = sin(4.9 * M_PI * x[2]); // 1,3
|
||||
f[3] = sin(6.1 * M_PI * x[1]); // 2,2
|
||||
f[4] = cos(6.1 * M_PI * x[2]); // 2,3
|
||||
f[5] = sin(6.1 * M_PI * x[2]); // 3,3
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("H1 pa_coeff")
|
||||
{
|
||||
for (dimension = 2; dimension < 4; ++dimension)
|
||||
@@ -185,11 +253,13 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
|
||||
mesh = new Mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
for (int coeffType = 0; coeffType < 3; ++coeffType)
|
||||
for (int coeffType = 0; coeffType < 5; ++coeffType)
|
||||
{
|
||||
Coefficient* coeff = nullptr;
|
||||
Coefficient* coeff2 = nullptr;
|
||||
VectorCoefficient* vcoeff = nullptr;
|
||||
MatrixCoefficient* mcoeff = nullptr;
|
||||
MatrixCoefficient* smcoeff = nullptr;
|
||||
if (coeffType == 0)
|
||||
{
|
||||
coeff = new ConstantCoefficient(12.34);
|
||||
@@ -205,33 +275,73 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
|
||||
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
|
||||
coeff2 = new FunctionCoefficient(&linearFunction);
|
||||
}
|
||||
|
||||
for (int spaceType = 0; spaceType < 2; ++spaceType)
|
||||
else if (coeffType == 3)
|
||||
{
|
||||
if (spaceType == 1 && coeffType == 2)
|
||||
mcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&fullSymmetricMatrixCoeffFunction);
|
||||
smcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&symmetricMatrixCoeffFunction);
|
||||
coeff2 = new FunctionCoefficient(&linearFunction);
|
||||
}
|
||||
else if (coeffType == 4)
|
||||
{
|
||||
mcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&asymmetricMatrixCoeffFunction);
|
||||
smcoeff = new MatrixFunctionCoefficient(dimension,
|
||||
&asymmetricMatrixCoeffFunction);
|
||||
coeff2 = new FunctionCoefficient(&linearFunction);
|
||||
}
|
||||
|
||||
enum MixedSpaces {Hcurl, Hdiv, HcurlHdiv, HdivHcurl, NumSpaceTypes};
|
||||
|
||||
for (int spaceType = 0; spaceType < NumSpaceTypes; ++spaceType)
|
||||
{
|
||||
if (spaceType == Hdiv && coeffType >= 2)
|
||||
{
|
||||
continue; // Case not implemented yet
|
||||
}
|
||||
|
||||
const int numIntegrators = (coeffType == 2) ? 2 : 3;
|
||||
const int numIntegrators =
|
||||
(spaceType >= HcurlHdiv) ? 1 : ((coeffType == 2) ? 2 : 3);
|
||||
|
||||
for (int integrator = 0; integrator < numIntegrators; ++integrator)
|
||||
{
|
||||
if (spaceType == 0)
|
||||
if (spaceType == Hcurl)
|
||||
std::cout << "Testing " << dimension
|
||||
<< "D ND partial assembly with " << "coeffType "
|
||||
<< coeffType << " and " << "integrator "
|
||||
<< "D ND partial assembly with coeffType "
|
||||
<< coeffType << " and integrator "
|
||||
<< integrator << std::endl;
|
||||
else
|
||||
else if (spaceType == Hdiv)
|
||||
std::cout << "Testing " << dimension
|
||||
<< "D RT partial assembly with " << "coeffType "
|
||||
<< coeffType << " and " << "integrator "
|
||||
<< "D RT partial assembly with coeffType "
|
||||
<< coeffType << " and integrator "
|
||||
<< integrator << std::endl;
|
||||
else if (spaceType == HcurlHdiv)
|
||||
std::cout << "Testing " << dimension
|
||||
<< "D ND x RT partial assembly with coeffType "
|
||||
<< coeffType << " and integrator "
|
||||
<< integrator << std::endl;
|
||||
else // HdivHcurl
|
||||
std::cout << "Testing " << dimension
|
||||
<< "D RT x ND partial assembly with coeffType "
|
||||
<< coeffType << " and integrator "
|
||||
<< integrator << std::endl;
|
||||
|
||||
for (int order = 1; order < 4; ++order)
|
||||
{
|
||||
FiniteElementCollection* fec = (spaceType == 0) ?
|
||||
(FiniteElementCollection*) new ND_FECollection(order, dimension) :
|
||||
(FiniteElementCollection*) new RT_FECollection(order, dimension);
|
||||
FiniteElementCollection* fec = nullptr;
|
||||
if (spaceType == Hcurl || spaceType == HcurlHdiv)
|
||||
{
|
||||
fec = (FiniteElementCollection*) new ND_FECollection(order, dimension);
|
||||
}
|
||||
else if (spaceType == HdivHcurl)
|
||||
{
|
||||
fec = (FiniteElementCollection*) new RT_FECollection(order - 1, dimension);
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = (FiniteElementCollection*) new RT_FECollection(order, dimension);
|
||||
}
|
||||
|
||||
FiniteElementSpace fespace(mesh, fec);
|
||||
|
||||
@@ -270,59 +380,127 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
|
||||
}
|
||||
}
|
||||
|
||||
BilinearForm paform(&fespace);
|
||||
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
BilinearForm assemblyform(&fespace);
|
||||
if (integrator < 2)
|
||||
Vector xin(fespace.GetTrueVSize());
|
||||
xin.Randomize();
|
||||
|
||||
Vector y_mat, y_assembly, y_pa;
|
||||
|
||||
if (spaceType >= HcurlHdiv)
|
||||
{
|
||||
if (coeffType == 2)
|
||||
FiniteElementCollection* fecTest = nullptr;
|
||||
if (spaceType == HcurlHdiv)
|
||||
{
|
||||
fecTest = (FiniteElementCollection*) new RT_FECollection(order - 1, dimension);
|
||||
}
|
||||
else
|
||||
{
|
||||
fecTest = (FiniteElementCollection*) new ND_FECollection(order, dimension);
|
||||
}
|
||||
|
||||
FiniteElementSpace fespaceTest(mesh, fecTest);
|
||||
|
||||
MixedBilinearForm paform(&fespace, &fespaceTest);
|
||||
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
MixedBilinearForm assemblyform(&fespace, &fespaceTest);
|
||||
|
||||
const int testSize = fespaceTest.GetTrueVSize();
|
||||
y_mat.SetSize(testSize);
|
||||
y_mat = 0.0;
|
||||
y_assembly.SetSize(testSize);
|
||||
y_assembly = 0.0;
|
||||
y_pa.SetSize(testSize);
|
||||
y_pa = 0.0;
|
||||
|
||||
if (coeffType >= 3)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
|
||||
}
|
||||
else if (coeffType == 2)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
assemblyform.AddDomainIntegrator(
|
||||
new VectorFEMassIntegrator(*vcoeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
assemblyform.AddDomainIntegrator(
|
||||
new VectorFEMassIntegrator(*coeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
}
|
||||
|
||||
Array<int> empty_ess; // empty
|
||||
|
||||
paform.Assemble();
|
||||
OperatorHandle paopr;
|
||||
paform.FormRectangularSystemMatrix(ess_tdof_list, empty_ess, paopr);
|
||||
|
||||
assemblyform.Assemble();
|
||||
SparseMatrix A_explicit;
|
||||
assemblyform.FormRectangularSystemMatrix(ess_tdof_list, empty_ess, A_explicit);
|
||||
|
||||
paopr->Mult(xin, y_pa);
|
||||
assemblyform.Mult(xin, y_assembly);
|
||||
A_explicit.Mult(xin, y_mat);
|
||||
|
||||
delete fecTest;
|
||||
}
|
||||
if (integrator > 0)
|
||||
else
|
||||
{
|
||||
if (spaceType == 0)
|
||||
BilinearForm paform(&fespace);
|
||||
paform.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
BilinearForm assemblyform(&fespace);
|
||||
|
||||
y_mat.SetSize(xin.Size());
|
||||
y_mat = 0.0;
|
||||
y_assembly.SetSize(xin.Size());
|
||||
y_assembly = 0.0;
|
||||
y_pa.SetSize(xin.Size());
|
||||
y_pa = 0.0;
|
||||
|
||||
if (integrator < 2)
|
||||
{
|
||||
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
|
||||
assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
|
||||
if (coeffType >= 3)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*smcoeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*mcoeff));
|
||||
}
|
||||
else if (coeffType == 2)
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*vcoeff));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
assemblyform.AddDomainIntegrator(new VectorFEMassIntegrator(*coeff));
|
||||
}
|
||||
}
|
||||
else
|
||||
if (integrator > 0)
|
||||
{
|
||||
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
|
||||
assemblyform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
|
||||
if (spaceType == Hcurl)
|
||||
{
|
||||
paform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
|
||||
assemblyform.AddDomainIntegrator(new CurlCurlIntegrator(*coeff2));
|
||||
}
|
||||
else
|
||||
{
|
||||
paform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
|
||||
assemblyform.AddDomainIntegrator(new DivDivIntegrator(*coeff2));
|
||||
}
|
||||
}
|
||||
paform.Assemble();
|
||||
OperatorHandle paopr;
|
||||
paform.FormSystemMatrix(ess_tdof_list, paopr);
|
||||
|
||||
assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
|
||||
assemblyform.Assemble();
|
||||
SparseMatrix A_explicit;
|
||||
assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);
|
||||
|
||||
paopr->Mult(xin, y_pa);
|
||||
assemblyform.Mult(xin, y_assembly);
|
||||
A_explicit.Mult(xin, y_mat);
|
||||
}
|
||||
paform.Assemble();
|
||||
OperatorHandle paopr;
|
||||
paform.FormSystemMatrix(ess_tdof_list, paopr);
|
||||
|
||||
assemblyform.SetDiagonalPolicy(Matrix::DIAG_ONE);
|
||||
assemblyform.Assemble();
|
||||
assemblyform.Finalize();
|
||||
SparseMatrix A_explicit;
|
||||
assemblyform.FormSystemMatrix(ess_tdof_list, A_explicit);
|
||||
|
||||
Vector xin(fespace.GetTrueVSize());
|
||||
xin.Randomize();
|
||||
Vector y_mat(xin);
|
||||
y_mat = 0.0;
|
||||
Vector y_assembly(xin);
|
||||
y_assembly = 0.0;
|
||||
Vector y_pa(xin);
|
||||
y_pa = 0.0;
|
||||
|
||||
paopr->Mult(xin, y_pa);
|
||||
assemblyform.Mult(xin, y_assembly);
|
||||
A_explicit.Mult(xin, y_mat);
|
||||
|
||||
y_pa -= y_mat;
|
||||
double pa_error = y_pa.Norml2();
|
||||
@@ -344,6 +522,9 @@ TEST_CASE("Hcurl/Hdiv pa_coeff")
|
||||
|
||||
delete coeff;
|
||||
delete coeff2;
|
||||
delete vcoeff;
|
||||
delete mcoeff;
|
||||
delete smcoeff;
|
||||
}
|
||||
|
||||
delete mesh;
|
||||
@@ -382,9 +563,9 @@ TEST_CASE("Hcurl/Hdiv mixed pa_coeff")
|
||||
vcoeff = new VectorFunctionCoefficient(dimension, &vectorCoeffFunction);
|
||||
}
|
||||
|
||||
enum MixedSpaces {HcurlH1, HcurlL2, HdivL2};
|
||||
enum MixedSpaces {HcurlH1, HcurlL2, HdivL2, NumSpaceTypes};
|
||||
|
||||
for (int spaceType = 0; spaceType < 3; ++spaceType)
|
||||
for (int spaceType = 0; spaceType < NumSpaceTypes; ++spaceType)
|
||||
{
|
||||
if (spaceType == HdivL2 && coeffType == 1)
|
||||
{
|
||||
|
||||
@@ -422,9 +422,9 @@ void test_pa_convection(Mesh &&mesh, int order, bool dg)
|
||||
//Basic unit test for convection
|
||||
TEST_CASE("PA Convection", "[PartialAssembly]")
|
||||
{
|
||||
for (bool dg : {true, false})
|
||||
SECTION("2D")
|
||||
{
|
||||
SECTION("2D")
|
||||
for (bool dg : {true, false})
|
||||
{
|
||||
for (int order : {2, 3, 4})
|
||||
{
|
||||
@@ -433,8 +433,10 @@ TEST_CASE("PA Convection", "[PartialAssembly]")
|
||||
test_pa_convection(Mesh("../../data/star-q3.mesh", 1, 1), order, dg);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("3D")
|
||||
}
|
||||
SECTION("3D")
|
||||
{
|
||||
for (bool dg : {true, false})
|
||||
{
|
||||
int order = 2;
|
||||
test_pa_convection(Mesh("../../data/periodic-cube.mesh", 1, 1), order, dg);
|
||||
@@ -442,9 +444,9 @@ TEST_CASE("PA Convection", "[PartialAssembly]")
|
||||
}
|
||||
}
|
||||
// Test AMR cases (DG not implemented)
|
||||
for (int order : {2, 3, 4})
|
||||
SECTION("AMR 2D")
|
||||
{
|
||||
SECTION("AMR 2D")
|
||||
for (int order : {2, 3, 4})
|
||||
{
|
||||
test_pa_convection(Mesh("../../data/amr-quad.mesh", 1, 1), order, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "mfem.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
constexpr double EPS = 1.e-12;
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
TEST_CASE("HypreParMatrixAbsMult", "[Parallel], [HypreParMatrixAbsMult]")
|
||||
{
|
||||
int rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
int dim = 2;
|
||||
int ne = 4;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
Mesh * mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
FiniteElementCollection *hdiv_coll(new RT_FECollection(order, dim));
|
||||
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
|
||||
ParFiniteElementSpace R_space(pmesh, hdiv_coll);
|
||||
ParFiniteElementSpace W_space(pmesh, l2_coll);
|
||||
|
||||
int n = R_space.GetTrueVSize();
|
||||
int m = W_space.GetTrueVSize();
|
||||
ParMixedBilinearForm a(&R_space, &W_space);
|
||||
a.AddDomainIntegrator(new VectorFEDivergenceIntegrator);
|
||||
a.Assemble();
|
||||
a.Finalize();
|
||||
|
||||
HypreParMatrix *A = a.ParallelAssemble();
|
||||
HypreParMatrix *Aabs = new HypreParMatrix(*A);
|
||||
|
||||
hypre_ParCSRMatrix * AparCSR = *Aabs;
|
||||
|
||||
int nnzd = AparCSR->diag->num_nonzeros;
|
||||
for (int j = 0; j < nnzd; j++)
|
||||
{
|
||||
AparCSR->diag->data[j] = fabs(AparCSR->diag->data[j]);
|
||||
}
|
||||
|
||||
int nnzoffd = AparCSR->offd->num_nonzeros;
|
||||
for (int j = 0; j < nnzoffd; j++)
|
||||
{
|
||||
AparCSR->offd->data[j] = fabs(AparCSR->offd->data[j]);
|
||||
}
|
||||
|
||||
Vector X0(n), X1(n);
|
||||
Vector Y0(m), Y1(m);
|
||||
|
||||
X0.Randomize();
|
||||
Y0.Randomize(1);
|
||||
Y1.Randomize(1);
|
||||
A->AbsMult(3.4,X0,-2.3,Y0);
|
||||
Aabs->Mult(3.4,X0,-2.3,Y1);
|
||||
|
||||
Y1 -=Y0;
|
||||
double error = Y1.Norml2();
|
||||
|
||||
std::cout << "Testing AbsMult: order: " << order
|
||||
<< ", error norm on rank "
|
||||
<< rank << ": " << error << std::endl;
|
||||
|
||||
REQUIRE(error == Approx(EPS));
|
||||
|
||||
MPI_Barrier(MPI_COMM_WORLD);
|
||||
|
||||
Y0.Randomize();
|
||||
X0.Randomize(1);
|
||||
X1.Randomize(1);
|
||||
A->AbsMultTranspose(3.4,Y0,-2.3,X0);
|
||||
Aabs->MultTranspose(3.4,Y0,-2.3,X1);
|
||||
X1 -=X0;
|
||||
|
||||
error = X1.Norml1();
|
||||
std::cout << "Testing AbsMultT: order: " << order
|
||||
<< ", error norm on rank "
|
||||
<< rank << ": " << error << std::endl;
|
||||
|
||||
REQUIRE(error == Approx(EPS));
|
||||
|
||||
delete A;
|
||||
delete Aabs;
|
||||
delete hdiv_coll;
|
||||
delete l2_coll;
|
||||
delete pmesh;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "mfem.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
constexpr double EPS = 1.e-12;
|
||||
|
||||
TEST_CASE("SparseMatrixAbsMult", "[SparseMatrixAbsMult]")
|
||||
{
|
||||
int dim = 2;
|
||||
int ne = 4;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
Mesh * mesh = new Mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
FiniteElementCollection *hdiv_coll(new RT_FECollection(order, dim));
|
||||
FiniteElementCollection *l2_coll(new L2_FECollection(order, dim));
|
||||
FiniteElementSpace R_space(mesh, hdiv_coll);
|
||||
FiniteElementSpace W_space(mesh, l2_coll);
|
||||
|
||||
int n = R_space.GetTrueVSize();
|
||||
int m = W_space.GetTrueVSize();
|
||||
MixedBilinearForm a(&R_space, &W_space);
|
||||
a.AddDomainIntegrator(new VectorFEDivergenceIntegrator);
|
||||
a.Assemble();
|
||||
a.Finalize();
|
||||
|
||||
SparseMatrix &A = a.SpMat();
|
||||
SparseMatrix *Aabs = new SparseMatrix(A);
|
||||
|
||||
int nnz = Aabs->NumNonZeroElems();
|
||||
for (int j = 0; j < nnz; j++)
|
||||
{
|
||||
Aabs->GetData()[j] = fabs(Aabs->GetData()[j]);
|
||||
}
|
||||
|
||||
Vector X0(n), X1(n);
|
||||
Vector Y0(m), Y1(m);
|
||||
|
||||
X0.Randomize();
|
||||
Y0.Randomize(1);
|
||||
Y1.Randomize(1);
|
||||
A.AbsMult(X0,Y0);
|
||||
Aabs->Mult(X0,Y1);
|
||||
|
||||
Y1 -=Y0;
|
||||
double error = Y1.Norml2();
|
||||
|
||||
std::cout << "Testing AbsMult: order: " << order
|
||||
<< ", error norm: "
|
||||
<< error << std::endl;
|
||||
|
||||
REQUIRE(error == Approx(EPS));
|
||||
|
||||
Y0.Randomize();
|
||||
X0.Randomize(1);
|
||||
X1.Randomize(1);
|
||||
A.AbsMultTranspose(Y0,X0);
|
||||
Aabs->MultTranspose(Y0,X1);
|
||||
X1 -=X0;
|
||||
|
||||
error = X1.Norml2();
|
||||
|
||||
std::cout << "Testing AbsMultT: order: " << order
|
||||
<< ", error norm: "
|
||||
<< error << std::endl;
|
||||
|
||||
REQUIRE(error == Approx(EPS));
|
||||
|
||||
delete Aabs;
|
||||
delete hdiv_coll;
|
||||
delete l2_coll;
|
||||
delete mesh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
@@ -0,0 +1,241 @@
|
||||
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include "catch.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
constexpr double EPS = 1.e-12;
|
||||
|
||||
// Test case: Verify that a conforming mesh yields the same norm for the
|
||||
// assembled diagonal with PA when using the standard (conforming)
|
||||
// Mesh vs. the corresponding (non-conforming) NCMesh.
|
||||
// (note: permutations of the values in the diagonal are expected)
|
||||
TEST_CASE("NCMesh PA diagonal", "[NCMesh]")
|
||||
{
|
||||
SECTION("Quad mesh")
|
||||
{
|
||||
int ne = 2;
|
||||
Mesh mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
Mesh nc_mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
nc_mesh.EnsureNCMesh();
|
||||
|
||||
mesh.UniformRefinement();
|
||||
nc_mesh.UniformRefinement();
|
||||
|
||||
int dim = 2;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
ND_FECollection fec(order, dim);
|
||||
|
||||
FiniteElementSpace fes(&mesh, &fec);
|
||||
FiniteElementSpace nc_fes(&nc_mesh, &fec);
|
||||
|
||||
BilinearForm a(&fes);
|
||||
BilinearForm nc_a(&nc_fes);
|
||||
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
|
||||
ConstantCoefficient coef(1.0);
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
|
||||
a.Assemble();
|
||||
nc_a.Assemble();
|
||||
|
||||
Vector diag(fes.GetTrueVSize());
|
||||
Vector nc_diag(nc_fes.GetTrueVSize());
|
||||
a.AssembleDiagonal(diag);
|
||||
nc_a.AssembleDiagonal(nc_diag);
|
||||
|
||||
double error = fabs(diag.Norml2() - nc_diag.Norml2());
|
||||
std::cout << "Testing quad NCMesh PA diag: "
|
||||
"order: " << order << ", error: " << error << std::endl;
|
||||
REQUIRE(error == Approx(EPS));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Hexa mesh")
|
||||
{
|
||||
int ne = 2;
|
||||
Mesh mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
Mesh nc_mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
nc_mesh.EnsureNCMesh();
|
||||
|
||||
mesh.UniformRefinement();
|
||||
nc_mesh.UniformRefinement();
|
||||
|
||||
int dim = 3;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
ND_FECollection fec(order, dim);
|
||||
|
||||
FiniteElementSpace fes(&mesh, &fec);
|
||||
FiniteElementSpace nc_fes(&nc_mesh, &fec);
|
||||
|
||||
BilinearForm a(&fes);
|
||||
BilinearForm nc_a(&nc_fes);
|
||||
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
|
||||
ConstantCoefficient coef(1.0);
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
|
||||
a.Assemble();
|
||||
nc_a.Assemble();
|
||||
|
||||
Vector diag(fes.GetTrueVSize());
|
||||
Vector nc_diag(nc_fes.GetTrueVSize());
|
||||
a.AssembleDiagonal(diag);
|
||||
nc_a.AssembleDiagonal(nc_diag);
|
||||
|
||||
double error = fabs(diag.Sum() - nc_diag.Sum());
|
||||
std::cout << "Testing hexa NCMesh PA diag: "
|
||||
"order: " << order << ", error: " << error << std::endl;
|
||||
REQUIRE(error == Approx(EPS));
|
||||
}
|
||||
}
|
||||
|
||||
} // test case
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
|
||||
// Test case: Verify that a conforming mesh yields the same norm for the
|
||||
// assembled diagonal with PA when using the standard (conforming)
|
||||
// Mesh vs. the corresponding (non-conforming) NCMesh.
|
||||
// (note: permutations of the values in the diagonal are expected)
|
||||
TEST_CASE("pNCMesh PA diagonal", "[Parallel], [NCMesh]")
|
||||
{
|
||||
int rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
|
||||
SECTION("Quad pmesh")
|
||||
{
|
||||
int ne = 2;
|
||||
Mesh mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
Mesh nc_mesh(ne, ne, Element::QUADRILATERAL, 1, 1.0, 1.0);
|
||||
nc_mesh.EnsureNCMesh();
|
||||
|
||||
mesh.UniformRefinement();
|
||||
nc_mesh.UniformRefinement();
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
ParMesh nc_pmesh(MPI_COMM_WORLD, nc_mesh);
|
||||
|
||||
int dim = 2;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
ND_FECollection fec(order, dim);
|
||||
|
||||
ParFiniteElementSpace pfes(&pmesh, &fec);
|
||||
ParFiniteElementSpace nc_pfes(&nc_pmesh, &fec);
|
||||
|
||||
ParBilinearForm a(&pfes);
|
||||
ParBilinearForm nc_a(&nc_pfes);
|
||||
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
|
||||
ConstantCoefficient coef(1.0);
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
|
||||
a.Assemble();
|
||||
nc_a.Assemble();
|
||||
|
||||
Vector diag(pfes.GetTrueVSize());
|
||||
Vector nc_diag(nc_pfes.GetTrueVSize());
|
||||
a.AssembleDiagonal(diag);
|
||||
nc_a.AssembleDiagonal(nc_diag);
|
||||
|
||||
double diag_lsum = diag.Sum(), nc_diag_lsum = nc_diag.Sum();
|
||||
double diag_gsum = 0.0, nc_diag_gsum = 0.0;
|
||||
MPI_Allreduce(&diag_lsum, &diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
MPI_Allreduce(&nc_diag_lsum, &nc_diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
double error = fabs(diag_gsum - nc_diag_gsum);
|
||||
if (rank==0)
|
||||
{
|
||||
std::cout << "Testing quad pNCMesh PA diag: "
|
||||
"order: " << order << ", error: " << error << std::endl;
|
||||
}
|
||||
REQUIRE(error == Approx(EPS));
|
||||
MPI_Barrier(MPI_COMM_WORLD);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Hexa pmesh")
|
||||
{
|
||||
int ne = 2;
|
||||
Mesh mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
Mesh nc_mesh(ne, ne, ne, Element::HEXAHEDRON, 1, 1.0, 1.0, 1.0);
|
||||
nc_mesh.EnsureNCMesh();
|
||||
|
||||
mesh.UniformRefinement();
|
||||
nc_mesh.UniformRefinement();
|
||||
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
ParMesh nc_pmesh(MPI_COMM_WORLD, nc_mesh);
|
||||
|
||||
int dim = 3;
|
||||
for (int order = 1; order <= 3; ++order)
|
||||
{
|
||||
ND_FECollection fec(order, dim);
|
||||
|
||||
ParFiniteElementSpace pfes(&pmesh, &fec);
|
||||
ParFiniteElementSpace nc_pfes(&nc_pmesh, &fec);
|
||||
|
||||
ParBilinearForm a(&pfes);
|
||||
ParBilinearForm nc_a(&nc_pfes);
|
||||
|
||||
a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
nc_a.SetAssemblyLevel(AssemblyLevel::PARTIAL);
|
||||
|
||||
ConstantCoefficient coef(1.0);
|
||||
a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
nc_a.AddDomainIntegrator(new CurlCurlIntegrator(coef));
|
||||
|
||||
a.Assemble();
|
||||
nc_a.Assemble();
|
||||
|
||||
Vector diag(pfes.GetTrueVSize());
|
||||
Vector nc_diag(nc_pfes.GetTrueVSize());
|
||||
a.AssembleDiagonal(diag);
|
||||
nc_a.AssembleDiagonal(nc_diag);
|
||||
|
||||
double diag_lsum = diag.Sum(), nc_diag_lsum = nc_diag.Sum();
|
||||
double diag_gsum = 0.0, nc_diag_gsum = 0.0;
|
||||
MPI_Allreduce(&diag_lsum, &diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
MPI_Allreduce(&nc_diag_lsum, &nc_diag_gsum, 1, MPI_DOUBLE, MPI_SUM,
|
||||
MPI_COMM_WORLD);
|
||||
double error = fabs(diag_gsum - nc_diag_gsum);
|
||||
if (rank==0)
|
||||
{
|
||||
std::cout << "Testing hexa pNCMesh PA diag: "
|
||||
"order: " << order << ", error: " << error << std::endl;
|
||||
}
|
||||
REQUIRE(error == Approx(EPS));
|
||||
MPI_Barrier(MPI_COMM_WORLD);
|
||||
}
|
||||
}
|
||||
|
||||
} // test case
|
||||
|
||||
#endif // MFEM_USE_MPI
|
||||
|
||||
} // namespace mfem
|
||||
Reference in New Issue
Block a user