Compare commits
268
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e8625cf89 | ||
|
|
3f7a432e74 | ||
|
|
a57fd02a4c | ||
|
|
2ae97ff2da | ||
|
|
2b712207c6 | ||
|
|
62e95fe7bc | ||
|
|
c62681aaf8 | ||
|
|
a25138e611 | ||
|
|
cc3a4475d2 | ||
|
|
8e00ae03e4 | ||
|
|
2930c1477f | ||
|
|
bf3423dcba | ||
|
|
dd23ccddb3 | ||
|
|
3c5dc275a4 | ||
|
|
6604ba702c | ||
|
|
b8ab8fce47 | ||
|
|
35054e78b6 | ||
|
|
646728dfac | ||
|
|
864eeea4a3 | ||
|
|
b89f29c4b5 | ||
|
|
6ba8d18e38 | ||
|
|
efd5b9f019 | ||
|
|
395e75f69a | ||
|
|
1875c34055 | ||
|
|
ae0c65082c | ||
|
|
f58decb421 | ||
|
|
635ac55e77 | ||
|
|
6beb0decd7 | ||
|
|
253aebb734 | ||
|
|
357e2cdb51 | ||
|
|
84661e6385 | ||
|
|
f795b0d728 | ||
|
|
c9d97af717 | ||
|
|
dc4715e03d | ||
|
|
1435d64dfb | ||
|
|
8461df3d67 | ||
|
|
7de36b40bb | ||
|
|
662b04ea8d | ||
|
|
ca5a4dff6f | ||
|
|
cfcf05b6f9 | ||
|
|
345f87f42e | ||
|
|
ae3bdebcac | ||
|
|
bf54fc6b3f | ||
|
|
fb3b943cf0 | ||
|
|
51a7703b48 | ||
|
|
a4f5921ae3 | ||
|
|
02d0bfe9c1 | ||
|
|
43d20869d2 | ||
|
|
fbcd11dfef | ||
|
|
0f86486c74 | ||
|
|
d00d9008e8 | ||
|
|
762a258cf1 | ||
|
|
657c64ac24 | ||
|
|
0be90bbb26 | ||
|
|
e89fb16c42 | ||
|
|
1e1cb2d842 | ||
|
|
56de3cc0b2 | ||
|
|
f4eeb1d34e | ||
|
|
4e199fd0b9 | ||
|
|
68908783d8 | ||
|
|
53a8346c95 | ||
|
|
df3d0b51c2 | ||
|
|
fb1de283a7 | ||
|
|
20849249cd | ||
|
|
4c4aeaeec3 | ||
|
|
679a0e6c15 | ||
|
|
0a1e62b127 | ||
|
|
42207dbfed | ||
|
|
6f9e370523 | ||
|
|
2ece39550c | ||
|
|
774cc3bd68 | ||
|
|
bd14c65b69 | ||
|
|
47ae39dbf1 | ||
|
|
582d49116f | ||
|
|
9258314ac6 | ||
|
|
58a459ab66 | ||
|
|
ad0420e812 | ||
|
|
cadb9778a4 | ||
|
|
3c45d38250 | ||
|
|
944dd26aa7 | ||
|
|
4f41f6bc4c | ||
|
|
10dde95578 | ||
|
|
71377db232 | ||
|
|
da01fc0ed1 | ||
|
|
32bdcb6ef2 | ||
|
|
e74d501ac3 | ||
|
|
fcd2f0ceb2 | ||
|
|
c0879aaf76 | ||
|
|
24e16c5af4 | ||
|
|
41d508dacd | ||
|
|
437cd41773 | ||
|
|
ff6e911139 | ||
|
|
101e5d948c | ||
|
|
4571095d12 | ||
|
|
286888a85d | ||
|
|
faa5a79a16 | ||
|
|
46e436b819 | ||
|
|
efa34ab718 | ||
|
|
4035ded04b | ||
|
|
d05afa8974 | ||
|
|
9e300dd159 | ||
|
|
c6d74cda89 | ||
|
|
c072176287 | ||
|
|
7d0ecbba20 | ||
|
|
aae15033bc | ||
|
|
0bbefe4e14 | ||
|
|
c6d5d3923a | ||
|
|
e37c2c7fb1 | ||
|
|
9bd653526e | ||
|
|
89abb3cd8c | ||
|
|
3f9ca7403a | ||
|
|
f75aa06cd1 | ||
|
|
271e8ad822 | ||
|
|
872e044a69 | ||
|
|
93d9683931 | ||
|
|
e88a811861 | ||
|
|
dc31c57359 | ||
|
|
db9c3c9142 | ||
|
|
7d4a7b2680 | ||
|
|
1fc6280e9f | ||
|
|
89648f1c00 | ||
|
|
e024ac0f9c | ||
|
|
9c5542a0de | ||
|
|
e73631f698 | ||
|
|
dfddd53892 | ||
|
|
08eb0f5bbb | ||
|
|
e332188212 | ||
|
|
ce47cb4eb4 | ||
|
|
a78aef812c | ||
|
|
afd31c8a7b | ||
|
|
b0350a5999 | ||
|
|
5369835883 | ||
|
|
3c47d47456 | ||
|
|
7a9b2bb98a | ||
|
|
860d2aca1c | ||
|
|
b3ee631aa6 | ||
|
|
daf2fdecec | ||
|
|
d3a0d0a181 | ||
|
|
91916ada56 | ||
|
|
3722c0b1a7 | ||
|
|
6983a71e63 | ||
|
|
79312eeb08 | ||
|
|
1f45834e42 | ||
|
|
4f82fbda71 | ||
|
|
3e70d5da1c | ||
|
|
72e442ba45 | ||
|
|
a556dc8eba | ||
|
|
e10c38c636 | ||
|
|
df62917d0c | ||
|
|
e55e61a32c | ||
|
|
109c53f13c | ||
|
|
3ae7c0ae8a | ||
|
|
f330d4cb9e | ||
|
|
32c8c20f23 | ||
|
|
328dc13ba4 | ||
|
|
66939bdf8c | ||
|
|
7aafd3c47f | ||
|
|
699d612513 | ||
|
|
1bf3e188fc | ||
|
|
6dffbbfa0b | ||
|
|
239030b50a | ||
|
|
07853b9c62 | ||
|
|
20089dd62b | ||
|
|
a8ebdf16bd | ||
|
|
99372de933 | ||
|
|
70d84e441d | ||
|
|
f6bc0f8988 | ||
|
|
ef54519a29 | ||
|
|
2852999324 | ||
|
|
523db914fc | ||
|
|
bb08084379 | ||
|
|
f64ad892d3 | ||
|
|
f77273f92a | ||
|
|
2cc07be4aa | ||
|
|
ab68fd9a78 | ||
|
|
d61ba83611 | ||
|
|
53006001ce | ||
|
|
00d182618f | ||
|
|
e1fc7d94b7 | ||
|
|
1fbad9f62d | ||
|
|
2856c64994 | ||
|
|
aa80429c54 | ||
|
|
6ec8be76f1 | ||
|
|
49a31c0cf7 | ||
|
|
ba9b251007 | ||
|
|
90a6df62c2 | ||
|
|
5ce2fa9ab9 | ||
|
|
29f9e6cb90 | ||
|
|
ea1685e4cc | ||
|
|
59e4409ea5 | ||
|
|
78c93de6ce | ||
|
|
8dda4f7441 | ||
|
|
ecfb8c755d | ||
|
|
1000f0118c | ||
|
|
b6aa995326 | ||
|
|
0d4b1cb9ff | ||
|
|
4f430f0ee4 | ||
|
|
3d4aa157cb | ||
|
|
908f689ea5 | ||
|
|
b8b5a21a7c | ||
|
|
c1f7f42dcc | ||
|
|
5925b7dfa8 | ||
|
|
e97a27d331 | ||
|
|
a5ef20ee9a | ||
|
|
e95687faaa | ||
|
|
bd424d6a89 | ||
|
|
f10f165b71 | ||
|
|
add2e8a3f2 | ||
|
|
0119774c0f | ||
|
|
84650f8381 | ||
|
|
4114098c86 | ||
|
|
a8abcac938 | ||
|
|
05dd41530a | ||
|
|
da31bce595 | ||
|
|
8eff49047c | ||
|
|
7e10b0a7ee | ||
|
|
52ccf07bdb | ||
|
|
a9496f3c58 | ||
|
|
c2a80e493c | ||
|
|
f8dd9bd06c | ||
|
|
3c404a6b27 | ||
|
|
e6ebf97a21 | ||
|
|
9b0641f472 | ||
|
|
2dcae3ac05 | ||
|
|
e262fcf988 | ||
|
|
8e9edf7c66 | ||
|
|
c8b773712d | ||
|
|
c88f75bbfc | ||
|
|
d302141496 | ||
|
|
f8a9c558ff | ||
|
|
af0fce3d73 | ||
|
|
1759ccb2f1 | ||
|
|
7a49e839db | ||
|
|
07f9bece01 | ||
|
|
17d7a117c1 | ||
|
|
bb2f464ca6 | ||
|
|
40d9185c8b | ||
|
|
e089d8a4af | ||
|
|
0001d33b5b | ||
|
|
cea889054e | ||
|
|
b0d657e631 | ||
|
|
f62a6eee75 | ||
|
|
9e0569c53a | ||
|
|
ea59ab0ce9 | ||
|
|
224895adc2 | ||
|
|
c3be660074 | ||
|
|
ce4d12c8cb | ||
|
|
a7f1c177c5 | ||
|
|
b32955bba7 | ||
|
|
80d1533590 | ||
|
|
2d4e3cf77e | ||
|
|
a7c2e91915 | ||
|
|
e673b80a9f | ||
|
|
8cd4c0049f | ||
|
|
54d57691de | ||
|
|
e24b839f22 | ||
|
|
3e8acd547c | ||
|
|
a953f6ee2a | ||
|
|
eef8f6ce8e | ||
|
|
eb216b91e3 | ||
|
|
35d6b0a442 | ||
|
|
f04242da6e | ||
|
|
eb9abd9cf6 | ||
|
|
b57c90e4bb | ||
|
|
2e3d917e0c | ||
|
|
9c6efb61b2 | ||
|
|
c388a9dd7b | ||
|
|
9c838adca6 |
@@ -29,6 +29,8 @@ config/sample-runs-build.log
|
||||
doc/CodeDocumentation.conf
|
||||
doc/CodeDocumentation.html
|
||||
doc/CodeDocumentation
|
||||
doc/undoc.log
|
||||
doc/warnings.log
|
||||
|
||||
# Temporary files created by the tests.
|
||||
*.stderr
|
||||
@@ -167,6 +169,7 @@ miniapps/meshing/twist
|
||||
miniapps/meshing/mesh-explorer
|
||||
miniapps/meshing/shaper
|
||||
miniapps/meshing/extruder
|
||||
miniapps/meshing/trimmer
|
||||
miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/minimal-surface
|
||||
@@ -180,6 +183,7 @@ miniapps/meshing/mesh-explorer.mesh
|
||||
miniapps/meshing/partitioning.txt
|
||||
miniapps/meshing/shaper.mesh
|
||||
miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
|
||||
|
||||
@@ -24,8 +24,14 @@ Meshing improvements
|
||||
and orientation based metrics.
|
||||
|
||||
- Added support for r-adaptivity with more than one discrete field. This allows
|
||||
the user to specify different discrete functions for controlling the
|
||||
size, aspect-ratio, orientation, and skew of elements in the mesh.
|
||||
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.
|
||||
|
||||
Performance improvements
|
||||
------------------------
|
||||
@@ -38,6 +44,8 @@ Performance improvements
|
||||
These are now enabled by default, and can be disabled with MFEM_USE_SIMD=NO.
|
||||
See the new file linalg/simd.hpp and the new directory linalg/simd.
|
||||
|
||||
Improved GPU capabilities
|
||||
-------------------------
|
||||
- Added support for Chebyshev accelerated polynomial smoother on GPU.
|
||||
|
||||
Discretization improvements
|
||||
@@ -66,6 +74,8 @@ Discretization improvements
|
||||
Additionaly, new LinearForm integrators were also added which make use of
|
||||
these new QuadratureFunction coefficient classes.
|
||||
|
||||
- Added support face integrals on the boundaries of NURBS meshes.
|
||||
|
||||
Linear and nonlinear solvers
|
||||
----------------------------
|
||||
- Added power method to iteratively estimate the largest eigenvalue and the
|
||||
@@ -94,11 +104,10 @@ New and updated examples and miniapps
|
||||
- Added a new Example 26/26p to demonstrate the construction of a matrix-free
|
||||
geometric and p-multigrid preconditioner for the Laplace problem.
|
||||
|
||||
- Added a new example, Example 27/27p, to demonstrate the enforcement of
|
||||
various boundary conditions with the Laplace operator. The example shows the
|
||||
procedures for applying Dirichlet, Neumann (both homogeneous and
|
||||
inhomogeneous), Robin, and periodic boundary conditions with either H1 or DG
|
||||
discretizations.
|
||||
- Added a new example, Example 27/27p, to demonstrate the enforcement of various
|
||||
boundary conditions with the Laplace operator. The example shows the procedure
|
||||
for applying Dirichlet, Neumann (both homogeneous and inhomogeneous), Robin,
|
||||
and periodic boundary conditions with either H1 or DG discretizations.
|
||||
|
||||
- Added a simple meshing miniapp, Twist, which demonstrates MFEM's strategy of
|
||||
stitching together opposite surfaces of a mesh to create a topologically
|
||||
@@ -113,6 +122,12 @@ New and updated examples and miniapps
|
||||
- Added a new test problem in example 24/24p, demonstrating a mixed bilinear
|
||||
form for H(div) and L_2, with partial assembly support.
|
||||
|
||||
- Added weak Dirichlet boundary conditions (Nitsche) to the NURBS miniapp.
|
||||
|
||||
- Added a simple mesh editing miniapp, Trimmer, which trims away portions of a
|
||||
mesh based on element attributes. Any newly exposed boundary elements are
|
||||
assigned attribute numbers related to the trimmed element attributes.
|
||||
|
||||
Improved testing
|
||||
----------------
|
||||
- Added a GitLab pipeline that automates PR testing on supercomputing systems
|
||||
|
||||
+17
-2
@@ -125,6 +125,7 @@ MFEM_USE_GINKGO = NO
|
||||
MFEM_USE_GNUTLS = NO
|
||||
MFEM_USE_NETCDF = NO
|
||||
MFEM_USE_PETSC = NO
|
||||
MFEM_USE_SLEPC = NO
|
||||
MFEM_USE_MPFR = NO
|
||||
MFEM_USE_SIDRE = NO
|
||||
MFEM_USE_CONDUIT = NO
|
||||
@@ -276,6 +277,20 @@ ifeq ($(PETSC_FOUND),YES)
|
||||
-L$(abspath $(PETSC_DIR))/lib -lpetsc $(PETSC_LIB)
|
||||
endif
|
||||
|
||||
SLEPC_DIR := $(MFEM_DIR)/../slepc
|
||||
SLEPC_VARS := $(SLEPC_DIR)/lib/slepc/conf/slepc_variables
|
||||
SLEPC_FOUND := $(if $(wildcard $(SLEPC_VARS)),YES,)
|
||||
SLEPC_INC_VAR = SLEPC_INCLUDE
|
||||
SLEPC_LIB_VAR = SLEPC_EXTERNAL_LIB
|
||||
ifeq ($(SLEPC_FOUND),YES)
|
||||
SLEPC_OPT := $(shell sed -n "s/$(SLEPC_INC_VAR) *= *//p" $(SLEPC_VARS))
|
||||
# Some additional external libraries might be defined in this file
|
||||
-include ${SLEPC_DIR}/${PETSC_ARCH}/lib/slepc/conf/slepcvariables
|
||||
SLEPC_LIB := $(shell sed -n "s/$(SLEPC_LIB_VAR) *= *//p" $(SLEPC_VARS))
|
||||
SLEPC_LIB := -Wl,-rpath,$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib\
|
||||
-L$(abspath $(SLEPC_DIR))/$(PETSC_ARCH)/lib -lslepc $(SLEPC_LIB)
|
||||
endif
|
||||
|
||||
# MPFR library configuration
|
||||
MPFR_OPT =
|
||||
MPFR_LIB = -lmpfr
|
||||
@@ -324,9 +339,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 =
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
R1 = 1.0;
|
||||
R2 = 2.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};
|
||||
Line(1) = {2, 3};
|
||||
Line(2) = {4, 5};
|
||||
Circle(3) = {2, 1, 4};
|
||||
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;
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
Periodic Line{1} = {2} Rotate{{0,0,1}, {0,0,0}, -Pi/3};
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Curve(1) = {3};
|
||||
Physical Curve(2) = {4};
|
||||
Physical Curve(3) = {1};
|
||||
Physical Curve(4) = {2};
|
||||
Physical Surface(1) = {1};
|
||||
|
||||
// Generate 2D mesh
|
||||
Mesh 2;
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
|
||||
Save "periodic-annulus-sector.msh";
|
||||
@@ -0,0 +1,185 @@
|
||||
$MeshFormat
|
||||
2.2 0 8
|
||||
$EndMeshFormat
|
||||
$Nodes
|
||||
55
|
||||
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
|
||||
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
|
||||
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
|
||||
$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
|
||||
$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
|
||||
5 10
|
||||
7 12
|
||||
2 4
|
||||
1 3
|
||||
$EndPeriodic
|
||||
@@ -0,0 +1,25 @@
|
||||
SetFactory("OpenCASCADE");
|
||||
|
||||
R = 1.5;
|
||||
r = 0.5;
|
||||
|
||||
Torus(1) = {0,0,0, R, r, Pi/3};
|
||||
|
||||
pts() = PointsOf{ Volume{1}; };
|
||||
|
||||
Characteristic Length{ pts() } = 0.25;
|
||||
|
||||
// Set a rotation periodicity constraint:
|
||||
Periodic Surface{3} = {2} Rotate{{0,0,1}, {0,0,0}, Pi/3};
|
||||
|
||||
// Tag surfaces and volumes with positive integers
|
||||
Physical Surface(1) = {1};
|
||||
Physical Surface(2) = {2};
|
||||
Physical Surface(3) = {3};
|
||||
Physical Volume(1) = {1};
|
||||
|
||||
// Generate 3D mesh
|
||||
Mesh 3;
|
||||
|
||||
Mesh.MshFileVersion = 2.2;
|
||||
Save "periodic-torus-sector.msh";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,155 @@
|
||||
MFEM NURBS mesh v1.0
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
5
|
||||
1 3 0 3 7 4
|
||||
1 3 3 2 6 7
|
||||
1 3 2 1 5 6
|
||||
1 3 1 0 4 5
|
||||
1 3 2 8 9 1
|
||||
|
||||
boundary
|
||||
10
|
||||
1 1 0 3
|
||||
2 1 3 2
|
||||
2 1 1 0
|
||||
2 1 2 8
|
||||
2 1 9 1
|
||||
3 1 7 4
|
||||
3 1 6 7
|
||||
3 1 5 6
|
||||
3 1 4 5
|
||||
4 1 8 9
|
||||
|
||||
edges
|
||||
15
|
||||
0 0 4
|
||||
0 3 7
|
||||
0 1 5
|
||||
0 2 6
|
||||
1 0 3
|
||||
1 4 7
|
||||
2 3 2
|
||||
2 7 6
|
||||
2 1 0
|
||||
2 5 4
|
||||
1 2 1
|
||||
1 6 5
|
||||
1 8 9
|
||||
3 2 8
|
||||
3 1 9
|
||||
|
||||
vertices
|
||||
10
|
||||
|
||||
patches
|
||||
|
||||
knotvectors
|
||||
2
|
||||
2 3 0 0 0 1 1 1
|
||||
2 4 0 0 0 0.5 1 1 1
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
controlpoints_cartesian
|
||||
-5 5 1
|
||||
-5 3.92523e-16 1
|
||||
-5 -5 1
|
||||
-2.47593 2.47593 1
|
||||
-4.95187 6.06429e-16 0.707107
|
||||
-2.47593 -2.47593 1
|
||||
-0.424264 0.424264 1
|
||||
-0.848528 1.03915e-16 0.707107
|
||||
-0.424264 -0.424264 1
|
||||
-0.353553 0.353553 1
|
||||
-0.707107 8.65956e-17 0.707107
|
||||
-0.353553 -0.353553 1
|
||||
|
||||
knotvectors
|
||||
2
|
||||
2 3 0 0 0 1 1 1
|
||||
2 4 0 0 0 0.5 1 1 1
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
controlpoints_cartesian
|
||||
-5 -5 1
|
||||
-1.17757e-15 -5 1
|
||||
5 -5 1
|
||||
-2.47593 -2.47593 1
|
||||
-9.09644e-16 -4.95187 0.707107
|
||||
2.47593 -2.47593 1
|
||||
-0.424264 -0.424264 1
|
||||
-1.55872e-16 -0.848528 0.707107
|
||||
0.424264 -0.424264 1
|
||||
-0.353553 -0.353553 1
|
||||
-1.29893e-16 -0.707107 0.707107
|
||||
0.353553 -0.353553 1
|
||||
|
||||
knotvectors
|
||||
2
|
||||
2 3 0 0 0 1 1 1
|
||||
2 4 0 0 0 0.5 1 1 1
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
controlpoints_cartesian
|
||||
5 -5 1
|
||||
5 -1.17757e-15 1
|
||||
5 5 1
|
||||
2.47593 -2.47593 1
|
||||
4.95187 -1.21286e-15 0.707107
|
||||
2.47593 2.47593 1
|
||||
0.424264 -0.424264 1
|
||||
0.848528 -2.07829e-16 0.707107
|
||||
0.424264 0.424264 1
|
||||
0.353553 -0.353553 1
|
||||
0.707107 -1.73191e-16 0.707107
|
||||
0.353553 0.353553 1
|
||||
|
||||
knotvectors
|
||||
2
|
||||
2 3 0 0 0 1 1 1
|
||||
2 4 0 0 0 0.5 1 1 1
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
controlpoints_cartesian
|
||||
5 5 1
|
||||
3.92523e-16 5 1
|
||||
-5 5 1
|
||||
2.47593 2.47593 1
|
||||
3.03215e-16 4.95187 0.707107
|
||||
-2.47593 2.47593 1
|
||||
0.424264 0.424264 1
|
||||
5.19574e-17 0.848528 0.707107
|
||||
-0.424264 0.424264 1
|
||||
0.353553 0.353553 1
|
||||
4.32978e-17 0.707107 0.707107
|
||||
-0.353553 0.353553 1
|
||||
|
||||
knotvectors
|
||||
2
|
||||
2 3 0 0 0 1 1 1
|
||||
2 3 0 0 0 1 1 1
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
controlpoints_cartesian
|
||||
5 -5 1
|
||||
10 -5 1
|
||||
15 -5 1
|
||||
5 0 1
|
||||
10 0 1
|
||||
15 0 1
|
||||
5 5 1
|
||||
10 5 1
|
||||
15 5 1
|
||||
+14
-29
@@ -16,36 +16,21 @@ if (DOXYGEN_FOUND)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CodeDocumentation.conf.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf @ONLY)
|
||||
|
||||
if (UNIX)
|
||||
# Only create symlinks if UNIX operating system
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
|
||||
${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
|
||||
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(clean-doc
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
|
||||
COMMENT "Removing API documentation"
|
||||
VERBATIM)
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
|
||||
COMMAND echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
|
||||
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen to CodeDocumentation.html"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(clean-doc
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.html
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${CMAKE_CURRENT_BINARY_DIR}/warnings.log
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
|
||||
COMMENT "Removing API documentation"
|
||||
VERBATIM)
|
||||
|
||||
else (UNIX)
|
||||
add_custom_target(doc
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation.conf
|
||||
BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation/html/index.html
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Doxygen to CodeDocumentation/html/index.html"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(clean-doc
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/CodeDocumentation
|
||||
COMMENT "Removing API documentation"
|
||||
VERBATIM)
|
||||
endif (UNIX)
|
||||
endif (DOXYGEN_FOUND)
|
||||
|
||||
@@ -51,7 +51,7 @@ PROJECT_BRIEF = "Finite element discretization library"
|
||||
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
|
||||
# the logo to the output directory.
|
||||
|
||||
PROJECT_LOGO =
|
||||
PROJECT_LOGO = web/logo-small.png
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
|
||||
# into which the generated documentation will be written. If a relative path is
|
||||
@@ -746,7 +746,7 @@ WARN_FORMAT = "$file:$line: $text"
|
||||
# messages should be written. If left blank the output is written to standard
|
||||
# error (stderr).
|
||||
|
||||
WARN_LOGFILE =
|
||||
WARN_LOGFILE = warnings.log
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
@@ -1470,7 +1470,7 @@ MATHJAX_FORMAT = HTML-CSS
|
||||
# The default value is: http://cdn.mathjax.org/mathjax/latest.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_RELPATH = https://cdn.llnl.gov/mathjax/2.7.2
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||
# extension names that should be enabled during MathJax rendering. For example
|
||||
|
||||
@@ -149,6 +149,7 @@ namespace mfem {
|
||||
* - <a class="el" href="extruder_8cpp_source.html">Extruder</a>: extrude a low-dimensional mesh into a higher dimension
|
||||
* - <a class="el" href="mesh-explorer_8cpp_source.html">Mesh Explorer</a>: visualize and manipulate meshes
|
||||
* - <a class="el" href="mesh-optimizer_8cpp_source.html">Mesh Optimizer</a>: optimize high-order meshes, <a class="el" href="mesh-optimizer_8cpp_source.html">serial</a> and <a class="el" href="pmesh-optimizer_8cpp_source.html">parallel</a> versions
|
||||
* - <a class="el" href="trimmer_8cpp_source.html">Trimmer</a>: trim elements from existing meshes
|
||||
* - <a class="el" href="display-basis_8cpp_source.html">Display Basis</a>: visualize finite element basis functions
|
||||
* - <a class="el" href="get-values_8cpp_source.html">Get Values</a>: extract field values via DataCollection classes
|
||||
* - <a class="el" href="load-dc_8cpp_source.html">Load DC</a>: visualize fields saved via DataCollection classes
|
||||
|
||||
+11
-4
@@ -9,18 +9,25 @@
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
SHELL = /bin/bash
|
||||
MFEM_DIR ?= ..
|
||||
DOXYGEN_CONF = CodeDocumentation.conf
|
||||
|
||||
|
||||
# doxygen uses: graphviz, latex
|
||||
html: $(DOXYGEN_CONF)
|
||||
doxygen $(DOXYGEN_CONF)
|
||||
rm -f CodeDocumentation.html
|
||||
ln -s CodeDocumentation/html/index.html CodeDocumentation.html
|
||||
@# Generate the html documentation
|
||||
@doxygen $(DOXYGEN_CONF)
|
||||
@echo "<meta http-equiv=\"REFRESH\" content=\"0;URL=CodeDocumentation/html/index.html\">" > CodeDocumentation.html
|
||||
@cat warnings.log
|
||||
@# 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
|
||||
|
||||
clean:
|
||||
rm -rf $(DOXYGEN_CONF) CodeDocumentation CodeDocumentation.html *~
|
||||
rm -rf undoc.log warnings.log
|
||||
|
||||
$(DOXYGEN_CONF): $(MFEM_DIR)/doc/$(DOXYGEN_CONF).in
|
||||
sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
|
||||
@sed -e 's%@MFEM_SOURCE_DIR@%$(MFEM_DIR)%g' $(<) \
|
||||
> $(DOXYGEN_CONF)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -9,6 +9,8 @@
|
||||
// ex1 -m ../data/fichera.mesh
|
||||
// ex1 -m ../data/fichera-mixed.mesh
|
||||
// ex1 -m ../data/toroid-wedge.mesh
|
||||
// ex1 -m ../data/periodic-annulus-sector.msh
|
||||
// ex1 -m ../data/periodic-torus-sector.msh
|
||||
// ex1 -m ../data/square-disc-p2.vtk -o 2
|
||||
// ex1 -m ../data/square-disc-p3.mesh -o 3
|
||||
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
// mpirun -np 4 ex11p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex11p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex11p -m ../data/fichera-mixed.mesh
|
||||
// mpirun -np 4 ex11p -m ../data/periodic-annulus-sector.msh
|
||||
// mpirun -np 4 ex11p -m ../data/periodic-torus-sector.msh -rs 1
|
||||
// mpirun -np 4 ex11p -m ../data/toroid-wedge.mesh -o 2
|
||||
// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2
|
||||
// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
// mpirun -np 4 ex1p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/fichera-mixed.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/toroid-wedge.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/periodic-annulus-sector.msh
|
||||
// mpirun -np 4 ex1p -m ../data/periodic-torus-sector.msh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
|
||||
// mpirun -np 3 ex4p -m ../data/amr-quad.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// mpirun -np 4 ex9p -m ../data/disc-nurbs.mesh -p 2 -rp 1 -dt 0.005 -tf 9
|
||||
// mpirun -np 4 ex9p -m ../data/periodic-square.mesh -p 3 -rp 2 -dt 0.0025 -tf 9 -vs 20
|
||||
// mpirun -np 4 ex9p -m ../data/periodic-cube.mesh -p 0 -o 2 -rp 1 -dt 0.01 -tf 8
|
||||
// mpirun -np 3 ex9p -m ../data/amr-hex.mesh -p 1 -rs 1 -rp 0 -dt 0.005 -tf 0.5
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex9p -pa
|
||||
|
||||
+93
-36
@@ -25,8 +25,8 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Enumeration defining the assembly level for bilinear and nonlinear form
|
||||
/// classes derived from Operator.
|
||||
/** @brief Enumeration defining the assembly level for bilinear and nonlinear
|
||||
form classes derived from Operator. */
|
||||
enum class AssemblyLevel
|
||||
{
|
||||
/// Fully assembled form, i.e. a global sparse matrix in MFEM, Hypre or PETSC
|
||||
@@ -44,15 +44,19 @@ enum class AssemblyLevel
|
||||
};
|
||||
|
||||
|
||||
/** Class for bilinear form - "Matrix" with associated FE space and
|
||||
BLFIntegrators. */
|
||||
/** @brief A "square matrix" operator for the associated FE space and
|
||||
BLFIntegrators The sum of all the BLFIntegrators can be used form the matrix
|
||||
M. This class also supports other assembly levels specified via the
|
||||
SetAssemblyLevel() function. */
|
||||
class BilinearForm : public Matrix
|
||||
{
|
||||
protected:
|
||||
/// Sparse matrix to be associated with the form. Owned.
|
||||
/// Sparse matrix \f$ M \f$ to be associated with the form. Owned.
|
||||
SparseMatrix *mat;
|
||||
|
||||
/// Matrix used to eliminate b.c. Owned.
|
||||
/** @brief Sparse Matrix \f$ M_e \f$ used to store the eliminations
|
||||
from the b.c. Owned.
|
||||
\f$ M + M_e = M_{original} \f$ */
|
||||
SparseMatrix *mat_e;
|
||||
|
||||
/// FE space on which the form lives. Not owned.
|
||||
@@ -62,12 +66,12 @@ protected:
|
||||
AssemblyLevel assembly;
|
||||
/// Element batch size used in the form action (1, 8, num_elems, etc.)
|
||||
int batch;
|
||||
/** Extension for supporting Full Assembly (FA), Element Assembly (EA),
|
||||
/** @brief Extension for supporting Full Assembly (FA), Element Assembly (EA),
|
||||
Partial Assembly (PA), or Matrix Free assembly (MF). */
|
||||
BilinearFormExtension *ext;
|
||||
|
||||
/// Indicates the Mesh::sequence corresponding to the current state of the
|
||||
/// BilinearForm.
|
||||
/** @brief Indicates the Mesh::sequence corresponding to the current state of
|
||||
the BilinearForm. */
|
||||
long sequence;
|
||||
|
||||
/** @brief Indicates the BilinearFormIntegrator%s stored in #dbfi, #bbfi,
|
||||
@@ -147,35 +151,43 @@ public:
|
||||
/// Get the size of the BilinearForm as a square matrix.
|
||||
int Size() const { return height; }
|
||||
|
||||
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
|
||||
/** This method must be called before assembly. */
|
||||
/// Set the desired assembly level.
|
||||
/** Valid choices are:
|
||||
|
||||
- AssemblyLevel::FULL (default)
|
||||
- AssemblyLevel::PARTIAL
|
||||
- AssemblyLevel::ELEMENT
|
||||
- AssemblyLevel::NONE
|
||||
|
||||
This method must be called before assembly. */
|
||||
void SetAssemblyLevel(AssemblyLevel assembly_level);
|
||||
|
||||
/// Returns the assembly level
|
||||
AssemblyLevel GetAssemblyLevel() const { return assembly; }
|
||||
|
||||
/** Enable the use of static condensation. For details see the description
|
||||
for class StaticCondensation in fem/staticcond.hpp This method should be
|
||||
called before assembly. If the number of unknowns after static
|
||||
/** @brief Enable the use of static condensation. For details see the
|
||||
description for class StaticCondensation in fem/staticcond.hpp This method
|
||||
should be called before assembly. If the number of unknowns after static
|
||||
condensation is not reduced, it is not enabled. */
|
||||
void EnableStaticCondensation();
|
||||
|
||||
/** Check if static condensation was actually enabled by a previous call to
|
||||
EnableStaticCondensation(). */
|
||||
/** @brief Check if static condensation was actually enabled by a previous
|
||||
call to EnableStaticCondensation(). */
|
||||
bool StaticCondensationIsEnabled() const { return static_cond; }
|
||||
|
||||
/// Return the trace FE space associated with static condensation.
|
||||
FiniteElementSpace *SCFESpace() const
|
||||
{ return static_cond ? static_cond->GetTraceFESpace() : NULL; }
|
||||
|
||||
/** Enable hybridization; for details see the description for class
|
||||
/// Enable hybridization.
|
||||
/** For details see the description for class
|
||||
Hybridization in fem/hybridization.hpp. This method should be called
|
||||
before assembly. */
|
||||
void EnableHybridization(FiniteElementSpace *constr_space,
|
||||
BilinearFormIntegrator *constr_integ,
|
||||
const Array<int> &ess_tdof_list);
|
||||
|
||||
/** For scalar FE spaces, precompute the sparsity pattern of the matrix
|
||||
/** @brief For scalar FE spaces, precompute the sparsity pattern of the matrix
|
||||
(assuming dense element matrices) based on the types of integrators
|
||||
present in the bilinear form. */
|
||||
void UsePrecomputedSparsity(int ps = 1) { precompute_sparsity = ps; }
|
||||
@@ -194,15 +206,16 @@ public:
|
||||
/// Use the sparsity of @a A to allocate the internal SparseMatrix.
|
||||
void UseSparsity(SparseMatrix &A);
|
||||
|
||||
/** Pre-allocate the internal SparseMatrix before assembly. If the flag
|
||||
'precompute sparsity' is set, the matrix is allocated in CSR format (i.e.
|
||||
/// Pre-allocate the internal SparseMatrix before assembly.
|
||||
/** If the flag 'precompute sparsity'
|
||||
is set, the matrix is allocated in CSR format (i.e.
|
||||
finalized) and the entries are initialized with zeros. */
|
||||
void AllocateMatrix() { if (mat == NULL) { AllocMat(); } }
|
||||
|
||||
/// Access all integrators added with AddDomainIntegrator().
|
||||
/// Access all the integrators added with AddDomainIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetDBFI() { return &dbfi; }
|
||||
|
||||
/// Access all integrators added with AddBoundaryIntegrator().
|
||||
/// Access all the integrators added with AddBoundaryIntegrator().
|
||||
Array<BilinearFormIntegrator*> *GetBBFI() { return &bbfi; }
|
||||
/** @brief Access all boundary markers added with AddBoundaryIntegrator().
|
||||
If no marker was specified when the integrator was added, the
|
||||
@@ -219,64 +232,85 @@ public:
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBFBFI_Marker() { return &bfbfi_marker; }
|
||||
|
||||
/// Returns a reference to: \f$ M_{ij} \f$
|
||||
const double &operator()(int i, int j) { return (*mat)(i,j); }
|
||||
|
||||
/// Returns reference to a_{ij}.
|
||||
/// Returns a reference to: \f$ M_{ij} \f$
|
||||
virtual double &Elem(int i, int j);
|
||||
|
||||
/// Returns constant reference to a_{ij}.
|
||||
/// Returns constant reference to: \f$ M_{ij} \f$
|
||||
virtual const double &Elem(int i, int j) const;
|
||||
|
||||
/// Matrix vector multiplication.
|
||||
/// Matrix vector multiplication: \f$ y = M x \f$
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
|
||||
/** @brief Matrix vector multiplication with the original uneliminated
|
||||
matrix. The original matrix is \f$ M + M_e \f$ so we have:
|
||||
\f$ y = M x + M_e x \f$ */
|
||||
void FullMult(const Vector &x, Vector &y) const
|
||||
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
|
||||
|
||||
/// Add the matrix vector multiple to a vector: \f$ y += a M x \f$
|
||||
virtual void AddMult(const Vector &x, Vector &y, const double a = 1.0) const
|
||||
{ mat -> AddMult (x, y, a); }
|
||||
|
||||
/** @brief Add the original uneliminated matrix vector multiple to a vector.
|
||||
The original matrix is \f$ M + Me \f$ so we have:
|
||||
\f$ y += M x + M_e x \f$ */
|
||||
void FullAddMult(const Vector &x, Vector &y) const
|
||||
{ mat->AddMult(x, y); mat_e->AddMult(x, y); }
|
||||
|
||||
/// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
|
||||
virtual void AddMultTranspose(const Vector & x, Vector & y,
|
||||
const double a = 1.0) const
|
||||
{ mat->AddMultTranspose(x, y, a); }
|
||||
|
||||
/** @brief Add the original uneliminated matrix transpose vector
|
||||
multiple to a vector. The original matrix is \f$ M + M_e \f$
|
||||
so we have: \f$ y += M^T x + {M_e}^T x \f$ */
|
||||
void FullAddMultTranspose(const Vector & x, Vector & y) const
|
||||
{ mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
|
||||
|
||||
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
|
||||
virtual void MultTranspose(const Vector & x, Vector & y) const
|
||||
{ y = 0.0; AddMultTranspose (x, y); }
|
||||
|
||||
/// Compute \f$ y^T M x \f$
|
||||
double InnerProduct(const Vector &x, const Vector &y) const
|
||||
{ return mat->InnerProduct (x, y); }
|
||||
|
||||
/// Returns a pointer to (approximation) of the matrix inverse.
|
||||
/// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$
|
||||
virtual MatrixInverse *Inverse() const;
|
||||
|
||||
/// Finalizes the matrix initialization.
|
||||
virtual void Finalize(int skip_zeros = 1);
|
||||
|
||||
/// Returns a reference to the sparse matrix
|
||||
/// Returns a const reference to the sparse matrix.
|
||||
const SparseMatrix &SpMat() const
|
||||
{
|
||||
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
|
||||
return *mat;
|
||||
}
|
||||
|
||||
/// Returns a reference to the sparse matrix: \f$ M \f$
|
||||
SparseMatrix &SpMat()
|
||||
{
|
||||
MFEM_VERIFY(mat, "mat is NULL and can't be dereferenced");
|
||||
return *mat;
|
||||
}
|
||||
|
||||
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
|
||||
to it. Used for transfering ownership. */
|
||||
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
|
||||
|
||||
/// Returns a reference to the sparse matrix of eliminated b.c.
|
||||
/// Returns a const reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
|
||||
const SparseMatrix &SpMatElim() const
|
||||
{
|
||||
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
|
||||
return *mat_e;
|
||||
}
|
||||
|
||||
/// Returns a reference to the sparse matrix of eliminated b.c.: \f$ M_e \f$
|
||||
SparseMatrix &SpMatElim()
|
||||
{
|
||||
MFEM_VERIFY(mat_e, "mat_e is NULL and can't be dereferenced");
|
||||
@@ -311,6 +345,7 @@ public:
|
||||
void AddBdrFaceIntegrator(BilinearFormIntegrator *bfi,
|
||||
Array<int> &bdr_marker);
|
||||
|
||||
/// Sets all sparse values of \f$ M \f$ and \f$ M_e \f$ to 'a'.
|
||||
void operator=(const double a)
|
||||
{
|
||||
if (mat != NULL) { *mat = a; }
|
||||
@@ -328,10 +363,10 @@ public:
|
||||
for an AMR mesh. */
|
||||
void AssembleDiagonal(Vector &diag) const;
|
||||
|
||||
/// Get the finite element space prolongation matrix
|
||||
/// Get the finite element space prolongation operator.
|
||||
virtual const Operator *GetProlongation() const
|
||||
{ return fes->GetConformingProlongation(); }
|
||||
/// Get the finite element space restriction matrix
|
||||
/// Get the finite element space restriction operator
|
||||
virtual const Operator *GetRestriction() const
|
||||
{ return fes->GetConformingRestriction(); }
|
||||
/// Get the output finite element space prolongation matrix
|
||||
@@ -491,10 +526,12 @@ public:
|
||||
double value);
|
||||
|
||||
/// Eliminate the given @a vdofs. NOTE: here, @a vdofs is a list of DOFs.
|
||||
/** In this case the eliminations are applied to the internal \f$ M \f$
|
||||
and @a rhs without storing the elimination matrix \f$ M_e \f$. */
|
||||
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
|
||||
DiagonalPolicy dpolicy = DIAG_ONE);
|
||||
|
||||
/// Eliminate the given @a vdofs, storing the eliminated part internally.
|
||||
/// Eliminate the given @a vdofs, storing the eliminated part internally in \f$ M_e \f$.
|
||||
/** This method works in conjunction with EliminateVDofsInRHS() and allows
|
||||
elimination of boundary conditions in multiple right-hand sides. In this
|
||||
method, @a vdofs is a list of DOFs. */
|
||||
@@ -523,9 +560,11 @@ public:
|
||||
void EliminateVDofsInRHS(const Array<int> &vdofs, const Vector &x,
|
||||
Vector &b);
|
||||
|
||||
/// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
|
||||
double FullInnerProduct(const Vector &x, const Vector &y) const
|
||||
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
|
||||
|
||||
/// Update the @a FiniteElementSpace and delete all data associated with the old one.
|
||||
virtual void Update(FiniteElementSpace *nfes = NULL);
|
||||
|
||||
/// (DEPRECATED) Return the FE space associated with the BilinearForm.
|
||||
@@ -537,7 +576,13 @@ public:
|
||||
/// Read-only access to the associated FiniteElementSpace.
|
||||
const FiniteElementSpace *FESpace() const { return fes; }
|
||||
|
||||
/// Sets diagonal policy used upon construction of the linear system
|
||||
/// Sets diagonal policy used upon construction of the linear system.
|
||||
/** Policies include:
|
||||
|
||||
- DIAG_ZERO (Set the diagonal values to zero)
|
||||
- DIAG_ONE (Set the diagonal values to one)
|
||||
- DIAG_KEEP (Keep the diagonal values)
|
||||
*/
|
||||
void SetDiagonalPolicy(DiagonalPolicy policy);
|
||||
|
||||
/// Indicate that integrators are not owned by the BilinearForm
|
||||
@@ -550,16 +595,16 @@ public:
|
||||
|
||||
/**
|
||||
Class for assembling of bilinear forms `a(u,v)` defined on different
|
||||
trial and test spaces. The assembled matrix `A` is such that
|
||||
trial and test spaces. The assembled matrix `M` is such that
|
||||
|
||||
a(u,v) = V^t A U
|
||||
a(u,v) = V^t M U
|
||||
|
||||
where `U` and `V` are the vectors representing the functions `u` and `v`,
|
||||
respectively. The first argument, `u`, of `a(,)` is in the trial space
|
||||
and the second argument, `v`, is in the test space. Thus,
|
||||
|
||||
# of rows of A = dimension of the test space and
|
||||
# of cols of A = dimension of the trial space.
|
||||
# of rows of M = dimension of the test space and
|
||||
# of cols of M = dimension of the trial space.
|
||||
|
||||
Both trial and test spaces should be defined on the same mesh.
|
||||
*/
|
||||
@@ -628,11 +673,15 @@ public:
|
||||
FiniteElementSpace *te_fes,
|
||||
MixedBilinearForm *mbf);
|
||||
|
||||
/// Returns a reference to: \f$ M_{ij} \f$
|
||||
virtual double &Elem(int i, int j);
|
||||
|
||||
/// Returns a reference to: \f$ M_{ij} \f$
|
||||
virtual const double &Elem(int i, int j) const;
|
||||
|
||||
/// Matrix multiplication: \f$ y = M x \f$
|
||||
virtual void Mult(const Vector & x, Vector & y) const;
|
||||
|
||||
virtual void AddMult(const Vector & x, Vector & y,
|
||||
const double a = 1.0) const;
|
||||
|
||||
@@ -642,6 +691,7 @@ public:
|
||||
|
||||
virtual MatrixInverse *Inverse() const;
|
||||
|
||||
/// Finalizes the matrix initialization.
|
||||
virtual void Finalize(int skip_zeros = 1);
|
||||
|
||||
/** Extract the associated matrix as SparseMatrix blocks. The number of
|
||||
@@ -649,8 +699,14 @@ public:
|
||||
test and trial spaces, respectively. */
|
||||
void GetBlocks(Array2D<SparseMatrix *> &blocks) const;
|
||||
|
||||
/// Returns a const reference to the sparse matrix: \f$ M \f$
|
||||
const SparseMatrix &SpMat() const { return *mat; }
|
||||
|
||||
/// Returns a reference to the sparse matrix: \f$ M \f$
|
||||
SparseMatrix &SpMat() { return *mat; }
|
||||
|
||||
/** @brief Nullifies the internal matrix \f$ M \f$ and returns a pointer
|
||||
to it. Used for transfering ownership. */
|
||||
SparseMatrix *LoseMat() { SparseMatrix *tmp = mat; mat = NULL; return tmp; }
|
||||
|
||||
/// Adds a domain integrator. Assumes ownership of @a bfi.
|
||||
@@ -697,6 +753,7 @@ public:
|
||||
corresponding pointer (to Array<int>) will be NULL. */
|
||||
Array<Array<int>*> *GetBTFBFI_Marker() { return &btfbfi_marker; }
|
||||
|
||||
/// Sets all sparse values of \f$ M \f$ to @a a.
|
||||
void operator=(const double a) { *mat = a; }
|
||||
|
||||
/// Set the desired assembly level. The default is AssemblyLevel::FULL.
|
||||
|
||||
@@ -22,9 +22,12 @@ namespace mfem
|
||||
class BilinearForm;
|
||||
class MixedBilinearForm;
|
||||
|
||||
|
||||
/** @brief Class extending the BilinearForm class to support the different
|
||||
AssemblyLevel%s. */
|
||||
/// Class extending the BilinearForm class to support different AssemblyLevels.
|
||||
/** FA - Full Assembly
|
||||
PA - Partial Assembly
|
||||
EA - Element Assembly
|
||||
MF - Matrix Free
|
||||
*/
|
||||
class BilinearFormExtension : public Operator
|
||||
{
|
||||
protected:
|
||||
@@ -42,6 +45,7 @@ public:
|
||||
/// Get the finite element space restriction matrix
|
||||
virtual const Operator *GetRestriction() const;
|
||||
|
||||
/// Assemble at the level given for the BilinearFormExtension subclass
|
||||
virtual void Assemble() = 0;
|
||||
|
||||
virtual void AssembleDiagonal(Vector &diag) const
|
||||
@@ -58,7 +62,8 @@ public:
|
||||
virtual void Update() = 0;
|
||||
};
|
||||
|
||||
/// Data and methods for fully-assembled bilinear forms
|
||||
/** @brief Data and methods for fully-assembled bilinear forms.
|
||||
Not yet implemented! Use the BilinearForm Class instead. */
|
||||
class FABilinearFormExtension : public BilinearFormExtension
|
||||
{
|
||||
public:
|
||||
@@ -127,7 +132,7 @@ public:
|
||||
void MultTranspose(const Vector &x, Vector &y) const;
|
||||
};
|
||||
|
||||
/// Data and methods for matrix-free bilinear forms
|
||||
/// Data and methods for matrix-free bilinear forms NOT YET IMPLEMENTED.
|
||||
class MFBilinearFormExtension : public BilinearFormExtension
|
||||
{
|
||||
public:
|
||||
@@ -147,8 +152,12 @@ public:
|
||||
~MFBilinearFormExtension() {}
|
||||
};
|
||||
|
||||
/** @brief Class extending the MixedBilinearForm class to support the different
|
||||
AssemblyLevel%s. */
|
||||
/// Class extending the MixedBilinearForm class to support different AssemblyLevels.
|
||||
/** FA - Full Assembly
|
||||
PA - Partial Assembly
|
||||
EA - Element Assembly
|
||||
MF - Matrix Free
|
||||
*/
|
||||
class MixedBilinearFormExtension : public Operator
|
||||
{
|
||||
protected:
|
||||
|
||||
+4
-1
@@ -199,6 +199,8 @@ public:
|
||||
virtual ~BilinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
/** Wraps a given @a BilinearFormIntegrator and transposes the resulting element
|
||||
matrices. See for example ex9, ex9p. */
|
||||
class TransposeIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
@@ -1563,7 +1565,7 @@ public:
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form a(u,v) := (-V u, Grad v) in 2D or 3D
|
||||
and where V is a vector coefficient, u is in H1 and v is in H1. */
|
||||
and where V is a vector coefficient, u is in H1 or L2 and v is in H1. */
|
||||
class MixedScalarWeakDivergenceIntegrator : public MixedScalarVectorIntegrator
|
||||
{
|
||||
public:
|
||||
@@ -2001,6 +2003,7 @@ public:
|
||||
void SetupPA(const FiniteElementSpace &fes, const bool force = false);
|
||||
};
|
||||
|
||||
/** Mass integrator (u, v) restricted to the boundary of a domain */
|
||||
class BoundaryMassIntegrator : public MassIntegrator
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -176,42 +176,41 @@ static void PADiffusionSetup3D(const int Q1D,
|
||||
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,
|
||||
MFEM_FORALL(eq, NE*NQ,
|
||||
{
|
||||
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 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
|
||||
}
|
||||
const int e = eq / NQ;
|
||||
const int q = eq % NQ;
|
||||
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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+23
-11
@@ -25,6 +25,7 @@ namespace mfem
|
||||
|
||||
void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
|
||||
{
|
||||
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
@@ -51,21 +52,30 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
|
||||
dofs1D = maps->ndof;
|
||||
quad1D = maps->nqpt;
|
||||
pa_data.SetSize(ne*nq, Device::GetDeviceMemoryType());
|
||||
Vector coeff;
|
||||
Vector *coeff{nullptr};
|
||||
bool own_coeff{true};
|
||||
if (Q == nullptr)
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = 1.0;
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = 1.0;
|
||||
}
|
||||
else if (ConstantCoefficient* cQ = dynamic_cast<ConstantCoefficient*>(Q))
|
||||
{
|
||||
coeff.SetSize(1);
|
||||
coeff(0) = cQ->constant;
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(1);
|
||||
(*coeff)(0) = 1.0;
|
||||
}
|
||||
else if (QuadratureCoefficient* cQ = dynamic_cast<QuadratureCoefficient*>(Q))
|
||||
{
|
||||
coeff = cQ->Data();
|
||||
own_coeff = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
coeff.SetSize(nq * ne);
|
||||
auto C = Reshape(coeff.HostWrite(), nq, ne);
|
||||
coeff = new Vector;
|
||||
coeff->SetSize(nq * ne);
|
||||
auto C = Reshape(coeff->HostWrite(), nq, ne);
|
||||
for (int e = 0; e < ne; ++e)
|
||||
{
|
||||
ElementTransformation& T = *fes.GetElementTransformation(e);
|
||||
@@ -80,11 +90,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
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);
|
||||
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ, NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -104,11 +114,11 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
|
||||
{
|
||||
const int NE = ne;
|
||||
const int NQ = nq;
|
||||
const bool const_c = coeff.Size() == 1;
|
||||
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);
|
||||
const_c ? Reshape(coeff->Read(), 1,1) : Reshape(coeff->Read(), NQ,NE);
|
||||
auto v = Reshape(pa_data.Write(), NQ,NE);
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
@@ -125,6 +135,8 @@ void MassIntegrator::SetupPA(const FiniteElementSpace &fes, const bool force)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (own_coeff) { delete coeff; }
|
||||
}
|
||||
|
||||
void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
+109
-19
@@ -12,6 +12,7 @@
|
||||
// Implementation of Coefficient class
|
||||
|
||||
#include "fem.hpp"
|
||||
#include "../linalg/dtensor.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -21,6 +22,13 @@ namespace mfem
|
||||
|
||||
using namespace std;
|
||||
|
||||
double QuadratureCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
auto coeff = mfem::Reshape(qData->HostRead(), nip, NE);
|
||||
return coeff(ip.index, T.ElementNo);
|
||||
}
|
||||
|
||||
double PWConstCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
@@ -416,13 +424,43 @@ double DeterminantCoefficient::Eval(ElementTransformation &T,
|
||||
return ma.Det();
|
||||
}
|
||||
|
||||
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
|
||||
VectorCoefficient &B,
|
||||
double _alpha, double _beta)
|
||||
: VectorCoefficient(A.GetVDim()), a(&A), b(&B), alpha(_alpha), beta(_beta),
|
||||
va(A.GetVDim())
|
||||
VectorSumCoefficient::VectorSumCoefficient(int dim)
|
||||
: VectorCoefficient(dim),
|
||||
ACoef(NULL), BCoef(NULL),
|
||||
A(dim), B(dim),
|
||||
alphaCoef(NULL), betaCoef(NULL),
|
||||
alpha(1.0), beta(1.0)
|
||||
{
|
||||
MFEM_ASSERT(A.GetVDim() == B.GetVDim(),
|
||||
A = 0.0; B = 0.0;
|
||||
}
|
||||
|
||||
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
|
||||
VectorCoefficient &_B,
|
||||
double _alpha, double _beta)
|
||||
: VectorCoefficient(_A.GetVDim()),
|
||||
ACoef(&_A), BCoef(&_B),
|
||||
A(_A.GetVDim()), B(_A.GetVDim()),
|
||||
alphaCoef(NULL), betaCoef(NULL),
|
||||
alpha(_alpha), beta(_beta)
|
||||
{
|
||||
MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
|
||||
"VectorSumCoefficient: "
|
||||
"Arguments must have the same dimension.");
|
||||
}
|
||||
|
||||
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &_A,
|
||||
VectorCoefficient &_B,
|
||||
Coefficient &_alpha,
|
||||
Coefficient &_beta)
|
||||
: VectorCoefficient(_A.GetVDim()),
|
||||
ACoef(&_A), BCoef(&_B),
|
||||
A(_A.GetVDim()),
|
||||
B(_A.GetVDim()),
|
||||
alphaCoef(&_alpha),
|
||||
betaCoef(&_beta),
|
||||
alpha(0.0), beta(0.0)
|
||||
{
|
||||
MFEM_ASSERT(_A.GetVDim() == _B.GetVDim(),
|
||||
"VectorSumCoefficient: "
|
||||
"Arguments must have the same dimension.");
|
||||
}
|
||||
@@ -430,26 +468,47 @@ VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A,
|
||||
void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
b->Eval(V, T, ip);
|
||||
if ( beta != 1.0 ) { V *= beta; }
|
||||
a->Eval(va, T, ip);
|
||||
V.Add(alpha, va);
|
||||
V.SetSize(A.Size());
|
||||
if ( ACoef) { ACoef->Eval(A, T, ip); }
|
||||
if ( BCoef) { BCoef->Eval(B, T, ip); }
|
||||
if (alphaCoef) { alpha = alphaCoef->Eval(T, ip); }
|
||||
if ( betaCoef) { beta = betaCoef->Eval(T, ip); }
|
||||
add(alpha, A, beta, B, V);
|
||||
}
|
||||
|
||||
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
|
||||
double A,
|
||||
VectorCoefficient &B)
|
||||
: VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B)
|
||||
{}
|
||||
|
||||
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
|
||||
Coefficient &A,
|
||||
VectorCoefficient &B)
|
||||
: VectorCoefficient(B.GetVDim()), a(&A), b(&B)
|
||||
: VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B)
|
||||
{}
|
||||
|
||||
void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double sa = a->Eval(T, ip);
|
||||
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
|
||||
b->Eval(V, T, ip);
|
||||
V *= sa;
|
||||
}
|
||||
|
||||
NormalizedVectorCoefficient::NormalizedVectorCoefficient(VectorCoefficient &A,
|
||||
double _tol)
|
||||
: VectorCoefficient(A.GetVDim()), a(&A), tol(_tol)
|
||||
{}
|
||||
|
||||
void NormalizedVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
a->Eval(V, T, ip);
|
||||
double nv = V.Norml2();
|
||||
V *= (nv > tol) ? (1.0/nv) : 0.0;
|
||||
}
|
||||
|
||||
VectorCrossProductCoefficient::VectorCrossProductCoefficient(
|
||||
VectorCoefficient &A,
|
||||
VectorCoefficient &B)
|
||||
@@ -471,17 +530,18 @@ void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
V[2] = va[0] * vb[1] - va[1] * vb[0];
|
||||
}
|
||||
|
||||
MatVecCoefficient::MatVecCoefficient(MatrixCoefficient &A,
|
||||
VectorCoefficient &B)
|
||||
MatrixVectorProductCoefficient::MatrixVectorProductCoefficient(
|
||||
MatrixCoefficient &A, VectorCoefficient &B)
|
||||
: VectorCoefficient(A.GetHeight()), a(&A), b(&B),
|
||||
ma(A.GetHeight(), A.GetWidth()), vb(B.GetVDim())
|
||||
{
|
||||
MFEM_ASSERT(A.GetWidth() == B.GetVDim(),
|
||||
"MatVecCoefficient: Arguments have incompatible dimensions.");
|
||||
"MatrixVectorProductCoefficient: "
|
||||
"Arguments have incompatible dimensions.");
|
||||
}
|
||||
|
||||
void MatVecCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
a->Eval(ma, T, ip);
|
||||
b->Eval(vb, T, ip);
|
||||
@@ -517,17 +577,23 @@ void MatrixSumCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
M.Add(alpha, ma);
|
||||
}
|
||||
|
||||
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
|
||||
double A,
|
||||
MatrixCoefficient &B)
|
||||
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(A), a(NULL), b(&B)
|
||||
{}
|
||||
|
||||
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
|
||||
Coefficient &A,
|
||||
MatrixCoefficient &B)
|
||||
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), a(&A), b(&B)
|
||||
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(0.0), a(&A), b(&B)
|
||||
{}
|
||||
|
||||
void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M,
|
||||
ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
double sa = a->Eval(T, ip);
|
||||
double sa = (a == NULL) ? aConst : a->Eval(T, ip);
|
||||
b->Eval(M, T, ip);
|
||||
M *= sa;
|
||||
}
|
||||
@@ -581,6 +647,30 @@ void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
}
|
||||
}
|
||||
|
||||
CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A,
|
||||
VectorCoefficient &K)
|
||||
: MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K),
|
||||
vk(K.GetVDim())
|
||||
{}
|
||||
|
||||
void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
k->Eval(vk, T, ip);
|
||||
M.SetSize(vk.Size(), vk.Size());
|
||||
M = 0.0;
|
||||
double k2 = vk*vk;
|
||||
for (int i=0; i<vk.Size(); i++)
|
||||
{
|
||||
M(i, i) = k2;
|
||||
for (int j=0; j<vk.Size(); j++)
|
||||
{
|
||||
M(i, j) -= vk[i] * vk[j];
|
||||
}
|
||||
}
|
||||
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
|
||||
}
|
||||
|
||||
double LpNormLoop(double p, Coefficient &coeff, Mesh &mesh,
|
||||
const IntegrationRule *irs[])
|
||||
{
|
||||
|
||||
+683
-78
File diff suppressed because it is too large
Load Diff
@@ -624,4 +624,77 @@ void FaceElementTransformations::Transform(const DenseMatrix &matrix,
|
||||
IsoparametricTransformation::Transform(matrix, result);
|
||||
}
|
||||
|
||||
double FaceElementTransformations::CheckConsistency(int print_level,
|
||||
std::ostream &out)
|
||||
{
|
||||
// Check that the face vertices are mapped to the same physical location
|
||||
// when using the following three transformations:
|
||||
// - the face transformation, *this
|
||||
// - Loc1 + Elem1
|
||||
// - Loc2 + Elem2, if present.
|
||||
|
||||
const bool have_face = (mask & 16);
|
||||
const bool have_el1 = (mask & 1) && (mask & 4);
|
||||
const bool have_el2 = (mask & 2) && (mask & 8) && (Elem2No >= 0);
|
||||
if (int(have_face) + int(have_el1) + int(have_el2) < 2)
|
||||
{
|
||||
// need at least two different transformations to perform a check
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const IntegrationRule &v_ir = *Geometries.GetVertices(GetGeometryType());
|
||||
|
||||
double max_dist = 0.0;
|
||||
Vector dist(v_ir.GetNPoints());
|
||||
DenseMatrix coords_base, coords_el;
|
||||
IntegrationRule v_eir(v_ir.GetNPoints());
|
||||
if (have_face)
|
||||
{
|
||||
Transform(v_ir, coords_base);
|
||||
if (print_level > 0)
|
||||
{
|
||||
out << "\nface vertex coordinates (from face transform):\n"
|
||||
<< "----------------------------------------------\n";
|
||||
coords_base.PrintT(out, coords_base.Height());
|
||||
}
|
||||
}
|
||||
if (have_el1)
|
||||
{
|
||||
Loc1.Transform(v_ir, v_eir);
|
||||
Elem1->Transform(v_eir, coords_el);
|
||||
if (print_level > 0)
|
||||
{
|
||||
out << "\nface vertex coordinates (from element 1 transform):\n"
|
||||
<< "---------------------------------------------------\n";
|
||||
coords_el.PrintT(out, coords_el.Height());
|
||||
}
|
||||
if (have_face)
|
||||
{
|
||||
coords_el -= coords_base;
|
||||
coords_el.Norm2(dist);
|
||||
max_dist = std::max(max_dist, dist.Normlinf());
|
||||
}
|
||||
else
|
||||
{
|
||||
coords_base = coords_el;
|
||||
}
|
||||
}
|
||||
if (have_el2)
|
||||
{
|
||||
Loc2.Transform(v_ir, v_eir);
|
||||
Elem2->Transform(v_eir, coords_el);
|
||||
if (print_level > 0)
|
||||
{
|
||||
out << "\nface vertex coordinates (from element 2 transform):\n"
|
||||
<< "---------------------------------------------------\n";
|
||||
coords_el.PrintT(out, coords_el.Height());
|
||||
}
|
||||
coords_el -= coords_base;
|
||||
coords_el.Norm2(dist);
|
||||
max_dist = std::max(max_dist, dist.Normlinf());
|
||||
}
|
||||
|
||||
return max_dist;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+97
-15
@@ -38,9 +38,12 @@ protected:
|
||||
};
|
||||
Geometry::Type geom;
|
||||
|
||||
// Evaluate the Jacobian of the transformation at the IntPoint and store it
|
||||
// in dFdx.
|
||||
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
|
||||
store it in dFdx. */
|
||||
virtual const DenseMatrix &EvalJacobian() = 0;
|
||||
|
||||
/** @brief Evaluate the Hessian of the transformation at the IntPoint and
|
||||
store it in d2Fdx2. */
|
||||
virtual const DenseMatrix &EvalHessian() = 0;
|
||||
|
||||
double EvalWeight();
|
||||
@@ -74,14 +77,27 @@ public:
|
||||
|
||||
ElementTransformation();
|
||||
|
||||
/** @brief Set the integration point @a ip that weights and Jacobians will
|
||||
be evaluated at. */
|
||||
void SetIntPoint(const IntegrationPoint *ip)
|
||||
{ IntPoint = ip; EvalState = 0; }
|
||||
|
||||
/** @brief Get a const reference to the currently set integration point. This
|
||||
will return NULL if no integration point is set. */
|
||||
const IntegrationPoint &GetIntPoint() { return *IntPoint; }
|
||||
|
||||
/** @brief Transform integration point from reference coordinates to
|
||||
physical coordinates and store them in the vector. */
|
||||
virtual void Transform(const IntegrationPoint &, Vector &) = 0;
|
||||
|
||||
/** @brief Transform all the integration points from the integration rule
|
||||
from reference coordinates to physical
|
||||
coordinates and store them as column vectors in the matrix. */
|
||||
virtual void Transform(const IntegrationRule &, DenseMatrix &) = 0;
|
||||
|
||||
/// Transform columns of 'matrix', store result in 'result'.
|
||||
/** @brief Transform all the integration points from the column vectors
|
||||
of @a matrix from reference coordinates to physical
|
||||
coordinates and store them as column vectors in @a result. */
|
||||
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result) = 0;
|
||||
|
||||
/** @brief Return the Jacobian matrix of the transformation at the currently
|
||||
@@ -92,27 +108,44 @@ public:
|
||||
const DenseMatrix &Jacobian()
|
||||
{ return (EvalState & JACOBIAN_MASK) ? dFdx : EvalJacobian(); }
|
||||
|
||||
|
||||
/** @brief Return the Hessian matrix of the transformation at the currently
|
||||
set IntegrationPoint, using the method SetIntPoint(). */
|
||||
const DenseMatrix &Hessian()
|
||||
{ return (EvalState & HESSIAN_MASK) ? d2Fdx2 : EvalHessian(); }
|
||||
|
||||
/** @brief Return the weight of the Jacobian matrix of the transformation
|
||||
at the currently set IntegrationPoint.
|
||||
The Weight evaluates to \f$ \sqrt{\lvert J^T J \rvert} \f$. */
|
||||
double Weight() { return (EvalState & WEIGHT_MASK) ? Wght : EvalWeight(); }
|
||||
|
||||
/** @brief Return the adjugate of the Jacobian matrix of the transformation
|
||||
at the currently set IntegrationPoint. */
|
||||
const DenseMatrix &AdjugateJacobian()
|
||||
{ return (EvalState & ADJUGATE_MASK) ? adjJ : EvalAdjugateJ(); }
|
||||
|
||||
/** @brief Return the inverse of the Jacobian matrix of the transformation
|
||||
at the currently set IntegrationPoint. */
|
||||
const DenseMatrix &InverseJacobian()
|
||||
{ return (EvalState & INVERSE_MASK) ? invJ : EvalInverseJ(); }
|
||||
|
||||
/// Return the order of the current element we are using for the transformation.
|
||||
virtual int Order() const = 0;
|
||||
|
||||
/// Return the order of the elements of the Jacobian of the transformation.
|
||||
virtual int OrderJ() const = 0;
|
||||
|
||||
/** @brief Return the order of the determinant of the Jacobian (weight)
|
||||
of the transformation. */
|
||||
virtual int OrderW() const = 0;
|
||||
/// Order of adj(J)^t.grad(fi)
|
||||
|
||||
/// Return the order of \f$ adj(J)^T \nabla fi \f$
|
||||
virtual int OrderGrad(const FiniteElement *fe) const = 0;
|
||||
|
||||
/// Return the Geometry::Type of the reference element.
|
||||
Geometry::Type GetGeometryType() const { return geom; }
|
||||
|
||||
/// Return the dimension of the reference element.
|
||||
/// Return the topological dimension of the reference element.
|
||||
int GetDimension() const { return Geometry::Dimension[geom]; }
|
||||
|
||||
/// Get the dimension of the target (physical) space.
|
||||
@@ -308,7 +341,7 @@ public:
|
||||
virtual int Transform(const Vector &pt, IntegrationPoint &ip);
|
||||
};
|
||||
|
||||
|
||||
/// A standard isoparametric element transformation
|
||||
class IsoparametricTransformation : public ElementTransformation
|
||||
{
|
||||
private:
|
||||
@@ -318,26 +351,29 @@ private:
|
||||
const FiniteElement *FElem;
|
||||
DenseMatrix PointMat; // dim x dof
|
||||
|
||||
// Evaluate the Jacobian of the transformation at the IntPoint and store it
|
||||
// in dFdx.
|
||||
/** @brief Evaluate the Jacobian of the transformation at the IntPoint and
|
||||
store it in dFdx. */
|
||||
virtual const DenseMatrix &EvalJacobian();
|
||||
// Evaluate the Hessian of the transformation at the IntPoint and store it
|
||||
// in d2Fdx2.
|
||||
virtual const DenseMatrix &EvalHessian();
|
||||
public:
|
||||
/// Set the element that will be used to compute the transformations
|
||||
void SetFE(const FiniteElement *FE) { FElem = FE; geom = FE->GetGeomType(); }
|
||||
|
||||
/// Get the current element used to compute the transformations
|
||||
const FiniteElement* GetFE() const { return FElem; }
|
||||
|
||||
/// @brief Set the underlying point matrix describing the transformation.
|
||||
/** The dimensions of the matrix are space-dim x dof. The transformation is
|
||||
defined as
|
||||
\f$ x = F( \hat x ) = P \phi( \hat x ) \f$
|
||||
|
||||
x = F(xh) = P . phi(xh),
|
||||
|
||||
where xh (x hat) is the reference point, x is the corresponding physical
|
||||
point, P is the point matrix, and phi(xh) is the column-vector of all
|
||||
basis functions evaluated at xh. The columns of P represent the control
|
||||
points in physical space defining the transformation. */
|
||||
where \f$ \hat x \f$ is the reference point, @a x is the corresponding
|
||||
physical point, @a P is the point matrix, and \f$ \phi( \hat x ) \f$ is
|
||||
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; }
|
||||
|
||||
/// Return the stored point matrix.
|
||||
@@ -346,19 +382,44 @@ public:
|
||||
/// Write access to the stored point matrix. Use with caution.
|
||||
DenseMatrix &GetPointMat() { return PointMat; }
|
||||
|
||||
/// Set the FiniteElement Geometry for the reference elements being used.
|
||||
void SetIdentityTransformation(Geometry::Type GeomType);
|
||||
|
||||
/** @brief Transform integration point from reference coordinates to
|
||||
physical coordinates and store them in the vector. */
|
||||
virtual void Transform(const IntegrationPoint &, Vector &);
|
||||
|
||||
/** @brief Transform all the integration points from the integration rule
|
||||
from reference coordinates to physical
|
||||
coordinates and store them as column vectors in the matrix. */
|
||||
virtual void Transform(const IntegrationRule &, DenseMatrix &);
|
||||
|
||||
/** @brief Transform all the integration points from the column vectors
|
||||
of @a matrix from reference coordinates to physical
|
||||
coordinates and store them as column vectors in @a result. */
|
||||
virtual void Transform(const DenseMatrix &matrix, DenseMatrix &result);
|
||||
|
||||
/// Return the order of the current element we are using for the transformation.
|
||||
virtual int Order() const { return FElem->GetOrder(); }
|
||||
|
||||
/// Return the order of the elements of the Jacobian of the transformation.
|
||||
virtual int OrderJ() const;
|
||||
|
||||
/** @brief Return the order of the determinant of the Jacobian (weight)
|
||||
of the transformation. */
|
||||
virtual int OrderW() const;
|
||||
|
||||
/// Return the order of \f$ adj(J)^T \nabla fi \f$
|
||||
virtual int OrderGrad(const FiniteElement *fe) const;
|
||||
|
||||
virtual int GetSpaceDim() const { return PointMat.Height(); }
|
||||
|
||||
/** @brief Transform a point @a pt from physical space to a point @a ip in
|
||||
reference space. */
|
||||
/** Attempt to find the IntegrationPoint that is transformed into the given
|
||||
point in physical space. If the inversion fails a non-zero value is
|
||||
returned. This method is not 100 percent reliable for non-linear
|
||||
transformations. */
|
||||
virtual int TransformBack(const Vector & v, IntegrationPoint & ip)
|
||||
{
|
||||
InverseElementTransformation inv_tr(this);
|
||||
@@ -378,6 +439,7 @@ public:
|
||||
void Transform (const IntegrationRule &, IntegrationRule &);
|
||||
};
|
||||
|
||||
|
||||
class FaceElementTransformations : public IsoparametricTransformation
|
||||
{
|
||||
private:
|
||||
@@ -430,9 +492,29 @@ public:
|
||||
ElementTransformation & GetElement2Transformation();
|
||||
IntegrationPointTransformation & GetIntPoint1Transformation();
|
||||
IntegrationPointTransformation & GetIntPoint2Transformation();
|
||||
|
||||
/** @brief Check for self-consistency: compares the result of mapping the
|
||||
reference face vertices to physical coordinates using the three
|
||||
transformations: face, element 1, and element 2.
|
||||
|
||||
@param[in] print_level If set to a positive number, print the physical
|
||||
coordinates of the face vertices computed through
|
||||
all available transformations: face, element 1,
|
||||
and/or element 2.
|
||||
@param[in,out] out The output stream to use for printing.
|
||||
|
||||
@returns A maximal distance between physical coordinates of face vertices
|
||||
that should coincide. A successful check should return a small
|
||||
number relative to the mesh extents. If less than 2 of the three
|
||||
transformations are set, returns 0.
|
||||
|
||||
@warning This check will generally fail on periodic boundary faces.
|
||||
*/
|
||||
double CheckConsistency(int print_level = 0,
|
||||
std::ostream &out = mfem::out);
|
||||
};
|
||||
|
||||
/* Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
|
||||
/** Elem1(Loc1(x)) = Face(x) = Elem2(Loc2(x))
|
||||
|
||||
|
||||
Physical Space
|
||||
|
||||
@@ -45,6 +45,7 @@ public:
|
||||
/// Force recomputation of the estimates on the next call to GetLocalErrors.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
/// Destruct the error estimator
|
||||
virtual ~ErrorEstimator() { }
|
||||
};
|
||||
|
||||
@@ -66,6 +67,14 @@ public:
|
||||
/** @brief The ZienkiewiczZhuEstimator class implements the Zienkiewicz-Zhu
|
||||
error estimation procedure.
|
||||
|
||||
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
|
||||
and a posteriori error estimates. Part 1: The recovery technique.
|
||||
Int. J. Num. Meth. Engng. 33, 1331-1364 (1992).
|
||||
|
||||
Zienkiewicz, O.C. and Zhu, J.Z., The superconvergent patch recovery
|
||||
and a posteriori error estimates. Part 2: Error estimates and adaptivity.
|
||||
Int. J. Num. Meth. Engng. 33, 1365-1382 (1992).
|
||||
|
||||
The required BilinearFormIntegrator must implement the methods
|
||||
ComputeElementFlux() and ComputeFluxEnergy().
|
||||
*/
|
||||
@@ -217,6 +226,7 @@ protected:
|
||||
class when needed.*/
|
||||
bool own_flux_fes; ///< Ownership flag for flux_space and smooth_flux_space.
|
||||
|
||||
/// Initialize with the integrator, solution, and flux finite element spaces.
|
||||
void Init(BilinearFormIntegrator &integ,
|
||||
ParGridFunction &sol,
|
||||
ParFiniteElementSpace *flux_fes,
|
||||
|
||||
+503
-503
File diff suppressed because it is too large
Load Diff
+431
-183
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -311,10 +311,10 @@ GetEdge(int &nv, v_t &v, int &ne, int &e, int &eo, const int edge_info)
|
||||
eo = edge_info%64;
|
||||
MFEM_ASSERT(0 <= e && e < g_consts::NumEdges, "");
|
||||
MFEM_ASSERT(0 <= eo && eo < e_consts::NumOrient, "");
|
||||
v[0] = g_consts::Edges[e][0];
|
||||
v[1] = g_consts::Edges[e][1];
|
||||
v[0] = e_consts::Orient[eo][v[0]];
|
||||
v[1] = e_consts::Orient[eo][v[1]];
|
||||
v[0] = e_consts::Orient[eo][0];
|
||||
v[1] = e_consts::Orient[eo][1];
|
||||
v[0] = g_consts::Edges[e][v[0]];
|
||||
v[1] = g_consts::Edges[e][v[1]];
|
||||
}
|
||||
|
||||
template <Geometry::Type geom, Geometry::Type f_geom,
|
||||
|
||||
+123
-49
@@ -19,10 +19,10 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** Collection of finite elements from the same family in multiple dimensions.
|
||||
This class is used to match the degrees of freedom of a FiniteElementSpace
|
||||
between elements, and to provide the finite element restriction from an
|
||||
element to its boundary. */
|
||||
/** @brief Collection of finite elements from the same family in multiple
|
||||
dimensions. This class is used to match the degrees of freedom of a
|
||||
FiniteElementSpace between elements, and to provide the finite element
|
||||
restriction from an element to its boundary. */
|
||||
class FiniteElementCollection
|
||||
{
|
||||
protected:
|
||||
@@ -41,8 +41,7 @@ protected:
|
||||
|
||||
public:
|
||||
/** @brief Enumeration for ContType: defines the continuity of the field
|
||||
across element interfaces.
|
||||
*/
|
||||
across element interfaces. */
|
||||
enum { CONTINUOUS, ///< Field is continuous across element interfaces
|
||||
TANGENTIAL, ///< Tangential components of vector field
|
||||
NORMAL, ///< Normal component of vector field
|
||||
@@ -77,15 +76,81 @@ public:
|
||||
|
||||
/** @brief Factory method: return a newly allocated FiniteElementCollection
|
||||
according to the given name. */
|
||||
/**
|
||||
| FEC Name | Space | Order | BasisType | FiniteElement::MapT | Notes |
|
||||
| :------: | :---: | :---: | :-------: | :-----: | :---: |
|
||||
| H1_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
|
||||
| H1@[BTYPE]_[DIM]_[ORDER] | H1 | * | * | VALUE | H1 nodal elements |
|
||||
| H1Pos_[DIM]_[ORDER] | H1 | * | 1 | VALUE | H1 nodal elements |
|
||||
| H1Pos_Trace_[DIM]_[ORDER] | H^{1/2} | * | 2 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
|
||||
| H1_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
|
||||
| H1_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 | VALUE | H^{1/2}-conforming trace elements for H1 defined on the interface between mesh elements (faces,edges,vertices) |
|
||||
| ND_[DIM]_[ORDER] | H(curl) | * | 1 / 0 | H_CURL | Nedelec vector elements |
|
||||
| ND@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(curl) | * | * / * | H_CURL | Nedelec vector elements |
|
||||
| ND_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
|
||||
| ND_Trace@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | H_CURL | H^{1/2}-conforming trace elements for H(curl) defined on the interface between mesh elements (faces) |
|
||||
| RT_[DIM]_[ORDER] | H(div) | * | 1 / 0 | H_DIV | Raviart-Thomas vector elements |
|
||||
| RT@[CBTYPE][OBTYPE]_[DIM]_[ORDER] | H(div) | * | * / * | H_DIV | Raviart-Thomas vector elements |
|
||||
| RT_Trace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
|
||||
| RT_ValTrace_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
|
||||
| RT_Trace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | INTEGRAL | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
|
||||
| RT_ValTrace@[BTYPE]_[DIM]_[ORDER] | H^{1/2} | * | 1 / 0 | VALUE | H^{1/2}-conforming trace elements for H(div) defined on the interface between mesh elements (faces) |
|
||||
| L2_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
|
||||
| L2_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | VALUE | Discontinous L2 elements |
|
||||
| L2Int_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
|
||||
| L2Int_T[BTYPE]_[DIM]_[ORDER] | L2 | * | 0 | INTEGRAL | Discontinous L2 elements |
|
||||
| DG_Iface_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
|
||||
| DG_Iface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | VALUE | Discontinuous elements on the interface between mesh elements (faces) |
|
||||
| DG_IntIface_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
|
||||
| DG_IntIface@[BTYPE]_[DIM]_[ORDER] | - | * | 0 | INTEGRAL | Discontinuous elements on the interface between mesh elements (faces) |
|
||||
| NURBS[ORDER] | - | * | - | VALUE | Non-Uniform Rational B-Splines (NURBS) elements |
|
||||
| LinearNonConf3D | - | 1 | 1 | VALUE | Piecewise-linear nonconforming finite elements in 3D |
|
||||
| CrouzeixRaviart | - | - | - | - | Crouzeix-Raviart nonconforming elements in 2D |
|
||||
| Local_[FENAME] | - | - | - | - | Special collection that builds a local version out of the FENAME collection |
|
||||
|-|-|-|-|-|-|
|
||||
| Linear | H1 | 1 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
|
||||
| Quadratic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
|
||||
| QuadraticPos | H1 | 2 | 2 | VALUE | Left in for backward compatibility, consider using H1_ |
|
||||
| Cubic | H1 | 2 | 1 | VALUE | Left in for backward compatibility, consider using H1_ |
|
||||
| Const2D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| Const3D | L2 | 0 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| LinearDiscont2D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| GaussLinearDiscont2D | L2 | 1 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| P1OnQuad | H1 | 1 | 1 | VALUE | Linear P1 element with 3 nodes on a square |
|
||||
| QuadraticDiscont2D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| QuadraticPosDiscont2D | L2 | 2 | 2 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| GaussQuadraticDiscont2D | L2 | 2 | 0 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| CubicDiscont2D | L2 | 3 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| LinearDiscont3D | L2 | 1 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| QuadraticDiscont3D | L2 | 2 | 1 | VALUE | Left in for backward compatibility, consider using L2_ |
|
||||
| ND1_3D | H(Curl) | 1 | 1 / 0 | H_CURL | Left in for backward compatibility, consider using ND_ |
|
||||
| RT0_2D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
|
||||
| RT1_2D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
|
||||
| RT2_2D | H(Div) | 3 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
|
||||
| RT0_3D | H(Div) | 1 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
|
||||
| RT1_3D | H(Div) | 2 | 1 / 0 | H_DIV | Left in for backward compatibility, consider using RT_ |
|
||||
|
||||
| Tag | Description |
|
||||
| :------: | :--------: |
|
||||
| [DIM] | Dimension of the elements (1D, 2D, 3D) |
|
||||
| [ORDER] | Approximation order of the elements (P0, P1, P2, ...) |
|
||||
| [BTYPE] | BasisType of the element (0-GaussLegendre, 1 - GaussLobatto, 2-Bernstein, 3-OpenUniform, 4-CloseUniform, 5-OpenHalfUniform) |
|
||||
| [OBTYPE] | Open BasisType of the element for elements which have both types |
|
||||
| [CBTYPE] | Closed BasisType of the element for elements which have both types |
|
||||
|
||||
[FENAME] Is a special case for the Local FEC which generates a local version of a given
|
||||
FEC. It is selected from one of (BiCubic2DFiniteElement, Quad_Q3, Nedelec1HexFiniteElement,
|
||||
Hex_ND1, H1_[DIM]_[ORDER],H1Pos_[DIM]_[ORDER], L2_[DIM]_[ORDER] )
|
||||
*/
|
||||
static FiniteElementCollection *New(const char *name);
|
||||
|
||||
/** @brief Get the local dofs for a given sub-manifold.
|
||||
|
||||
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex,
|
||||
1D - edge, 2D - face) including those on its boundary. The local index of
|
||||
the sub-manifold (inside Geom) and its orientation are given by the
|
||||
parameter Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed
|
||||
that 0 <= SDim <= Dim(Geom). */
|
||||
Return the local dofs for a SDim-dimensional sub-manifold (0D - vertex, 1D
|
||||
- edge, 2D - face) including those on its boundary. The local index of the
|
||||
sub-manifold (inside Geom) and its orientation are given by the parameter
|
||||
Info = 64 * SubIndex + SubOrientation. Naturally, it is assumed that 0 <=
|
||||
SDim <= Dim(Geom). */
|
||||
void SubDofOrder(Geometry::Type Geom, int SDim, int Info,
|
||||
Array<int> &dofs) const;
|
||||
};
|
||||
@@ -123,8 +188,8 @@ public:
|
||||
virtual ~H1_FECollection();
|
||||
};
|
||||
|
||||
/** Arbitrary order H1-conforming (continuous) finite elements with positive
|
||||
basis functions. */
|
||||
/** @brief Arbitrary order H1-conforming (continuous) finite elements with
|
||||
positive basis functions. */
|
||||
class H1Pos_FECollection : public H1_FECollection
|
||||
{
|
||||
public:
|
||||
@@ -132,6 +197,7 @@ public:
|
||||
: H1_FECollection(p, dim, BasisType::Positive) { }
|
||||
};
|
||||
|
||||
|
||||
/** Arbitrary order H1-conforming (continuous) serendipity finite elements;
|
||||
Current implementation works in 2D only; 3D version is in development. */
|
||||
class H1Ser_FECollection : public H1_FECollection
|
||||
@@ -141,9 +207,9 @@ public:
|
||||
: H1_FECollection(p, dim, BasisType::Serendipity) { };
|
||||
};
|
||||
|
||||
/** Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the
|
||||
interface between mesh elements (faces,edges,vertices); these are the trace
|
||||
FEs of the H1-conforming FEs. */
|
||||
/** @brief Arbitrary order "H^{1/2}-conforming" trace finite elements defined on
|
||||
the interface between mesh elements (faces,edges,vertices); these are the
|
||||
trace FEs of the H1-conforming FEs. */
|
||||
class H1_Trace_FECollection : public H1_FECollection
|
||||
{
|
||||
public:
|
||||
@@ -241,9 +307,9 @@ public:
|
||||
virtual ~RT_FECollection();
|
||||
};
|
||||
|
||||
/** Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the
|
||||
interface between mesh elements (faces); these are the normal trace FEs of
|
||||
the H(div)-conforming FEs. */
|
||||
/** @brief Arbitrary order "H^{-1/2}-conforming" face finite elements defined on
|
||||
the interface between mesh elements (faces); these are the normal trace FEs
|
||||
of the H(div)-conforming FEs. */
|
||||
class RT_Trace_FECollection : public RT_FECollection
|
||||
{
|
||||
public:
|
||||
@@ -291,9 +357,9 @@ public:
|
||||
virtual ~ND_FECollection();
|
||||
};
|
||||
|
||||
/** Arbitrary order H(curl)-trace finite elements defined on the interface
|
||||
between mesh elements (faces,edges); these are the tangential trace FEs of
|
||||
the H(curl)-conforming FEs. */
|
||||
/** @brief Arbitrary order H(curl)-trace finite elements defined on the
|
||||
interface between mesh elements (faces,edges); these are the tangential
|
||||
trace FEs of the H(curl)-conforming FEs. */
|
||||
class ND_Trace_FECollection : public ND_FECollection
|
||||
{
|
||||
public:
|
||||
@@ -358,7 +424,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/// Piecewise-(bi)linear continuous finite elements.
|
||||
/// Piecewise-(bi/tri)linear continuous finite elements.
|
||||
class LinearFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -514,8 +580,8 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/** First order Raviart-Thomas finite elements in 2D. This class is kept only
|
||||
for backward compatibility, consider using RT_FECollection instead. */
|
||||
/** @brief First order Raviart-Thomas finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT0_2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -538,8 +604,8 @@ public:
|
||||
virtual int GetContType() const { return NORMAL; }
|
||||
};
|
||||
|
||||
/** Second order Raviart-Thomas finite elements in 2D. This class is kept only
|
||||
for backward compatibility, consider using RT_FECollection instead. */
|
||||
/** @brief Second order Raviart-Thomas finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT1_2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -562,8 +628,8 @@ public:
|
||||
virtual int GetContType() const { return NORMAL; }
|
||||
};
|
||||
|
||||
/** Third order Raviart-Thomas finite elements in 2D. This class is kept only
|
||||
for backward compatibility, consider using RT_FECollection instead. */
|
||||
/** @brief Third order Raviart-Thomas finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT2_2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -586,8 +652,9 @@ public:
|
||||
virtual int GetContType() const { return NORMAL; }
|
||||
};
|
||||
|
||||
/** Piecewise-constant discontinuous finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-constant discontinuous finite elements in 2D. This class is
|
||||
kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class Const2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -609,8 +676,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-linear discontinuous finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-linear discontinuous finite elements in 2D. This class is
|
||||
kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class LinearDiscont2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -673,8 +741,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-quadratic discontinuous finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-quadratic discontinuous finite elements in 2D. This class
|
||||
is kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class QuadraticDiscont2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -737,8 +806,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-cubic discontinuous finite elements in 2D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-cubic discontinuous finite elements in 2D. This class is
|
||||
kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class CubicDiscont2DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -760,8 +830,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-constant discontinuous finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-constant discontinuous finite elements in 3D. This class is
|
||||
kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class Const3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -784,8 +855,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-linear discontinuous finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-linear discontinuous finite elements in 3D. This class is
|
||||
kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class LinearDiscont3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -807,8 +879,9 @@ public:
|
||||
virtual int GetContType() const { return DISCONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Piecewise-quadratic discontinuous finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using L2_FECollection instead. */
|
||||
/** @brief Piecewise-quadratic discontinuous finite elements in 3D. This class
|
||||
is kept only for backward compatibility, consider using L2_FECollection
|
||||
instead. */
|
||||
class QuadraticDiscont3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -856,8 +929,9 @@ public:
|
||||
virtual int GetContType() const { return CONTINUOUS; }
|
||||
};
|
||||
|
||||
/** Lowest order Nedelec finite elements in 3D. This class is kept only for
|
||||
backward compatibility, consider using the new ND_FECollection instead. */
|
||||
/** @brief Lowest order Nedelec finite elements in 3D. This class is kept only
|
||||
for backward compatibility, consider using the new ND_FECollection
|
||||
instead. */
|
||||
class ND1_3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -879,8 +953,8 @@ public:
|
||||
virtual int GetContType() const { return TANGENTIAL; }
|
||||
};
|
||||
|
||||
/** First order Raviart-Thomas finite elements in 3D. This class is kept only
|
||||
for backward compatibility, consider using RT_FECollection instead. */
|
||||
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT0_3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
@@ -903,8 +977,8 @@ public:
|
||||
virtual int GetContType() const { return NORMAL; }
|
||||
};
|
||||
|
||||
/** Second order Raviart-Thomas finite elements in 3D. This class is kept only
|
||||
for backward compatibility, consider using RT_FECollection instead. */
|
||||
/** @brief Second order Raviart-Thomas finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT1_3DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
|
||||
+170
-46
@@ -60,7 +60,7 @@ FiniteElementSpace::FiniteElementSpace()
|
||||
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
|
||||
fdofs(NULL), bdofs(NULL),
|
||||
elem_dof(NULL), bdrElem_dof(NULL),
|
||||
elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
cP(NULL), cR(NULL), cP_is_set(false),
|
||||
Th(Operator::ANY_TYPE),
|
||||
@@ -233,6 +233,54 @@ void FiniteElementSpace::BuildElementToDofTable() const
|
||||
elem_dof = el_dof;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildBdrElementToDofTable() const
|
||||
{
|
||||
if (bdrElem_dof) { return; }
|
||||
|
||||
Table *bel_dof = new Table;
|
||||
Array<int> dofs;
|
||||
bel_dof->MakeI(mesh->GetNBE());
|
||||
for (int i = 0; i < mesh->GetNBE(); i++)
|
||||
{
|
||||
GetBdrElementDofs(i, dofs);
|
||||
bel_dof->AddColumnsInRow(i, dofs.Size());
|
||||
}
|
||||
bel_dof->MakeJ();
|
||||
for (int i = 0; i < mesh->GetNBE(); i++)
|
||||
{
|
||||
GetBdrElementDofs(i, dofs);
|
||||
bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
|
||||
}
|
||||
bel_dof->ShiftUpI();
|
||||
bdrElem_dof = bel_dof;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildFaceToDofTable() const
|
||||
{
|
||||
// Here, "face" == (dim-1)-dimensional mesh entity.
|
||||
|
||||
if (face_dof) { return; }
|
||||
|
||||
if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
|
||||
|
||||
Table *fc_dof = new Table;
|
||||
Array<int> dofs;
|
||||
fc_dof->MakeI(mesh->GetNumFaces());
|
||||
for (int i = 0; i < fc_dof->Size(); i++)
|
||||
{
|
||||
GetFaceDofs(i, dofs);
|
||||
fc_dof->AddColumnsInRow(i, dofs.Size());
|
||||
}
|
||||
fc_dof->MakeJ();
|
||||
for (int i = 0; i < fc_dof->Size(); i++)
|
||||
{
|
||||
GetFaceDofs(i, dofs);
|
||||
fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
|
||||
}
|
||||
fc_dof->ShiftUpI();
|
||||
face_dof = fc_dof;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::RebuildElementToDofTable()
|
||||
{
|
||||
delete elem_dof;
|
||||
@@ -1456,6 +1504,7 @@ void FiniteElementSpace::Constructor(Mesh *mesh, NURBSExtension *NURBSext,
|
||||
this->ordering = (Ordering::Type) ordering;
|
||||
|
||||
elem_dof = NULL;
|
||||
face_dof = NULL;
|
||||
sequence = mesh->GetSequence();
|
||||
Th.SetType(Operator::ANY_TYPE);
|
||||
|
||||
@@ -1505,6 +1554,8 @@ NURBSExtension *FiniteElementSpace::StealNURBSext()
|
||||
|
||||
void FiniteElementSpace::UpdateNURBS()
|
||||
{
|
||||
MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
|
||||
|
||||
nvdofs = 0;
|
||||
nedofs = 0;
|
||||
nfdofs = 0;
|
||||
@@ -1512,6 +1563,10 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
fdofs = NULL;
|
||||
bdofs = NULL;
|
||||
|
||||
delete face_dof;
|
||||
face_dof = NULL;
|
||||
face_to_be.DeleteAll();
|
||||
|
||||
dynamic_cast<const NURBSFECollection *>(fec)->Reset();
|
||||
|
||||
ndofs = NURBSext->GetNDof();
|
||||
@@ -1519,6 +1574,55 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
bdrElem_dof = NURBSext->GetBdrElementDofTable();
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildNURBSFaceToDofTable() const
|
||||
{
|
||||
if (face_dof) { return; }
|
||||
|
||||
const int dim = mesh->Dimension();
|
||||
|
||||
// Find bdr to face mapping
|
||||
face_to_be.SetSize(GetNF());
|
||||
face_to_be = -1;
|
||||
for (int b = 0; b < GetNBE(); b++)
|
||||
{
|
||||
int f = mesh->GetBdrElementEdgeIndex(b);
|
||||
face_to_be[f] = b;
|
||||
}
|
||||
|
||||
// Loop over faces in correct order, to prevent a sort
|
||||
// Sort will destroy orientation info in ordering of dofs
|
||||
Array<Connection> face_dof_list;
|
||||
Array<int> row;
|
||||
for (int f = 0; f < GetNF(); f++)
|
||||
{
|
||||
int b = face_to_be[f];
|
||||
if (b == -1) { continue; }
|
||||
// FIXME: this assumes the boundary element and the face element have the
|
||||
// same orientation.
|
||||
if (dim > 1)
|
||||
{
|
||||
const Element *fe = mesh->GetFace(f);
|
||||
const Element *be = mesh->GetBdrElement(b);
|
||||
const int nv = be->GetNVertices();
|
||||
const int *fv = fe->GetVertices();
|
||||
const int *bv = be->GetVertices();
|
||||
for (int i = 0; i < nv; i++)
|
||||
{
|
||||
MFEM_VERIFY(fv[i] == bv[i],
|
||||
"non-matching face and boundary elements detected!");
|
||||
}
|
||||
}
|
||||
GetBdrElementDofs(b, row);
|
||||
Connection conn(f,0);
|
||||
for (int i = 0; i < row.Size(); i++)
|
||||
{
|
||||
conn.to = row[i];
|
||||
face_dof_list.Append(conn);
|
||||
}
|
||||
}
|
||||
face_dof = new Table(GetNF(), face_dof_list);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::Construct()
|
||||
{
|
||||
// This method should be used only for non-NURBS spaces.
|
||||
@@ -1526,6 +1630,7 @@ void FiniteElementSpace::Construct()
|
||||
|
||||
elem_dof = NULL;
|
||||
bdrElem_dof = NULL;
|
||||
face_dof = NULL;
|
||||
|
||||
ndofs = 0;
|
||||
nedofs = nfdofs = nbdofs = 0;
|
||||
@@ -1788,59 +1893,68 @@ void FiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
|
||||
|
||||
void FiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
|
||||
Array<int> V, E, Eo;
|
||||
const int *ind;
|
||||
// If face_dof is already built, use it.
|
||||
// If it is not and we have a NURBS space, build the face_dof and use it.
|
||||
if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true)))
|
||||
{
|
||||
face_dof->GetRow(i, dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
|
||||
Array<int> V, E, Eo;
|
||||
const int *ind;
|
||||
|
||||
// for 1D, 2D and 3D faces
|
||||
nv = fec->DofForGeometry(Geometry::POINT);
|
||||
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
|
||||
if (nv > 0)
|
||||
{
|
||||
mesh->GetFaceVertices(i, V);
|
||||
}
|
||||
if (ne > 0)
|
||||
{
|
||||
mesh->GetFaceEdges(i, E, Eo);
|
||||
}
|
||||
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
|
||||
nd = V.Size() * nv + E.Size() * ne + nf;
|
||||
dofs.SetSize(nd);
|
||||
if (nv > 0)
|
||||
{
|
||||
for (k = 0; k < V.Size(); k++)
|
||||
// for 1D, 2D and 3D faces
|
||||
nv = fec->DofForGeometry(Geometry::POINT);
|
||||
ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
|
||||
if (nv > 0)
|
||||
{
|
||||
for (j = 0; j < nv; j++)
|
||||
{
|
||||
dofs[k*nv+j] = V[k]*nv+j;
|
||||
}
|
||||
mesh->GetFaceVertices(i, V);
|
||||
}
|
||||
}
|
||||
nv *= V.Size();
|
||||
if (ne > 0)
|
||||
{
|
||||
for (k = 0; k < E.Size(); k++)
|
||||
if (ne > 0)
|
||||
{
|
||||
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
|
||||
for (j = 0; j < ne; j++)
|
||||
mesh->GetFaceEdges(i, E, Eo);
|
||||
}
|
||||
nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
|
||||
nd = V.Size() * nv + E.Size() * ne + nf;
|
||||
dofs.SetSize(nd);
|
||||
if (nv > 0)
|
||||
{
|
||||
for (k = 0; k < V.Size(); k++)
|
||||
{
|
||||
if (ind[j] < 0)
|
||||
for (j = 0; j < nv; j++)
|
||||
{
|
||||
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
|
||||
dofs[k*nv+j] = V[k]*nv+j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ne = nv + ne * E.Size();
|
||||
if (nf > 0)
|
||||
{
|
||||
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
|
||||
nv *= V.Size();
|
||||
if (ne > 0)
|
||||
{
|
||||
dofs[ne+k] = j;
|
||||
for (k = 0; k < E.Size(); k++)
|
||||
{
|
||||
ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[k]);
|
||||
for (j = 0; j < ne; j++)
|
||||
{
|
||||
if (ind[j] < 0)
|
||||
{
|
||||
dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
|
||||
}
|
||||
else
|
||||
{
|
||||
dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ne = nv + ne * E.Size();
|
||||
if (nf > 0)
|
||||
{
|
||||
for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
|
||||
{
|
||||
dofs[ne+k] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1969,14 +2083,21 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
|
||||
fe = fec->FiniteElementForGeometry(mesh->GetFaceBaseGeometry(i));
|
||||
}
|
||||
|
||||
// if (NURBSext)
|
||||
// NURBSext->LoadFaceElement(i, fe);
|
||||
if (NURBSext)
|
||||
{
|
||||
// Ensure 'face_to_be' is built:
|
||||
if (!face_dof) { BuildNURBSFaceToDofTable(); }
|
||||
MFEM_ASSERT(face_to_be[i] >= 0,
|
||||
"NURBS mesh: only boundary faces are supported!");
|
||||
NURBSext->LoadBE(face_to_be[i], fe);
|
||||
}
|
||||
|
||||
return fe;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i) const
|
||||
{
|
||||
MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2");
|
||||
return fec->FiniteElementForGeometry(Geometry::SEGMENT);
|
||||
}
|
||||
|
||||
@@ -2024,11 +2145,14 @@ void FiniteElementSpace::Destroy()
|
||||
if (NURBSext)
|
||||
{
|
||||
if (own_ext) { delete NURBSext; }
|
||||
delete face_dof;
|
||||
face_to_be.DeleteAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete elem_dof;
|
||||
delete bdrElem_dof;
|
||||
delete face_dof;
|
||||
|
||||
delete [] bdofs;
|
||||
delete [] fdofs;
|
||||
|
||||
+73
-29
@@ -111,7 +111,9 @@ protected:
|
||||
int *fdofs, *bdofs;
|
||||
|
||||
mutable Table *elem_dof; // if NURBS FE space, not owned; otherwise, owned.
|
||||
Table *bdrElem_dof; // used only with NURBS FE spaces; not owned.
|
||||
mutable Table *bdrElem_dof; // not owned only if NURBS FE space.
|
||||
mutable Table *face_dof; // owned
|
||||
mutable Array<int> face_to_be; // used only with NURBS FE spaces; owned.
|
||||
|
||||
Array<int> dof_elem_array, dof_ldof_array;
|
||||
|
||||
@@ -158,6 +160,14 @@ protected:
|
||||
void Destroy();
|
||||
|
||||
void BuildElementToDofTable() const;
|
||||
void BuildBdrElementToDofTable() const;
|
||||
void BuildFaceToDofTable() const;
|
||||
|
||||
/** @brief Generates partial face_dof table for a NURBS space.
|
||||
|
||||
The table is only defined for exterior faces that coincide with a
|
||||
boundary. */
|
||||
void BuildNURBSFaceToDofTable() const;
|
||||
|
||||
/// Helpers to remove encoded sign from a DOF
|
||||
static inline int DecodeDof(int dof)
|
||||
@@ -206,7 +216,7 @@ protected:
|
||||
virtual ~RefinementOperator();
|
||||
};
|
||||
|
||||
// Derefinement operator, used by the friend class InterpolationGridTransfer.
|
||||
/// Derefinement operator, used by the friend class InterpolationGridTransfer.
|
||||
class DerefinementOperator : public Operator
|
||||
{
|
||||
const FiniteElementSpace *fine_fes; // Not owned.
|
||||
@@ -225,12 +235,12 @@ protected:
|
||||
virtual ~DerefinementOperator();
|
||||
};
|
||||
|
||||
// This method makes the same assumptions as the method:
|
||||
// void GetLocalRefinementMatrices(
|
||||
// const FiniteElementSpace &coarse_fes, Geometry::Type geom,
|
||||
// DenseTensor &localP) const
|
||||
// which is defined below. It also assumes that the coarse fes and this have
|
||||
// the same vector dimension, vdim.
|
||||
/** This method makes the same assumptions as the method:
|
||||
void GetLocalRefinementMatrices(
|
||||
const FiniteElementSpace &coarse_fes, Geometry::Type geom,
|
||||
DenseTensor &localP) const
|
||||
which is defined below. It also assumes that the coarse fes and this have
|
||||
the same vector dimension, vdim. */
|
||||
SparseMatrix *RefinementMatrix_main(const int coarse_ndofs,
|
||||
const Table &coarse_elem_dof,
|
||||
const DenseTensor localP[]) const;
|
||||
@@ -248,11 +258,13 @@ protected:
|
||||
/// Calculate GridFunction restriction matrix after mesh derefinement.
|
||||
SparseMatrix* DerefinementMatrix(int old_ndofs, const Table* old_elem_dof);
|
||||
|
||||
// This method assumes that this->mesh is a refinement of coarse_fes->mesh
|
||||
// and that the CoarseFineTransformations of this->mesh are set accordingly.
|
||||
// Another assumption is that the FEs of this use the same MapType as the FEs
|
||||
// of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
|
||||
// NOT variable-order spaces.
|
||||
/** @brief Return in @a localP the local refinement matrices that map
|
||||
between fespaces after mesh refinement. */
|
||||
/** This method assumes that this->mesh is a refinement of coarse_fes->mesh
|
||||
and that the CoarseFineTransformations of this->mesh are set accordingly.
|
||||
Another assumption is that the FEs of this use the same MapType as the FEs
|
||||
of coarse_fes. Finally, it assumes that the spaces this and coarse_fes are
|
||||
NOT variable-order spaces. */
|
||||
void GetLocalRefinementMatrices(const FiniteElementSpace &coarse_fes,
|
||||
Geometry::Type geom,
|
||||
DenseTensor &localP) const;
|
||||
@@ -467,11 +479,11 @@ public:
|
||||
/// Returns indexes of degrees of freedom for i'th boundary element.
|
||||
virtual void GetBdrElementDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/** Returns the indexes of the degrees of freedom for i'th face
|
||||
/** @brief eturns the indexes of the degrees of freedom for i'th face
|
||||
including the dofs for the edges and the vertices of the face. */
|
||||
virtual void GetFaceDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/** Returns the indexes of the degrees of freedom for i'th edge
|
||||
/** @brief Returns the indexes of the degrees of freedom for i'th edge
|
||||
including the dofs for the vertices of the edge. */
|
||||
void GetEdgeDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
@@ -526,28 +538,59 @@ public:
|
||||
is preserved. */
|
||||
void ReorderElementToDofTable();
|
||||
|
||||
/** @brief Return a reference to the internal Table that stores the lists of
|
||||
scalar dofs, for each mesh element, as returned by GetElementDofs(). */
|
||||
const Table &GetElementToDofTable() const { return *elem_dof; }
|
||||
|
||||
/** @brief Return a reference to the internal Table that stores the lists of
|
||||
scalar dofs, for each boundary mesh element, as returned by
|
||||
GetBdrElementDofs(). */
|
||||
const Table &GetBdrElementToDofTable() const
|
||||
{ if (!bdrElem_dof) { BuildBdrElementToDofTable(); } return *bdrElem_dof; }
|
||||
|
||||
/** @brief Return a reference to the internal Table that stores the lists of
|
||||
scalar dofs, for each face in the mesh, as returned by GetFaceDofs(). In
|
||||
this context, "face" refers to a (dim-1)-dimensional mesh entity. */
|
||||
/** @note In the case of a NURBS space, the rows corresponding to interior
|
||||
faces will be empty. */
|
||||
const Table &GetFaceToDofTable() const
|
||||
{ if (!face_dof) { BuildFaceToDofTable(); } return *face_dof; }
|
||||
|
||||
/** @brief Initialize internal data that enables the use of the methods
|
||||
GetElementForDof() and GetLocalDofForDof(). */
|
||||
void BuildDofToArrays();
|
||||
|
||||
const Table &GetElementToDofTable() const { return *elem_dof; }
|
||||
const Table &GetBdrElementToDofTable() const { return *bdrElem_dof; }
|
||||
|
||||
/// Return the index of the first element that contains dof @a i.
|
||||
/** This method can be called only after setup is performed using the method
|
||||
BuildDofToArrays(). */
|
||||
int GetElementForDof(int i) const { return dof_elem_array[i]; }
|
||||
/// Return the local dof index in the first element that contains dof @a i.
|
||||
/** This method can be called only after setup is performed using the method
|
||||
BuildDofToArrays(). */
|
||||
int GetLocalDofForDof(int i) const { return dof_ldof_array[i]; }
|
||||
|
||||
/// Returns pointer to the FiniteElement associated with i'th element.
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th element in the mesh object. */
|
||||
const FiniteElement *GetFE(int i) const;
|
||||
|
||||
/// Returns pointer to the FiniteElement for the i'th boundary element.
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th boundary face in the mesh object. */
|
||||
const FiniteElement *GetBE(int i) const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th face in the mesh object. Faces in this case refer
|
||||
to the MESHDIM-1 primitive so in 2D they are segments and in 1D they are
|
||||
points.*/
|
||||
const FiniteElement *GetFaceElement(int i) const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th edge in the mesh object. */
|
||||
const FiniteElement *GetEdgeElement(int i) const;
|
||||
|
||||
/// Return the trace element from element 'i' to the given 'geom_type'
|
||||
const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const;
|
||||
|
||||
/** Mark degrees of freedom associated with boundary elements with
|
||||
/** @brief Mark degrees of freedom associated with boundary elements with
|
||||
the specified boundary attributes (marked in 'bdr_attr_is_ess').
|
||||
For spaces with 'vdim' > 1, the 'component' parameter can be used
|
||||
to restricts the marked vDOFs to the specified component. */
|
||||
@@ -555,7 +598,7 @@ public:
|
||||
Array<int> &ess_vdofs,
|
||||
int component = -1) const;
|
||||
|
||||
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
|
||||
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
|
||||
boundary attributes marked in the array bdr_attr_is_ess.
|
||||
For spaces with 'vdim' > 1, the 'component' parameter can be used
|
||||
to restricts the marked tDOFs to the specified component. */
|
||||
@@ -566,19 +609,19 @@ public:
|
||||
/// Convert a Boolean marker array to a list containing all marked indices.
|
||||
static void MarkerToList(const Array<int> &marker, Array<int> &list);
|
||||
|
||||
/** Convert an array of indices (list) to a Boolean marker array where all
|
||||
/** @brief Convert an array of indices (list) to a Boolean marker array where all
|
||||
indices in the list are marked with the given value and the rest are set
|
||||
to zero. */
|
||||
static void ListToMarker(const Array<int> &list, int marker_size,
|
||||
Array<int> &marker, int mark_val = -1);
|
||||
|
||||
/** For a partially conforming FE space, convert a marker array (nonzero
|
||||
/** @brief For a partially conforming FE space, convert a marker array (nonzero
|
||||
entries are true) on the partially conforming dofs to a marker array on
|
||||
the conforming dofs. A conforming dofs is marked iff at least one of its
|
||||
dependent dofs is marked. */
|
||||
void ConvertToConformingVDofs(const Array<int> &dofs, Array<int> &cdofs);
|
||||
|
||||
/** For a partially conforming FE space, convert a marker array (nonzero
|
||||
/** @brief For a partially conforming FE space, convert a marker array (nonzero
|
||||
entries are true) on the conforming dofs to a marker array on the
|
||||
(partially conforming) dofs. A dof is marked iff it depends on a marked
|
||||
conforming dofs, where dependency is defined by the ConformingRestriction
|
||||
@@ -586,15 +629,15 @@ public:
|
||||
conforming dof. */
|
||||
void ConvertFromConformingVDofs(const Array<int> &cdofs, Array<int> &dofs);
|
||||
|
||||
/** Generate the global restriction matrix from a discontinuous
|
||||
/** @brief Generate the global restriction matrix from a discontinuous
|
||||
FE space to the continuous FE space of the same polynomial degree. */
|
||||
SparseMatrix *D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
|
||||
|
||||
/** Generate the global restriction matrix from a discontinuous
|
||||
/** @brief Generate the global restriction matrix from a discontinuous
|
||||
FE space to the piecewise constant FE space. */
|
||||
SparseMatrix *D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes);
|
||||
|
||||
/** Construct the restriction matrix from the FE space given by
|
||||
/** @brief Construct the restriction matrix from the FE space given by
|
||||
(*this) to the lower degree FE space given by (*lfes) which
|
||||
is defined on the same mesh. */
|
||||
SparseMatrix *H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes);
|
||||
@@ -631,7 +674,7 @@ public:
|
||||
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes,
|
||||
OperatorHandle &T) const;
|
||||
|
||||
/** Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
|
||||
/** @brief Reflect changes in the mesh: update number of DOFs, etc. Also, calculate
|
||||
GridFunction transformation operator (unless want_transform is false).
|
||||
Safe to call multiple times, does nothing if space already up to date. */
|
||||
virtual void Update(bool want_transform = true);
|
||||
@@ -669,6 +712,7 @@ public:
|
||||
return dynamic_cast<const L2_FECollection*>(fec) != NULL;
|
||||
}
|
||||
|
||||
/// Save finite element space to output stream @a out.
|
||||
void Save(std::ostream &out) const;
|
||||
|
||||
/** @brief Read a FiniteElementSpace from a stream. The returned
|
||||
|
||||
+2
-2
@@ -1031,13 +1031,13 @@ int GridFunction::GetFaceVectorValues(
|
||||
}
|
||||
if (di == 0)
|
||||
{
|
||||
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
|
||||
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
|
||||
Transf->Loc1.Transform(ir, eir);
|
||||
GetVectorValues(*Transf->Elem1, eir, vals, &tr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
|
||||
Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
|
||||
Transf->Loc2.Transform(ir, eir);
|
||||
GetVectorValues(*Transf->Elem2, eir, vals, &tr);
|
||||
}
|
||||
|
||||
+4
-2
@@ -598,11 +598,13 @@ public:
|
||||
type = adios2stream::data_type::point_data) const;
|
||||
#endif
|
||||
|
||||
/** Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be
|
||||
called first. The parameter ref > 0 must match the one used in
|
||||
/** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK
|
||||
must be called first. The parameter ref > 0 must match the one used in
|
||||
Mesh::PrintVTK. */
|
||||
void SaveVTK(std::ostream &out, const std::string &field_name, int ref);
|
||||
|
||||
/** @brief Write the GridFunction in STL format. Note that the mesh dimension
|
||||
must be 2 and that quad elements will be broken into two triangles.*/
|
||||
void SaveSTL(std::ostream &out, int TimesToRefine = 1);
|
||||
|
||||
/// Destroys grid function.
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Class for linear form - Vector with associated FE space and LFIntegrators.
|
||||
/// Vector with associated FE space and LinearFormIntegrators.
|
||||
class LinearForm : public Vector
|
||||
{
|
||||
protected:
|
||||
|
||||
+166
-7
@@ -63,6 +63,53 @@ void DomainLFIntegrator::AssembleDeltaElementVect(
|
||||
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
||||
}
|
||||
|
||||
void DomainLFGradIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int spaceDim = Tr.GetSpaceDim();
|
||||
|
||||
dshape.SetSize(dof, spaceDim);
|
||||
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2 * el.GetOrder();
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetIntPoint(&ip);
|
||||
el.CalcPhysDShape(Tr, dshape);
|
||||
|
||||
Q.Eval(Qvec, Tr, ip);
|
||||
Qvec *= ip.weight * Tr.Weight();
|
||||
|
||||
dshape.AddMult(Qvec, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainLFGradIntegrator::AssembleDeltaElementVect(
|
||||
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
||||
{
|
||||
MFEM_ASSERT(vec_delta != NULL,"coefficient must be VectorDeltaCoefficient");
|
||||
int dof = fe.GetDof();
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
|
||||
dshape.SetSize(dof, spaceDim);
|
||||
fe.CalcPhysDShape(Trans, dshape);
|
||||
|
||||
vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint());
|
||||
|
||||
elvect.SetSize(dof);
|
||||
dshape.Mult(Qvec, elvect);
|
||||
}
|
||||
|
||||
void BoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
@@ -255,7 +302,6 @@ void VectorDomainLFIntegrator::AssembleDeltaElementVect(
|
||||
MultVWt(shape, Qvec, elvec_as_mat);
|
||||
}
|
||||
|
||||
|
||||
void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -332,7 +378,6 @@ void VectorBoundaryLFIntegrator::AssembleRHSElementVect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -362,7 +407,6 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
|
||||
|
||||
QF.Eval (vec, Tr, ip);
|
||||
vec *= ip.weight * Tr.Weight();
|
||||
|
||||
vshape.AddMult (vec, elvect);
|
||||
}
|
||||
}
|
||||
@@ -383,6 +427,125 @@ void VectorFEDomainLFIntegrator::AssembleDeltaElementVect(
|
||||
vshape.Mult(vec, elvect);
|
||||
}
|
||||
|
||||
void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int spaceDim = Tr.GetSpaceDim();
|
||||
int n=(spaceDim == 3)? spaceDim : 1;
|
||||
curlshape.SetSize(dof,n);
|
||||
vec.SetSize(n);
|
||||
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
el.CalcPhysCurlShape(Tr, curlshape);
|
||||
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_VERIFY(QF, "VectorFunctionCoefficient not provided");
|
||||
QF->Eval(vec, Tr, ip);
|
||||
break;
|
||||
case 2:
|
||||
MFEM_VERIFY(Q, "FunctionCoefficient (Scalar) not provided");
|
||||
vec[0] = Q->Eval(Tr, ip);
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
vec *= ip.weight * Tr.Weight();
|
||||
curlshape.AddMult (vec, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
|
||||
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
||||
{
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
MFEM_ASSERT(vec_delta != NULL,
|
||||
"coefficient must be VectorDeltaCoefficient");
|
||||
break;
|
||||
case 2:
|
||||
MFEM_ASSERT(delta != NULL,
|
||||
"coefficient must be DeltaCoefficient");
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
int dof = fe.GetDof();
|
||||
int n=(spaceDim == 3)? spaceDim : 1;
|
||||
curlshape.SetSize(dof, n);
|
||||
elvect.SetSize(dof);
|
||||
fe.CalcPhysCurlShape(Trans, curlshape);
|
||||
|
||||
switch (spaceDim)
|
||||
{
|
||||
case 3:
|
||||
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
||||
curlshape.Mult(vec, elvect);
|
||||
break;
|
||||
case 2:
|
||||
curlshape.GetColumn(0,elvect);
|
||||
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
||||
break;
|
||||
default:
|
||||
break; // This should be unreachable
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
|
||||
divshape.SetSize(dof); // vector of size dof
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2 * el.GetOrder();
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Tr.SetIntPoint (&ip);
|
||||
double val = Tr.Weight() * Q.Eval(Tr, ip);
|
||||
el.CalcPhysDivShape(Tr, divshape);
|
||||
|
||||
add(elvect, ip.weight * val, divshape, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFEDomainLFDivIntegrator::AssembleDeltaElementVect(
|
||||
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
||||
{
|
||||
MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient");
|
||||
elvect.SetSize(fe.GetDof());
|
||||
fe.CalcPhysDivShape(Trans, elvect);
|
||||
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
||||
}
|
||||
|
||||
void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -448,7 +611,6 @@ void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -483,7 +645,6 @@ void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BoundaryFlowIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -548,7 +709,6 @@ void BoundaryFlowIntegrator::AssembleRHSElementVect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DGDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
@@ -637,7 +797,6 @@ void DGDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect(
|
||||
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
||||
{
|
||||
|
||||
+78
-1
@@ -119,6 +119,33 @@ public:
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/// Class for domain integrator L(v) := (f, grad v)
|
||||
class DomainLFGradIntegrator : public DeltaLFIntegrator
|
||||
{
|
||||
private:
|
||||
Vector shape, Qvec;
|
||||
VectorCoefficient &Q;
|
||||
DenseMatrix dshape;
|
||||
|
||||
public:
|
||||
/// Constructs the domain integrator (Q, grad v)
|
||||
DomainLFGradIntegrator(VectorCoefficient &QF)
|
||||
: DeltaLFIntegrator(QF), Q(QF) { }
|
||||
|
||||
/** Given a particular Finite Element and a transformation (Tr)
|
||||
computes the element right hand side element vector, elvect. */
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
Vector &elvect);
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
|
||||
/// Class for boundary integration L(v) := (g, v)
|
||||
class BoundaryLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
@@ -252,6 +279,56 @@ public:
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/// \f$ (Q, curl v)_{\Omega} \f$ for Nedelec Elements)
|
||||
class VectorFEDomainLFCurlIntegrator : public DeltaLFIntegrator
|
||||
{
|
||||
private:
|
||||
VectorCoefficient *QF=nullptr;
|
||||
Coefficient *Q=nullptr;
|
||||
DenseMatrix curlshape;
|
||||
Vector vec;
|
||||
|
||||
public:
|
||||
/// Constructs the domain integrator (Q, curl v)
|
||||
VectorFEDomainLFCurlIntegrator(VectorCoefficient &F)
|
||||
: DeltaLFIntegrator(F), QF(&F) { }
|
||||
VectorFEDomainLFCurlIntegrator(Coefficient &F)
|
||||
: DeltaLFIntegrator(F), Q(&F) { }
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
Vector &elvect);
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/// \f$ (Q, div v)_{\Omega} \f$ for RT Elements)
|
||||
class VectorFEDomainLFDivIntegrator : public DeltaLFIntegrator
|
||||
{
|
||||
private:
|
||||
Vector divshape;
|
||||
Coefficient &Q;
|
||||
public:
|
||||
/// Constructs the domain integrator (Q, div v)
|
||||
VectorFEDomainLFDivIntegrator(Coefficient &QF)
|
||||
: DeltaLFIntegrator(QF), Q(QF) { }
|
||||
|
||||
/** Given a particular Finite Element and a transformation (Tr)
|
||||
computes the element right hand side element vector, elvect. */
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
virtual void AssembleDeltaElementVect(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
Vector &elvect);
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
/** \f$ (f, v \cdot n)_{\partial\Omega} \f$ for vector test function
|
||||
v=(v1,...,vn) where all vi are in the same scalar FE space and f is a
|
||||
@@ -283,7 +360,7 @@ class VectorFEBoundaryFluxLFIntegrator : public LinearFormIntegrator
|
||||
private:
|
||||
Coefficient *F;
|
||||
Vector shape;
|
||||
int oa, ob; // these contol the quadrature order, see DomainLFIntegrator
|
||||
int oa, ob; // these control the quadrature order, see DomainLFIntegrator
|
||||
|
||||
public:
|
||||
VectorFEBoundaryFluxLFIntegrator(int a = 1, int b = -1)
|
||||
|
||||
+3
-4
@@ -20,10 +20,9 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/** The abstract base class NonlinearFormIntegrator is used to express the
|
||||
local action of a general nonlinear finite element operator. In addition
|
||||
it may provide the capability to assemble the local gradient operator
|
||||
and to compute the local energy. */
|
||||
/** @brief This class is used to express the local action of a general nonlinear
|
||||
finite element operator. In addition it may provide the capability to
|
||||
assemble the local gradient operator and to compute the local energy. */
|
||||
class NonlinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
|
||||
+12
-4
@@ -487,6 +487,11 @@ void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
|
||||
|
||||
void ParFiniteElementSpace::GetFaceDofs(int i, Array<int> &dofs) const
|
||||
{
|
||||
if (face_dof)
|
||||
{
|
||||
face_dof->GetRow(i, dofs);
|
||||
return;
|
||||
}
|
||||
FiniteElementSpace::GetFaceDofs(i, dofs);
|
||||
if (Conforming())
|
||||
{
|
||||
@@ -1167,7 +1172,7 @@ void ParFiniteElementSpace::GetFaceNbrFaceVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
// Works for NC mesh where 'i' is an index returned by
|
||||
// ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
|
||||
// the index of a ghost.
|
||||
// the index of a ghost face.
|
||||
MFEM_ASSERT(Nonconforming() && i >= pmesh->GetNumFaces(), "");
|
||||
int el1, el2, inf1, inf2;
|
||||
pmesh->GetFaceElements(i, &el1, &el2);
|
||||
@@ -1207,11 +1212,14 @@ const FiniteElement *ParFiniteElementSpace::GetFaceNbrFE(int i) const
|
||||
|
||||
const FiniteElement *ParFiniteElementSpace::GetFaceNbrFaceFE(int i) const
|
||||
{
|
||||
// Works for NC mesh where 'i' is an index returned by
|
||||
// ParMesh::GetSharedFace() such that i >= Mesh::GetNumFaces(), i.e. 'i' is
|
||||
// the index of a ghost face.
|
||||
// Works in tandem with GetFaceNbrFaceVDofs() defined above.
|
||||
|
||||
MFEM_ASSERT(Nonconforming() && !NURBSext, "");
|
||||
Geometry::Type geom = (pmesh->Dimension() == 2) ?
|
||||
Geometry::SEGMENT : Geometry::SQUARE;
|
||||
return fec->FiniteElementForGeometry(geom);
|
||||
Geometry::Type face_geom = pmesh->GetFaceGeometryType(i);
|
||||
return fec->FiniteElementForGeometry(face_geom);
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ public:
|
||||
|
||||
void PrintPartitionStats();
|
||||
|
||||
// Obsolete, kept for backward compatibility
|
||||
/// Obsolete, kept for backward compatibility
|
||||
int TrueVSize() const { return ltdof_size; }
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ void ParGridFunction::ExchangeFaceNbrData()
|
||||
ParMesh *pmesh = pfes->GetParMesh();
|
||||
|
||||
face_nbr_data.SetSize(pfes->GetFaceNbrVSize());
|
||||
Vector send_data(pfes->send_face_nbr_ldof.Size_of_connections());
|
||||
send_data.SetSize(pfes->send_face_nbr_ldof.Size_of_connections());
|
||||
|
||||
int *send_offset = pfes->send_face_nbr_ldof.GetI();
|
||||
const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(),
|
||||
|
||||
@@ -38,6 +38,11 @@ protected:
|
||||
initialized by ExchangeFaceNbrData(). */
|
||||
Vector face_nbr_data;
|
||||
|
||||
/** @brief Vector used as an MPI buffer to send face-neighbor data
|
||||
in ExchangeFaceNbrData() to neighboring processors. */
|
||||
//TODO: Use temporary memory to avoid CUDA malloc allocation cost.
|
||||
Vector send_data;
|
||||
|
||||
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff,
|
||||
Array<int> &attr);
|
||||
|
||||
|
||||
@@ -150,6 +150,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 +161,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)
|
||||
{
|
||||
|
||||
@@ -495,8 +495,9 @@ void FaceQuadratureInterpolator::Mult(
|
||||
}
|
||||
}
|
||||
|
||||
void FaceQuadratureInterpolator::Values(
|
||||
const Vector &e_vec, Vector &q_val) const
|
||||
|
||||
void FaceQuadratureInterpolator::Values(const Vector &e_vec,
|
||||
Vector &q_val) const
|
||||
{
|
||||
Vector q_der, q_det, q_nor;
|
||||
Mult(e_vec, VALUES, q_val, q_der, q_det, q_nor);
|
||||
|
||||
+33
-10
@@ -24,10 +24,22 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Templated bilinear form class, cf. bilinearform.?pp
|
||||
/** @brief Templated bilinear form class, cf. bilinearform.?pp
|
||||
|
||||
// complex_t - sol dof data type
|
||||
@tparam meshType typically TMesh, which is templated on FE type
|
||||
// real_t - mesh nodes, sol basis, mesh basis data type
|
||||
@tparam solFESpace eg. H1_FiniteElementSpace
|
||||
@tparam IR integration rule, typically TIntegrationRule, which is further
|
||||
templated on element geometry
|
||||
@tparam IntegratorType typically a TIntegrator, which is templated on a
|
||||
kernel, eg. TDiffusionKernel or TMassKernel. This
|
||||
describes what actual problem you solve.
|
||||
@tparam solVecLayout_t describes how degrees of freedom are laid out,
|
||||
scalar or vector, column/row major, etc.
|
||||
@tparam complex_t data type for solution dofs
|
||||
@tparam real_t data type for mesh nodes, solution basis, and mesh basis
|
||||
*/
|
||||
template <typename meshType, typename solFESpace,
|
||||
typename IR, typename IntegratorType,
|
||||
typename solVecLayout_t = ScalarLayout,
|
||||
@@ -61,11 +73,19 @@ protected:
|
||||
typedef typename impl_traits_t::vcomplex_t vcomplex_t;
|
||||
typedef typename impl_traits_t::vreal_t vreal_t;
|
||||
|
||||
/// @name IntegratorType defines several internal types
|
||||
///@{
|
||||
typedef IntegratorType integ_t;
|
||||
/// coeff_t might be TConstantCoefficient or TFunctionCoefficient, for example
|
||||
typedef typename integ_t::coefficient_type coeff_t;
|
||||
/// kernel_t may be TDiffusionKernel or TMassKernel
|
||||
typedef typename integ_t::template kernel<sdim,dim,vcomplex_t>::type kernel_t;
|
||||
/// p_assembled_t is something like a TTensor or TMatrix for partial assembly
|
||||
typedef typename kernel_t::template p_asm_data<qpts>::type p_assembled_t;
|
||||
/// f_assembled_t is something like a TTensor or TMatrix for full assembly
|
||||
typedef typename kernel_t::template f_asm_data<qpts>::type f_assembled_t;
|
||||
///@}
|
||||
|
||||
typedef typename kernel_t::template
|
||||
CoefficientEval<IR,coeff_t,impl_traits_t>::Type coeff_eval_t;
|
||||
|
||||
@@ -80,6 +100,9 @@ protected:
|
||||
|
||||
typedef FieldEvaluator<solFESpace,solVecLayout_t,IR,
|
||||
complex_t,real_t> solFieldEval;
|
||||
|
||||
/** @brief Contains matrix sizes, type of kernel (ElementMatrix is templated
|
||||
on a kernel, e.g. ElementMatrix::Compute may be AssembleGradGrad()). */
|
||||
struct S_spec
|
||||
{
|
||||
typedef typename solFieldEval::template Spec<kernel_t,impl_traits_t> Spec;
|
||||
@@ -191,7 +214,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Partial assembly of quadrature point data
|
||||
/// Partial assembly of quadrature point data
|
||||
void Assemble()
|
||||
{
|
||||
Trans_t T(mesh, meshEval);
|
||||
@@ -276,8 +299,8 @@ public:
|
||||
typedef TTensor3<meshFE_type::dofs,sdim,BE,vreal_t> lnodes_t;
|
||||
|
||||
const int NE = mesh.GetNE();
|
||||
// TODO: How do we make sure that this array is aligned properly, AND
|
||||
// the compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready
|
||||
// TODO: How do we make sure that this array is aligned properly, AND the
|
||||
// compiler knows that it is aligned? => ALIGN_32|ALIGN_64 when ready
|
||||
const int NVE = (NE+TE-1)/TE;
|
||||
vreal_t *vsNodes = new vreal_t[lnodes_t::size*NVE];
|
||||
sNodes.NewDataAndSize(vsNodes[0].vec, (lnodes_t::size*SS)*NVE);
|
||||
@@ -291,7 +314,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// partial assembly from "serialized" nodes
|
||||
/// Partial assembly from "serialized" nodes
|
||||
// real_t = double
|
||||
void AssembleFromSerializedNodes(const Vector &sNodes)
|
||||
{
|
||||
@@ -343,7 +366,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// serialized vector sx --> serialized vector 'sy'
|
||||
/// serialized vector sx --> serialized vector 'sy'
|
||||
// complex_t = double
|
||||
void MultAssembledSerialized(const Vector &sx, Vector &sy) const
|
||||
{
|
||||
@@ -371,7 +394,7 @@ public:
|
||||
}
|
||||
#endif // MFEM_TEMPLATE_ENABLE_SERIALIZE
|
||||
|
||||
// Assemble the operator in a SparseMatrix.
|
||||
/// Assemble the operator in a SparseMatrix.
|
||||
// complex_t = double
|
||||
void AssembleMatrix(SparseMatrix &M) const
|
||||
{
|
||||
@@ -419,7 +442,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble element matrices and store them as a DenseTensor object.
|
||||
/// Assemble element matrices and store them as a DenseTensor object.
|
||||
// complex_t = double
|
||||
void AssembleMatrix(DenseTensor &M) const
|
||||
{
|
||||
@@ -472,7 +495,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Assemble element matrices and add them to the bilinear form
|
||||
/// Assemble element matrices and add them to the bilinear form
|
||||
// complex_t = double
|
||||
void AssembleBilinearForm(BilinearForm &a) const
|
||||
{
|
||||
@@ -572,7 +595,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Multiplication using assembled element matrices stored as a DenseTensor.
|
||||
/// Multiplication using assembled element matrices stored as a DenseTensor.
|
||||
// complex_t = double
|
||||
void AddMult(DenseTensor &M, const Vector &x, Vector &y) const
|
||||
{
|
||||
|
||||
+151
-132
@@ -21,8 +21,7 @@ namespace mfem
|
||||
|
||||
// Templated local bilinear form integrator kernels, cf. bilininteg.?pp
|
||||
|
||||
// The Integrator class combines a kernel and a coefficient
|
||||
|
||||
/// The Integrator class combines a kernel and a coefficient
|
||||
template <typename coeff_t, template<int,int,typename> class kernel_t>
|
||||
class TIntegrator
|
||||
{
|
||||
@@ -38,30 +37,32 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Mass kernel
|
||||
|
||||
/// Mass kernel
|
||||
template <int SDim, int Dim, typename complex_t>
|
||||
struct TMassKernel
|
||||
{
|
||||
typedef complex_t complex_type;
|
||||
|
||||
// needed for the TElementTransformation::Result class
|
||||
/// Needed for the TElementTransformation::Result class
|
||||
static const bool uses_Jacobians = true;
|
||||
|
||||
// needed for the FieldEvaluator::Data class
|
||||
/// @name Needed for the FieldEvaluator::Data class
|
||||
///@{
|
||||
static const bool in_values = true;
|
||||
static const bool in_gradients = false;
|
||||
static const bool out_values = true;
|
||||
static const bool out_gradients = false;
|
||||
///@}
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in partial assembly, and partially
|
||||
// assembled action.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in partial assembly, and partially
|
||||
assembled action. */
|
||||
template <int qpts>
|
||||
struct p_asm_data { typedef TVector<qpts,complex_t> type; };
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in full element matrix assembly.
|
||||
/** @brief Partially assembled data type for one element with the given
|
||||
number of quadrature points. This type is used in full element matrix
|
||||
assembly. */
|
||||
template <int qpts>
|
||||
struct f_asm_data { typedef TVector<qpts,complex_t> type; };
|
||||
|
||||
@@ -71,13 +72,13 @@ struct TMassKernel
|
||||
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
|
||||
};
|
||||
|
||||
// Method used for un-assembled (matrix free) action.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// val_qpts [M x NC x NE] - in/out data member in R
|
||||
//
|
||||
// val_qpts *= w det(J)
|
||||
/** @brief Method used for un-assembled (matrix free) action.
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q CoefficientEval<>::Type
|
||||
@param q CoefficientEval<>::Type::result_t
|
||||
@param R val_qpts [M x NC x NE] - in/out data member in R
|
||||
val_qpts *= w det(J) */
|
||||
template <typename T_result_t, typename Q_t, typename q_t,
|
||||
typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
@@ -101,13 +102,16 @@ struct TMassKernel
|
||||
}
|
||||
}
|
||||
|
||||
// Method defining partial assembly.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// A [M] - partially assembled scalars
|
||||
//
|
||||
// A = w det(J)
|
||||
/** @brief Method defining partial assembly.
|
||||
Result in A is the quadrature-point dependent part of element matrix
|
||||
assembly (as opposed to part that is same for all elements),
|
||||
A = w det(J)
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q CoefficientEval<>::Type
|
||||
@param q CoefficientEval<>::Type::result_t
|
||||
@param A [M] - partially assembled scalars
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t, int qpts>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void Assemble(const int k, const T_result_t &F,
|
||||
@@ -124,11 +128,12 @@ struct TMassKernel
|
||||
}
|
||||
}
|
||||
|
||||
// Method for partially assembled action.
|
||||
// A [M] - partially assembled scalars
|
||||
// val_qpts [M x NC x NE] - in/out data member in R
|
||||
//
|
||||
// val_qpts *= A
|
||||
/** @brief Method for partially assembled action.
|
||||
@param k the element number
|
||||
@param A [M] - partially assembled scalars
|
||||
@param R val_qpts [M x NC x NE] - in/out data member in R
|
||||
val_qpts *= A
|
||||
*/
|
||||
template <int qpts, typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void MultAssembled(const int k, const TVector<qpts,complex_t> &A, S_data_t &R)
|
||||
@@ -148,35 +153,38 @@ struct TMassKernel
|
||||
};
|
||||
|
||||
|
||||
// Diffusion kernel
|
||||
|
||||
// complex_t - type for the assembled data
|
||||
/** @brief Diffusion kernel
|
||||
@tparam complex_t - type for the assembled data
|
||||
*/
|
||||
template <int SDim, int Dim, typename complex_t>
|
||||
struct TDiffusionKernel;
|
||||
|
||||
// Diffusion kernel in 1D
|
||||
/// Diffusion kernel in 1D
|
||||
template <typename complex_t>
|
||||
struct TDiffusionKernel<1,1,complex_t>
|
||||
{
|
||||
typedef complex_t complex_type;
|
||||
|
||||
// needed for the TElementTransformation::Result class
|
||||
/// Needed for the TElementTransformation::Result class
|
||||
static const bool uses_Jacobians = true;
|
||||
|
||||
// needed for the FieldEvaluator::Data class
|
||||
/// Needed for the FieldEvaluator::Data class
|
||||
///@{
|
||||
static const bool in_values = false;
|
||||
static const bool in_gradients = true;
|
||||
static const bool out_values = false;
|
||||
static const bool out_gradients = true;
|
||||
///@}
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in partial assembly, and partially
|
||||
// assembled action.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in partial assembly, and partially
|
||||
assembled action. */
|
||||
template <int qpts>
|
||||
struct p_asm_data { typedef TMatrix<qpts,1,complex_t> type; };
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in full element matrix assembly.
|
||||
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in full element matrix assembly. */
|
||||
template <int qpts>
|
||||
struct f_asm_data { typedef TTensor3<qpts,1,1,complex_t> type; };
|
||||
|
||||
@@ -186,13 +194,13 @@ struct TDiffusionKernel<1,1,complex_t>
|
||||
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
|
||||
};
|
||||
|
||||
// Method used for un-assembled (matrix free) action.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
|
||||
/** @brief Method used for un-assembled (matrix free) action.
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q - CoefficientEval<>::Type
|
||||
@param q - CoefficientEval<>::Type::result_t
|
||||
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts */
|
||||
template <typename T_result_t, typename Q_t, typename q_t,
|
||||
typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
@@ -214,17 +222,20 @@ struct TDiffusionKernel<1,1,complex_t>
|
||||
}
|
||||
}
|
||||
|
||||
// Method defining partial assembly. The pointwise Dim x Dim matrices are
|
||||
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
|
||||
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
|
||||
// matrices.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
|
||||
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
|
||||
//
|
||||
// A = (w/det(J)) adj(J) adj(J)^t
|
||||
|
||||
/** @brief Method defining partial assembly.
|
||||
The pointwise Dim x Dim matrices are stored as symmetric (when
|
||||
asm_type == p_asm_data, i.e. A.layout.rank == 2) or
|
||||
non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
|
||||
== 3) matrices.
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q CoefficientEval<>::Type
|
||||
@param q CoefficientEval<>::Type::result_t
|
||||
@param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
|
||||
A [M x Dim x Dim] - partially assembled Dim x Dim matrices
|
||||
A = (w/det(J)) adj(J) adj(J)^t
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void Assemble(const int k, const T_result_t &F,
|
||||
@@ -240,13 +251,13 @@ struct TDiffusionKernel<1,1,complex_t>
|
||||
A[i] = Q.get(q,i,k) / F.Jt(i,0,0,k);
|
||||
}
|
||||
}
|
||||
|
||||
// Method for partially assembled action.
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
|
||||
// matrices
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = A grad_qpts
|
||||
/** @brief Method for partially assembled action.
|
||||
@param k the element number
|
||||
@param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symmetric
|
||||
matrices
|
||||
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
grad_qpts = A grad_qpts
|
||||
*/
|
||||
template <int qpts, typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void MultAssembled(const int k, const TMatrix<qpts,1,complex_t> &A,
|
||||
@@ -266,30 +277,32 @@ struct TDiffusionKernel<1,1,complex_t>
|
||||
}
|
||||
};
|
||||
|
||||
// Diffusion kernel in 2D
|
||||
/// Diffusion kernel in 2D
|
||||
template <typename complex_t>
|
||||
struct TDiffusionKernel<2,2,complex_t>
|
||||
{
|
||||
typedef complex_t complex_type;
|
||||
|
||||
// needed for the TElementTransformation::Result class
|
||||
/// Needed for the TElementTransformation::Result class
|
||||
static const bool uses_Jacobians = true;
|
||||
|
||||
// needed for the FieldEvaluator::Data class
|
||||
/// Needed for the FieldEvaluator::Data class
|
||||
///@{
|
||||
static const bool in_values = false;
|
||||
static const bool in_gradients = true;
|
||||
static const bool out_values = false;
|
||||
static const bool out_gradients = true;
|
||||
///@}
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in partial assembly, and partially
|
||||
// assembled action. Stores one symmetric 2 x 2 matrix per point.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in partial assembly, and partially
|
||||
assembled action. Stores one symmetric 2 x 2 matrix per point. */
|
||||
template <int qpts>
|
||||
struct p_asm_data { typedef TMatrix<qpts,3,complex_t> type; };
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in full element matrix assembly.
|
||||
// Stores one general (non-symmetric) 2 x 2 matrix per point.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in full element matrix assembly.
|
||||
Stores one general (non-symmetric) 2 x 2 matrix per point. */
|
||||
template <int qpts>
|
||||
struct f_asm_data { typedef TTensor3<qpts,2,2,complex_t> type; };
|
||||
|
||||
@@ -299,13 +312,14 @@ struct TDiffusionKernel<2,2,complex_t>
|
||||
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
|
||||
};
|
||||
|
||||
// Method used for un-assembled (matrix free) action.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
|
||||
/** @brief Method used for un-assembled (matrix free) action.
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q CoefficientEval<>::Type
|
||||
@param q CoefficientEval<>::Type::result_t
|
||||
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t,
|
||||
typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
@@ -338,17 +352,18 @@ struct TDiffusionKernel<2,2,complex_t>
|
||||
}
|
||||
}
|
||||
|
||||
// Method defining partial assembly. The pointwise Dim x Dim matrices are
|
||||
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
|
||||
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
|
||||
// matrices.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
|
||||
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
|
||||
//
|
||||
// A = (w/det(J)) adj(J) adj(J)^t
|
||||
/** @brief Method defining partial assembly.
|
||||
The pointwise Dim x Dim matrices are stored as symmetric (when
|
||||
asm_type == p_asm_data, i.e. A.layout.rank == 2) or non-symmetric
|
||||
(when asm_type == f_asm_data, i.e. A.layout.rank == 3) matrices.
|
||||
A = (w/det(J)) adj(J) adj(J)^t
|
||||
@param k the element number
|
||||
@param F Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
@param Q CoefficientEval<>::Type
|
||||
@param q CoefficientEval<>::Type::result_t
|
||||
@param A [M x Dim*(Dim+1)/2] partially assembled Dim x Dim symm. matrices
|
||||
@param A [M x Dim x Dim] partially assembled Dim x Dim matrices
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void Assemble(const int k, const T_result_t &F,
|
||||
@@ -376,12 +391,13 @@ struct TDiffusionKernel<2,2,complex_t>
|
||||
}
|
||||
}
|
||||
|
||||
// Method for partially assembled action.
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
|
||||
// matrices
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = A grad_qpts
|
||||
/** @brief Method for partially assembled action.
|
||||
@param k the element number
|
||||
@param A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
|
||||
matrices
|
||||
@param R grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
grad_qpts = A grad_qpts
|
||||
*/
|
||||
template <int qpts, typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void MultAssembled(const int k, const TMatrix<qpts,3,complex_t> &A,
|
||||
@@ -407,30 +423,32 @@ struct TDiffusionKernel<2,2,complex_t>
|
||||
}
|
||||
};
|
||||
|
||||
// Diffusion kernel in 3D
|
||||
/// Diffusion kernel in 3D
|
||||
template <typename complex_t>
|
||||
struct TDiffusionKernel<3,3,complex_t>
|
||||
{
|
||||
typedef complex_t complex_type;
|
||||
|
||||
// needed for the TElementTransformation::Result class
|
||||
/// Needed for the TElementTransformation::Result class
|
||||
static const bool uses_Jacobians = true;
|
||||
|
||||
// needed for the FieldEvaluator::Data class
|
||||
/// Needed for the FieldEvaluator::Data class
|
||||
///@{
|
||||
static const bool in_values = false;
|
||||
static const bool in_gradients = true;
|
||||
static const bool out_values = false;
|
||||
static const bool out_gradients = true;
|
||||
///@}
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in partial assembly, and partially
|
||||
// assembled action. Stores one symmetric 3 x 3 matrix per point.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in partial assembly, and partially
|
||||
assembled action. Stores one symmetric 3 x 3 matrix per point. */
|
||||
template <int qpts>
|
||||
struct p_asm_data { typedef TMatrix<qpts,6,complex_t> type; };
|
||||
|
||||
// Partially assembled data type for one element with the given number of
|
||||
// quadrature points. This type is used in full element matrix assembly.
|
||||
// Stores one general (non-symmetric) 3 x 3 matrix per point.
|
||||
/** @brief Partially assembled data type for one element with the given number of
|
||||
quadrature points. This type is used in full element matrix assembly.
|
||||
Stores one general (non-symmetric) 3 x 3 matrix per point. */
|
||||
template <int qpts>
|
||||
struct f_asm_data { typedef TTensor3<qpts,3,3,complex_t> type; };
|
||||
|
||||
@@ -440,13 +458,13 @@ struct TDiffusionKernel<3,3,complex_t>
|
||||
typedef typename IntRuleCoefficient<IR,coeff_t,impl_traits_t>::Type Type;
|
||||
};
|
||||
|
||||
// Method used for un-assembled (matrix free) action.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
|
||||
/** @brief Method used for un-assembled (matrix free) action.
|
||||
grad_qpts = (w/det(J)) adj(J) adj(J)^t grad_qpts
|
||||
Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
Q - CoefficientEval<>::Type
|
||||
q - CoefficientEval<>::Type::result_t
|
||||
grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t,
|
||||
typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
@@ -477,17 +495,18 @@ struct TDiffusionKernel<3,3,complex_t>
|
||||
}
|
||||
}
|
||||
|
||||
// Method defining partial assembly. The pointwise Dim x Dim matrices are
|
||||
// stored as symmetric (when asm_type == p_asm_data, i.e. A.layout.rank == 2)
|
||||
// or non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank == 3)
|
||||
// matrices.
|
||||
// Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
// Q - CoefficientEval<>::Type
|
||||
// q - CoefficientEval<>::Type::result_t
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
|
||||
// A [M x Dim x Dim] - partially assembled Dim x Dim matrices
|
||||
//
|
||||
// A = (w/det(J)) adj(J) adj(J)^t
|
||||
/** @brief Method defining partial assembly.
|
||||
The pointwise Dim x Dim matrices are stored as symmetric (when
|
||||
asm_type == p_asm_data, i.e. A.layout.rank == 2) or
|
||||
non-symmetric (when asm_type == f_asm_data, i.e. A.layout.rank
|
||||
== 3) matrices.
|
||||
A = (w/det(J)) adj(J) adj(J)^t
|
||||
Jt [M x Dim x SDim x NE] - Jacobian transposed, data member in F
|
||||
Q - CoefficientEval<>::Type
|
||||
q - CoefficientEval<>::Type::result_t
|
||||
A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symm. matrices
|
||||
A [M x Dim x Dim] - partially assembled Dim x Dim matrices
|
||||
*/
|
||||
template <typename T_result_t, typename Q_t, typename q_t, typename asm_type>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void Assemble(const int k, const T_result_t &F,
|
||||
@@ -518,12 +537,12 @@ struct TDiffusionKernel<3,3,complex_t>
|
||||
}
|
||||
}
|
||||
|
||||
// Method for partially assembled action.
|
||||
// A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
|
||||
// matrices
|
||||
// grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
//
|
||||
// grad_qpts = A grad_qpts
|
||||
/** @brief Method for partially assembled action.
|
||||
A [M x Dim*(Dim+1)/2] - partially assembled Dim x Dim symmetric
|
||||
matrices
|
||||
grad_qpts [M x SDim x NC x NE] - in/out data member in R
|
||||
grad_qpts = A grad_qpts
|
||||
*/
|
||||
template <int qpts, typename S_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
void MultAssembled(const int k, const TMatrix<qpts,6,complex_t> &A,
|
||||
|
||||
+11
-10
@@ -21,7 +21,7 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
// Templated coefficient classes, cf. coefficient.?pp
|
||||
/// Templated coefficient classes, cf. coefficient.?pp
|
||||
|
||||
class TCoefficient
|
||||
{
|
||||
@@ -56,12 +56,13 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Function coefficient. The template class 'Func' has to implement at least one
|
||||
// of the following methods, depending on the dimension that will be used:
|
||||
// complex_t Eval1D(real_t);
|
||||
// complex_t Eval2D(real_t,real_t);
|
||||
// complex_t Eval3D(real_t,real_t,real_t);
|
||||
// Use MFEM_FLOPS_ADD() to count flops inside Eval*D.
|
||||
/** @brief Function coefficient.
|
||||
@tparam Func has to implement at least one of the following methods,
|
||||
depending on the dimension that will be used:
|
||||
complex_t Eval1D(real_t);
|
||||
complex_t Eval2D(real_t,real_t);
|
||||
complex_t Eval3D(real_t,real_t,real_t);
|
||||
Use MFEM_FLOPS_ADD() to count flops inside Eval*D. */
|
||||
template <typename Func, typename complex_t = double>
|
||||
class TFunctionCoefficient : public TCoefficient
|
||||
{
|
||||
@@ -139,9 +140,9 @@ protected:
|
||||
};
|
||||
|
||||
public:
|
||||
// Constructor for the case when Func has no data members.
|
||||
/// Constructor for the case when Func has no data members.
|
||||
TFunctionCoefficient() : F() { }
|
||||
// Constructor for the case when Func has data members.
|
||||
/// Constructor for the case when Func has data members.
|
||||
TFunctionCoefficient(Func &F_) : F(F_) { }
|
||||
// Default copy constructor, Func has to have copy constructor.
|
||||
|
||||
@@ -197,7 +198,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// GridFunction coefficient class.
|
||||
template <typename FieldEval>
|
||||
class TGridFunctionCoefficient : public TCoefficient
|
||||
{
|
||||
|
||||
+21
-15
@@ -21,12 +21,14 @@ namespace mfem
|
||||
|
||||
// Templated element transformation classes, cf. eltrans.?pp
|
||||
|
||||
// Element transformation class, templated on a mesh type and an integration
|
||||
// rule. It is constructed from a mesh (e.g. class TMesh) and shape evaluator
|
||||
// (e.g. class ShapeEvaluator) objects. Allows computation of physical
|
||||
// coordinates and Jacobian matrices corresponding to the reference integration
|
||||
// points. The desired result is specified through the template subclass Result
|
||||
// and stored in an object of the same type.
|
||||
/** @brief Element transformation class, templated on a mesh type and an
|
||||
integration rule.
|
||||
It is constructed from a mesh (e.g. class TMesh) and shape evaluator
|
||||
(e.g. class ShapeEvaluator) objects. Allows computation of physical
|
||||
coordinates and Jacobian matrices corresponding to the reference integration
|
||||
points. The desired result is specified through the template subclass Result
|
||||
and stored in an object of the same type.
|
||||
*/
|
||||
template <typename Mesh_t, typename IR, typename real_t = double>
|
||||
class TElementTransformation
|
||||
{
|
||||
@@ -39,9 +41,9 @@ public:
|
||||
|
||||
typedef TElementTransformation<Mesh_t,IR,real_t> T_type;
|
||||
|
||||
// Enumeration for the result type of the TElementTransformation::Eval()
|
||||
// method. The types can obtained by summing constants from this enumeration
|
||||
// and used as a template parameter in struct Result.
|
||||
/// Enumeration for the result type of the TElementTransformation::Eval()
|
||||
/// method. The types can obtained by summing constants from this enumeration
|
||||
/// and used as a template parameter in struct Result.
|
||||
enum EvalOperations
|
||||
{
|
||||
EvalNone = 0,
|
||||
@@ -51,6 +53,8 @@ public:
|
||||
LoadElementIdxs = 8
|
||||
};
|
||||
|
||||
/// Determines at compile-time the operations needed for given coefficient
|
||||
/// and kernel
|
||||
template <typename coeff_t, typename kernel_t> struct Get
|
||||
{
|
||||
static const int EvalOps =
|
||||
@@ -61,11 +65,13 @@ public:
|
||||
(EvalJacobians * kernel_t::uses_Jacobians);
|
||||
};
|
||||
|
||||
// Templated struct Result, used to specify the type result that is computed
|
||||
// by the TElementTransformation::Eval() method and stored in this structure.
|
||||
// The template parameter EvalOps is a sum (bitwise or) of constants from
|
||||
// the enum EvalOperations. The type impl_traits_t specifies additional
|
||||
// parameters and types to be used by the Eval() method.
|
||||
/** @brief Templated struct Result, used to specify the type result that is
|
||||
computed by the TElementTransformation::Eval() method and stored in this
|
||||
structure.
|
||||
@tparam EvalOps is a sum (bitwise or) of constants from the enum EvalOperations
|
||||
@tparam NE is the number of elements to be processed in the Eval() method.
|
||||
@tparam impl_traits_t specifies additional parameters and types to be used by the Eval() method
|
||||
*/
|
||||
template<int EvalOps, typename impl_traits_t> struct Result;
|
||||
|
||||
static const int dim = Mesh_t::dim;
|
||||
@@ -109,7 +115,7 @@ public:
|
||||
elements(mesh.m_mesh.GetElementsArray())
|
||||
{ }
|
||||
|
||||
// Evaluate coordinates and/or Jacobian matrices at quadrature points.
|
||||
/// Evaluate coordinates and/or Jacobian matrices at quadrature points.
|
||||
template<int EvalOps, typename impl_traits_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
void Eval(int el, Result<EvalOps,impl_traits_t> &F)
|
||||
|
||||
+103
-88
@@ -23,12 +23,16 @@ namespace mfem
|
||||
// Templated classes for transitioning between degrees of freedom and quadrature
|
||||
// points values.
|
||||
|
||||
// Shape evaluators -- values of basis functions on the reference element
|
||||
|
||||
/** @brief Shape evaluators -- values of basis functions on the reference element
|
||||
@tparam FE some form of TFiniteElement, probably got from TMesh::FE_type
|
||||
@tparam IR some form of TIntegrationRule
|
||||
@tparam TP tensor product or not
|
||||
@tparam real_t data type for mesh nodes, solution basis, mesh basis
|
||||
*/
|
||||
template <class FE, class IR, bool TP, typename real_t>
|
||||
class ShapeEvaluator_base;
|
||||
|
||||
// ShapeEvaluator without tensor-product structure
|
||||
/// ShapeEvaluator without tensor-product structure
|
||||
template <class FE, class IR, typename real_t>
|
||||
class ShapeEvaluator_base<FE, IR, false, real_t>
|
||||
{
|
||||
@@ -54,8 +58,8 @@ public:
|
||||
|
||||
// default copy constructor
|
||||
|
||||
// Multi-component shape evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
|
||||
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
|
||||
dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename qpt_layout_t, typename qpt_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -76,8 +80,8 @@ public:
|
||||
qpt_layout, qpt_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
// qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp).
|
||||
/** @brief Multi-component shape evaluation transpose from quadrature points to
|
||||
DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename qpt_layout_t, typename qpt_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -99,8 +103,8 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
|
||||
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename grad_layout_t, typename grad_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -124,8 +128,8 @@ public:
|
||||
grad_layout.merge_12(), grad_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation transpose from quadrature points to
|
||||
// DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp).
|
||||
/** @brief Multi-component gradient evaluation transpose from quadrature points to
|
||||
DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename grad_layout_t, typename grad_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -150,8 +154,9 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component assemble.
|
||||
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
|
||||
/** @brief Multi-component assemble.
|
||||
qpt_layout is (NIP x NumComp),
|
||||
M_layout is (DOF x DOF x NumComp) */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename M_layout_t, typename M_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -173,9 +178,9 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
// Multi-component assemble of grad-grad element matrices.
|
||||
// qpt_layout is (NIP x DIM x DIM x NumComp), and
|
||||
// D_layout is (DOF x DOF x NumComp).
|
||||
/** @brief Multi-component assemble of grad-grad element matrices.
|
||||
qpt_layout is (NIP x DIM x DIM x NumComp), and
|
||||
D_layout is (DOF x DOF x NumComp). */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename D_layout_t, typename D_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -208,7 +213,7 @@ public:
|
||||
template <int Dim, int DOF, int NIP, typename real_t>
|
||||
class TProductShapeEvaluator;
|
||||
|
||||
// ShapeEvaluator with 1D tensor-product structure
|
||||
/// ShapeEvaluator with 1D tensor-product structure
|
||||
template <int DOF, int NIP, typename real_t>
|
||||
class TProductShapeEvaluator<1, DOF, NIP, real_t>
|
||||
{
|
||||
@@ -221,8 +226,8 @@ protected:
|
||||
public:
|
||||
TProductShapeEvaluator() { }
|
||||
|
||||
// Multi-component shape evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp).
|
||||
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
|
||||
dof_layout is (DOF x NumComp) and qpt_layout is (NIP x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename qpt_layout_t, typename qpt_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -234,8 +239,8 @@ public:
|
||||
qpt_layout, qpt_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
// qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp).
|
||||
/** @brief Multi-component shape evaluation transpose from quadrature points
|
||||
to DOFs. qpt_layout is (NIP x NumComp) and dof_layout is (DOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename qpt_layout_t, typename qpt_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -248,8 +253,8 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp).
|
||||
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
dof_layout is (DOF x NumComp) and grad_layout is (NIP x DIM x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename grad_layout_t, typename grad_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -264,8 +269,8 @@ public:
|
||||
grad_layout.merge_12(), grad_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation transpose from quadrature points to
|
||||
// DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp).
|
||||
/** @brief Multi-component gradient evaluation transpose from quadrature points to
|
||||
DOFs. grad_layout is (NIP x DIM x NumComp), dof_layout is (DOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename grad_layout_t, typename grad_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -282,8 +287,8 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component assemble.
|
||||
// qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp)
|
||||
/** @brief Multi-component assemble.
|
||||
qpt_layout is (NIP x NumComp), M_layout is (DOF x DOF x NumComp) */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename M_layout_t, typename M_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -305,9 +310,9 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
// Multi-component assemble of grad-grad element matrices.
|
||||
// qpt_layout is (NIP x DIM x DIM x NumComp), and
|
||||
// D_layout is (DOF x DOF x NumComp).
|
||||
/** @brief Multi-component assemble of grad-grad element matrices.
|
||||
qpt_layout is (NIP x DIM x DIM x NumComp), and
|
||||
D_layout is (DOF x DOF x NumComp). */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename D_layout_t, typename D_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -332,7 +337,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ShapeEvaluator with 2D tensor-product structure
|
||||
/// ShapeEvaluator with 2D tensor-product structure
|
||||
template <int DOF, int NIP, typename real_t>
|
||||
class TProductShapeEvaluator<2, DOF, NIP, real_t>
|
||||
{
|
||||
@@ -368,8 +373,8 @@ public:
|
||||
qpt_layout.template split_1<NIP,NIP>(), qpt_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
|
||||
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
|
||||
dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename qpt_layout_t, typename qpt_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -401,8 +406,8 @@ public:
|
||||
dof_layout.template split_1<DOF,DOF>(), dof_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
// qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp).
|
||||
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename qpt_layout_t, typename qpt_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -413,8 +418,8 @@ public:
|
||||
CalcT<false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
|
||||
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename grad_layout_t, typename grad_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -429,9 +434,9 @@ public:
|
||||
grad_layout.ind2(1), grad_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation transpose from quadrature points to
|
||||
// DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
|
||||
// (TDOF x NumComp).
|
||||
/** @brief Multi-component gradient evaluation transpose from quadrature points to
|
||||
DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
|
||||
(TDOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename grad_layout_t, typename grad_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -447,8 +452,8 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component assemble.
|
||||
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
|
||||
/** @brief Multi-component assemble.
|
||||
qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename M_layout_t, typename M_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -540,9 +545,9 @@ public:
|
||||
D_layout.merge_23().template split_12<DOF,DOF,DOF,DOF*NC>(), D_data);
|
||||
}
|
||||
|
||||
// Multi-component assemble of grad-grad element matrices.
|
||||
// qpt_layout is (TNIP x DIM x DIM x NumComp), and
|
||||
// D_layout is (TDOF x TDOF x NumComp).
|
||||
/** @brief Multi-component assemble of grad-grad element matrices.
|
||||
qpt_layout is (TNIP x DIM x DIM x NumComp), and
|
||||
D_layout is (TDOF x TDOF x NumComp). */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename D_layout_t, typename D_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -612,7 +617,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ShapeEvaluator with 3D tensor-product structure
|
||||
/// ShapeEvaluator with 3D tensor-product structure
|
||||
template <int DOF, int NIP, typename real_t>
|
||||
class TProductShapeEvaluator<3, DOF, NIP, real_t>
|
||||
{
|
||||
@@ -652,8 +657,8 @@ public:
|
||||
qpt_layout.template split_1<NIP*NIP,NIP>(), qpt_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp).
|
||||
/** @brief Multi-component shape evaluation from DOFs to quadrature points.
|
||||
dof_layout is (TDOF x NumComp) and qpt_layout is (TNIP x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename qpt_layout_t, typename qpt_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -689,8 +694,8 @@ public:
|
||||
dof_layout.template split_1<DOF,DOF*DOF>(), dof_data);
|
||||
}
|
||||
|
||||
// Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
// qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp).
|
||||
/** @brief Multi-component shape evaluation transpose from quadrature points to DOFs.
|
||||
qpt_layout is (TNIP x NumComp) and dof_layout is (TDOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename qpt_layout_t, typename qpt_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -701,8 +706,8 @@ public:
|
||||
CalcT<false,false,false,Add>(qpt_layout, qpt_data, dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
// dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp).
|
||||
/** @brief Multi-component gradient evaluation from DOFs to quadrature points.
|
||||
dof_layout is (TDOF x NumComp) and grad_layout is (TNIP x DIM x NumComp). */
|
||||
template <typename dof_layout_t, typename dof_data_t,
|
||||
typename grad_layout_t, typename grad_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -721,9 +726,9 @@ public:
|
||||
// y-derivatives and second time for the z-derivatives.
|
||||
}
|
||||
|
||||
// Multi-component gradient evaluation transpose from quadrature points to
|
||||
// DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
|
||||
// (TDOF x NumComp).
|
||||
/** @brief Multi-component gradient evaluation transpose from quadrature points to
|
||||
DOFs. grad_layout is (TNIP x DIM x NumComp), dof_layout is
|
||||
(TDOF x NumComp). */
|
||||
template <bool Add,
|
||||
typename grad_layout_t, typename grad_data_t,
|
||||
typename dof_layout_t, typename dof_data_t>
|
||||
@@ -741,8 +746,8 @@ public:
|
||||
dof_layout, dof_data);
|
||||
}
|
||||
|
||||
// Multi-component assemble.
|
||||
// qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp)
|
||||
/** @brief Multi-component assemble.
|
||||
qpt_layout is (TNIP x NumComp), M_layout is (TDOF x TDOF x NumComp) */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename M_layout_t, typename M_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -868,9 +873,9 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
// Multi-component assemble of grad-grad element matrices.
|
||||
// qpt_layout is (TNIP x DIM x DIM x NumComp), and
|
||||
// D_layout is (TDOF x TDOF x NumComp).
|
||||
/** @brief Multi-component assemble of grad-grad element matrices.
|
||||
qpt_layout is (TNIP x DIM x DIM x NumComp), and
|
||||
D_layout is (TDOF x TDOF x NumComp). */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename D_layout_t, typename D_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
@@ -904,7 +909,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// ShapeEvaluator with tensor-product structure in any dimension
|
||||
/// ShapeEvaluator with tensor-product structure in any dimension
|
||||
template <class FE, class IR, typename real_t>
|
||||
class ShapeEvaluator_base<FE, IR, true, real_t>
|
||||
: public TProductShapeEvaluator<FE::dim, FE::dofs_1d, IR::qpts_1d, real_t>
|
||||
@@ -930,7 +935,7 @@ public:
|
||||
// default copy constructor
|
||||
};
|
||||
|
||||
// General ShapeEvaluator for any scalar FE type (L2 or H1)
|
||||
/// General ShapeEvaluator for any scalar FE type (L2 or H1)
|
||||
template <class FE, class IR, typename real_t>
|
||||
class ShapeEvaluator
|
||||
: public ShapeEvaluator_base<FE,IR,FE::tensor_prod && IR::tensor_prod,real_t>
|
||||
@@ -955,8 +960,9 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Field evaluators -- values of a given global FE grid function
|
||||
|
||||
/** @brief Field evaluators -- values of a given global FE grid function
|
||||
This is roughly speaking a templated version of GridFunction
|
||||
*/
|
||||
template <typename FESpace_t, typename VecLayout_t, typename IR,
|
||||
typename complex_t, typename real_t>
|
||||
class FieldEvaluator_base
|
||||
@@ -969,7 +975,7 @@ protected:
|
||||
ShapeEval_type shapeEval;
|
||||
VecLayout_t vec_layout;
|
||||
|
||||
// With this constructor, fespace is a shallow copy.
|
||||
/// With this constructor, fespace is a shallow copy.
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
FieldEvaluator_base(const FESpace_t &tfes, const ShapeEval_type &shape_eval,
|
||||
const VecLayout_t &vec_layout)
|
||||
@@ -978,14 +984,14 @@ protected:
|
||||
vec_layout(vec_layout)
|
||||
{ }
|
||||
|
||||
// This constructor creates new fespace, not a shallow copy.
|
||||
/// This constructor creates new fespace, not a shallow copy.
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
FieldEvaluator_base(const FE_type &fe, const FiniteElementSpace &fes)
|
||||
: fespace(fe, fes), shapeEval(fe), vec_layout(fes)
|
||||
{ }
|
||||
};
|
||||
|
||||
// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type
|
||||
/// complex_t - dof/qpt data type, real_t - ShapeEvaluator (FE basis) data type
|
||||
template <typename FESpace_t, typename VecLayout_t, typename IR,
|
||||
typename complex_t = double, typename real_t = double>
|
||||
class FieldEvaluator
|
||||
@@ -1018,7 +1024,7 @@ protected:
|
||||
complex_t *data_out;
|
||||
|
||||
public:
|
||||
// With this constructor, fespace is a shallow copy of tfes.
|
||||
/// With this constructor, fespace is a shallow copy of tfes.
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
FieldEvaluator(const FESpace_t &tfes, const ShapeEval_type &shape_eval,
|
||||
const VecLayout_type &vec_layout,
|
||||
@@ -1028,7 +1034,7 @@ public:
|
||||
data_out(global_data_out)
|
||||
{ }
|
||||
|
||||
// With this constructor, fespace is a shallow copy of f.fespace.
|
||||
/// With this constructor, fespace is a shallow copy of f.fespace.
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
FieldEvaluator(const FieldEvaluator &f,
|
||||
const complex_t *global_data_in, complex_t *global_data_out)
|
||||
@@ -1037,7 +1043,7 @@ public:
|
||||
data_out(global_data_out)
|
||||
{ }
|
||||
|
||||
// This constructor creates a new fespace, not a shallow copy.
|
||||
/// This constructor creates a new fespace, not a shallow copy.
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
FieldEvaluator(const FiniteElementSpace &fes,
|
||||
const complex_t *global_data_in, complex_t *global_data_out)
|
||||
@@ -1058,7 +1064,7 @@ public:
|
||||
fespace.SetElement(el);
|
||||
}
|
||||
|
||||
// val_layout_t is (qpts x vdim x NE)
|
||||
/// val_layout_t is (qpts x vdim x NE)
|
||||
template <typename val_layout_t, typename val_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
void GetValues(int el, const val_layout_t &l, val_data_t &vals)
|
||||
@@ -1070,7 +1076,7 @@ public:
|
||||
shapeEval.Calc(val_dofs.layout.merge_23(), val_dofs, l.merge_23(), vals);
|
||||
}
|
||||
|
||||
// grad_layout_t is (qpts x dim x vdim x NE)
|
||||
/// grad_layout_t is (qpts x dim x vdim x NE)
|
||||
template <typename grad_layout_t, typename grad_data_t>
|
||||
inline MFEM_ALWAYS_INLINE
|
||||
void GetGradients(int el, const grad_layout_t &l, grad_data_t &grad)
|
||||
@@ -1137,9 +1143,9 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
// Enumeration for the data type used by the Eval() and Assemble() methods.
|
||||
// The types can obtained by summing constants from this enumeration and used
|
||||
// as a template parameter in struct Data.
|
||||
/** @brief Enumeration for the data type used by the Eval() and Assemble() methods.
|
||||
The types can be obtained by summing constants from this enumeration and used
|
||||
as a template parameter in struct Data. */
|
||||
enum InOutData
|
||||
{
|
||||
None = 0,
|
||||
@@ -1147,10 +1153,12 @@ public:
|
||||
Gradients = 2
|
||||
};
|
||||
|
||||
// Auxiliary templated struct AData, used by the Eval() and Assemble()
|
||||
// methods. The template parameter IOData is "bitwise or" of constants from
|
||||
// the enum InOutData. The type impl_traits_t specifies parameters and types
|
||||
// to be used in the Eval() and Assemble() methods.
|
||||
/** @brief Auxiliary templated struct AData, used by the Eval() and Assemble()
|
||||
methods.
|
||||
|
||||
The template parameter IOData is "bitwise or" of constants from
|
||||
the enum InOutData. The parameter NE is the number of elements to be
|
||||
processed in the Eval() and Assemble() methods. */
|
||||
template<int IOData, typename impl_traits_t> struct AData;
|
||||
|
||||
template <typename it_t> struct AData<0,it_t> // 0 = None
|
||||
@@ -1198,8 +1206,8 @@ public:
|
||||
TTensor4<qpts,dim,vdim,ne,vcomplex_t> grad_qpts;
|
||||
};
|
||||
|
||||
// This struct is similar to struct AData, adding separate static data
|
||||
// members for the input (InData) and output (OutData) data types.
|
||||
/** @brief This struct is similar to struct AData, adding separate static data
|
||||
members for the input (InData) and output (OutData) data types. */
|
||||
template <int IData, int OData, typename it_t>
|
||||
struct BData : public AData<IData|OData,it_t>
|
||||
{
|
||||
@@ -1208,9 +1216,9 @@ public:
|
||||
static const int OutData = OData;
|
||||
};
|
||||
|
||||
// This struct implements the input (Eval, EvalSerialized) and output
|
||||
// (Assemble, AssembleSerialized) operations for the given Ops.
|
||||
// Ops is "bitwise or" of constants from the enum InOutData.
|
||||
/** @brief This struct implements the input (Eval, EvalSerialized) and output
|
||||
(Assemble, AssembleSerialized) operations for the given Ops.
|
||||
Ops is "bitwise or" of constants from the enum InOutData. */
|
||||
template <int Ops, bool dummy> struct Action;
|
||||
|
||||
template <bool dummy> struct Action<0,dummy> // 0 = None
|
||||
@@ -1396,8 +1404,8 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
// This struct implements element matrix computation for some combinations
|
||||
// of input (InOps) and output (OutOps) operations.
|
||||
/** @brief This struct implements element matrix computation for some combinations
|
||||
of input (InOps) and output (OutOps) operations. */
|
||||
template <int InOps, int OutOps, typename it_t> struct TElementMatrix;
|
||||
|
||||
// Case 1,1 = Values,Values
|
||||
@@ -1419,8 +1427,15 @@ public:
|
||||
// Case 2,2 = Gradients,Gradients
|
||||
template <typename it_t> struct TElementMatrix<2,2,it_t>
|
||||
{
|
||||
// qpt_layout_t is (nip x dim x dim), M_layout_t is (dof x dof)
|
||||
// it_t::batch_size = 1 is assumed
|
||||
/** @brief Assemble element mass matrix
|
||||
@param a the layout for the quadrature point data
|
||||
@param A given quadrature point data for element (incl. coefficient,
|
||||
geometry)
|
||||
@param m the layout for the resulting element mass matrix
|
||||
@param M the resulting element mass matrix
|
||||
@param ev the shape evaluator
|
||||
qpt_layout_t is (nip), M_layout_t is (dof x dof)
|
||||
NE = 1 is assumed */
|
||||
template <typename qpt_layout_t, typename qpt_data_t,
|
||||
typename M_layout_t, typename M_data_t>
|
||||
static inline MFEM_ALWAYS_INLINE
|
||||
|
||||
+29
@@ -20,6 +20,18 @@ namespace mfem
|
||||
|
||||
// Templated finite element classes, cf. fe.?pp
|
||||
|
||||
/** @brief Store mass-like matrix B for each integration point on the reference
|
||||
element.
|
||||
For tensor product evaluation, this is only called on the 1D reference
|
||||
element, and higher dimensions are put together from that.
|
||||
The element mass matrix can be written \f$ M_E = B^T D_E B \f$ where the B
|
||||
built here is the B, and is unchanging across the mesh. The diagonal matrix
|
||||
\f$ D_E \f$ then contains all the element-specific geometry and physics data.
|
||||
@param fe the element we are calculating on
|
||||
@param ir the integration rule to calculate the shape matrix on
|
||||
@param B must be (nip x dof) with column major storage
|
||||
@param dof_map the inverse of dof_map is applied to reorder local dofs.
|
||||
*/
|
||||
template <typename real_t>
|
||||
void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir,
|
||||
real_t *B, const Array<int> *dof_map = NULL)
|
||||
@@ -41,6 +53,23 @@ void CalcShapeMatrix(const FiniteElement &fe, const IntegrationRule &ir,
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief store gradient matrix G for each integration point on the reference
|
||||
element.
|
||||
For tensor product evaluation, this is only called on the 1D reference
|
||||
element, and higher dimensions are put together from that.
|
||||
The element stiffness matrix can be written
|
||||
\f[
|
||||
S_E = \sum_{k=1}^{nq} G_{k,i}^T (D_E^G)_{k,k} G_{k,j}
|
||||
\f]
|
||||
where \f$ nq \f$ is the number of quadrature points, \f$ D_E^G \f$ contains
|
||||
all the information about the element geometry and coefficients (Jacobians
|
||||
etc.), and \f$ G \f$ is the matrix built in this routine, which is the same
|
||||
for all elements in a mesh.
|
||||
@param fe the element we are calculating on
|
||||
@param ir the integration rule to calculate the gradients on
|
||||
@param[out] G must be (nip x dim x dof) with column major storage
|
||||
@param[in] dof_map the inverse of dof_map is applied to reorder local dofs.
|
||||
*/
|
||||
template <typename real_t>
|
||||
void CalcGradTensor(const FiniteElement &fe, const IntegrationRule &ir,
|
||||
real_t *G, const Array<int> *dof_map = NULL)
|
||||
|
||||
+311
-72
@@ -843,7 +843,20 @@ void TargetConstructor::ComputeAvgVolume() const
|
||||
#endif
|
||||
}
|
||||
|
||||
// virtual method
|
||||
bool TargetConstructor::ContainsVolumeInfo() const
|
||||
{
|
||||
switch (target_type)
|
||||
{
|
||||
case IDEAL_SHAPE_UNIT_SIZE: return false;
|
||||
case IDEAL_SHAPE_EQUAL_SIZE:
|
||||
case IDEAL_SHAPE_GIVEN_SIZE:
|
||||
case GIVEN_SHAPE_AND_SIZE:
|
||||
case GIVEN_FULL: return true;
|
||||
default: MFEM_ABORT("TargetType not added to ContainsVolumeInfo.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TargetConstructor::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
const IntegrationRule &ir,
|
||||
const Vector &elfun,
|
||||
@@ -1045,6 +1058,7 @@ void DiscreteAdaptTC::SetDiscreteTargetBase(const GridFunction &tspec_)
|
||||
// make a copy of tspec->tspec_temp, increase its size, and
|
||||
// copy data from tspec_temp -> tspec, then add new entries
|
||||
Vector tspec_temp = tspec;
|
||||
tspec.UseDevice(true);
|
||||
tspec.SetSize(ncomp*dof_cnt);
|
||||
|
||||
for (int i = 0; i < tspec_temp.Size(); i++)
|
||||
@@ -1196,11 +1210,12 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
ntspec_dofs = ndofs*ncomp;
|
||||
|
||||
Vector shape(ndofs), tspec_vals(ntspec_dofs), par_vals,
|
||||
par_vals_c1(ndofs), par_vals_c2(ndofs), par_vals_c3(ndofs);
|
||||
par_vals_c1, par_vals_c2, par_vals_c3;
|
||||
|
||||
Array<int> dofs;
|
||||
DenseMatrix D_rho(dim), Q_phi(dim), R_theta(dim);
|
||||
tspec_fesv->GetElementVDofs(e_id, dofs);
|
||||
tspec.UseDevice(true);
|
||||
tspec.GetSubVector(dofs, tspec_vals);
|
||||
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
@@ -1237,9 +1252,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
{
|
||||
par_vals.SetDataAndSize(tspec_vals.GetData()+
|
||||
aspectratioidx*ndofs, ndofs*3);
|
||||
par_vals_c1.SetData(par_vals.GetData());
|
||||
par_vals_c2.SetData(par_vals.GetData()+ndofs);
|
||||
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
|
||||
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
|
||||
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
|
||||
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
|
||||
|
||||
const double rho1 = shape * par_vals_c1;
|
||||
const double rho2 = shape * par_vals_c2;
|
||||
@@ -1272,9 +1287,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
{
|
||||
par_vals.SetDataAndSize(tspec_vals.GetData()+
|
||||
skewidx*ndofs, ndofs*3);
|
||||
par_vals_c1.SetData(par_vals.GetData());
|
||||
par_vals_c2.SetData(par_vals.GetData()+ndofs);
|
||||
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
|
||||
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
|
||||
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
|
||||
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
|
||||
|
||||
const double phi12 = shape * par_vals_c1;
|
||||
const double phi13 = shape * par_vals_c2;
|
||||
@@ -1312,9 +1327,9 @@ void DiscreteAdaptTC::ComputeElementTargets(int e_id, const FiniteElement &fe,
|
||||
{
|
||||
par_vals.SetDataAndSize(tspec_vals.GetData()+
|
||||
orientationidx*ndofs, ndofs*3);
|
||||
par_vals_c1.SetData(par_vals.GetData());
|
||||
par_vals_c2.SetData(par_vals.GetData()+ndofs);
|
||||
par_vals_c3.SetData(par_vals.GetData()+2*ndofs);
|
||||
par_vals_c1.SetDataAndSize(par_vals.GetData(), ndofs);
|
||||
par_vals_c2.SetDataAndSize(par_vals.GetData()+ndofs, ndofs);
|
||||
par_vals_c3.SetDataAndSize(par_vals.GetData()+2*ndofs, ndofs);
|
||||
|
||||
const double theta = shape * par_vals_c1;
|
||||
const double psi = shape * par_vals_c2;
|
||||
@@ -1471,6 +1486,17 @@ AdaptivityEvaluator::~AdaptivityEvaluator()
|
||||
#endif
|
||||
}
|
||||
|
||||
TMOP_Integrator::~TMOP_Integrator()
|
||||
{
|
||||
delete lim_func;
|
||||
delete zeta;
|
||||
for (int i = 0; i < ElemDer.Size(); i++)
|
||||
{
|
||||
delete ElemDer[i];
|
||||
delete ElemPertEnergy[i];
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::EnableLimiting(const GridFunction &n0,
|
||||
const GridFunction &dist, Coefficient &w0,
|
||||
TMOP_LimiterFunction *lfunc)
|
||||
@@ -1496,24 +1522,57 @@ void TMOP_Integrator::EnableLimiting(const GridFunction &n0, Coefficient &w0,
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::EnableAdaptiveLimiting(const GridFunction &z0,
|
||||
Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae)
|
||||
{
|
||||
zeta_0 = &z0;
|
||||
delete zeta;
|
||||
zeta = new GridFunction(z0);
|
||||
coeff_zeta = &coeff;
|
||||
adapt_eval = &ae;
|
||||
|
||||
adapt_eval->SetSerialMetaInfo(*zeta->FESpace()->GetMesh(),
|
||||
*zeta->FESpace()->FEColl(), 1);
|
||||
adapt_eval->SetInitialField
|
||||
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void TMOP_Integrator::EnableAdaptiveLimiting(const ParGridFunction &z0,
|
||||
Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae)
|
||||
{
|
||||
zeta_0 = &z0;
|
||||
delete zeta;
|
||||
zeta = new GridFunction(z0);
|
||||
coeff_zeta = &coeff;
|
||||
adapt_eval = &ae;
|
||||
|
||||
adapt_eval->SetParMetaInfo(*z0.ParFESpace()->GetParMesh(),
|
||||
*z0.ParFESpace()->FEColl(), 1);
|
||||
adapt_eval->SetInitialField
|
||||
(*zeta->FESpace()->GetMesh()->GetNodes(), *zeta);
|
||||
}
|
||||
#endif
|
||||
|
||||
double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun)
|
||||
{
|
||||
int dof = el.GetDof(), dim = el.GetDim();
|
||||
const int dof = el.GetDof(), dim = el.GetDim();
|
||||
double energy;
|
||||
|
||||
// No adaptive limiting terms if this is a FD computation.
|
||||
const bool adaptive_limiting = (zeta && fd_call_flag == false);
|
||||
|
||||
DSh.SetSize(dof, dim);
|
||||
Jrt.SetSize(dim);
|
||||
Jpr.SetSize(dim);
|
||||
Jpt.SetSize(dim);
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
}
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(el);
|
||||
|
||||
energy = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
@@ -1544,7 +1603,7 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
|
||||
// Define ref->physical transformation, when a Coefficient is specified.
|
||||
IsoparametricTransformation *Tpr = NULL;
|
||||
if (coeff1 || coeff0)
|
||||
if (coeff1 || coeff0 || adaptive_limiting)
|
||||
{
|
||||
Tpr = new IsoparametricTransformation;
|
||||
Tpr->SetFE(&el);
|
||||
@@ -1561,6 +1620,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
// the physical coordinates (i.e. changes in 'elfun'), e.g. when the
|
||||
// coefficient is a ConstantCoefficient or a GridFunctionCoefficient.
|
||||
|
||||
Vector zeta_q, zeta0_q;
|
||||
if (adaptive_limiting)
|
||||
{
|
||||
zeta->GetValues(T.ElementNo, *ir, zeta_q);
|
||||
zeta_0->GetValues(T.ElementNo, *ir, zeta0_q);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
@@ -1584,6 +1650,13 @@ double TMOP_Integrator::GetElementEnergy(const FiniteElement &el,
|
||||
val += lim_normal *
|
||||
lim_func->Eval(p, p0, d_vals(i)) * coeff0->Eval(*Tpr, ip);
|
||||
}
|
||||
|
||||
if (adaptive_limiting)
|
||||
{
|
||||
const double diff = zeta_q(i) - zeta0_q(i);
|
||||
val += coeff_zeta->Eval(*Tpr, ip) * lim_normal * diff * diff;
|
||||
}
|
||||
|
||||
energy += weight * val;
|
||||
}
|
||||
delete Tpr;
|
||||
@@ -1621,9 +1694,10 @@ void TMOP_Integrator::AssembleElementGrad(const FiniteElement &el,
|
||||
|
||||
void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun, Vector &elvect)
|
||||
const Vector &elfun,
|
||||
Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof(), dim = el.GetDim();
|
||||
const int dof = el.GetDof(), dim = el.GetDim();
|
||||
|
||||
DSh.SetSize(dof, dim);
|
||||
DS.SetSize(dof, dim);
|
||||
@@ -1634,14 +1708,12 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
elvect.SetSize(dof*dim);
|
||||
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
}
|
||||
const IntegrationRule *ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
|
||||
elvect = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
Vector weights(nqp);
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
|
||||
// Limited case.
|
||||
@@ -1663,13 +1735,13 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
}
|
||||
else
|
||||
{
|
||||
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
|
||||
d_vals.SetSize(nqp); d_vals = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Define ref->physical transformation, when a Coefficient is specified.
|
||||
IsoparametricTransformation *Tpr = NULL;
|
||||
if (coeff1 || coeff0)
|
||||
if (coeff1 || coeff0 || zeta)
|
||||
{
|
||||
Tpr = new IsoparametricTransformation;
|
||||
Tpr->SetFE(&el);
|
||||
@@ -1679,14 +1751,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
Tpr->GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
const DenseMatrix &Jtr_i = Jtr(i);
|
||||
metric->SetTargetJacobian(Jtr_i);
|
||||
CalcInverse(Jtr_i, Jrt);
|
||||
const double weight = ip.weight * Jtr_i.Det();
|
||||
double weight_m = weight * metric_normal;
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
const DenseMatrix &Jtr_q = Jtr(q);
|
||||
metric->SetTargetJacobian(Jtr_q);
|
||||
CalcInverse(Jtr_q, Jrt);
|
||||
weights(q) = ip.weight * Jtr_q.Det();
|
||||
double weight_m = weights(q) * metric_normal;
|
||||
|
||||
el.CalcDShape(ip, DSh);
|
||||
Mult(DSh, Jrt, DS);
|
||||
@@ -1706,11 +1778,14 @@ void TMOP_Integrator::AssembleElementVectorExact(const FiniteElement &el,
|
||||
el.CalcShape(ip, shape);
|
||||
PMatI.MultTranspose(shape, p);
|
||||
pos0.MultTranspose(shape, p0);
|
||||
lim_func->Eval_d1(p, p0, d_vals(i), grad);
|
||||
grad *= weight * lim_normal * coeff0->Eval(*Tpr, ip);
|
||||
lim_func->Eval_d1(p, p0, d_vals(q), grad);
|
||||
grad *= weights(q) * lim_normal * coeff0->Eval(*Tpr, ip);
|
||||
AddMultVWt(shape, grad, PMatO);
|
||||
}
|
||||
}
|
||||
|
||||
if (zeta) { AssembleElemVecAdaptLim(el, weights, *Tpr, *ir, PMatO); }
|
||||
|
||||
delete Tpr;
|
||||
}
|
||||
|
||||
@@ -1719,7 +1794,7 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
const Vector &elfun,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int dof = el.GetDof(), dim = el.GetDim();
|
||||
const int dof = el.GetDof(), dim = el.GetDim();
|
||||
|
||||
DSh.SetSize(dof, dim);
|
||||
DS.SetSize(dof, dim);
|
||||
@@ -1728,14 +1803,12 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
elmat.SetSize(dof*dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
}
|
||||
const IntegrationRule *ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
|
||||
elmat = 0.0;
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
Vector weights(nqp);
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
|
||||
// Limited case.
|
||||
@@ -1757,13 +1830,13 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
}
|
||||
else
|
||||
{
|
||||
d_vals.SetSize(ir->GetNPoints()); d_vals = 1.0;
|
||||
d_vals.SetSize(nqp); d_vals = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Define ref->physical transformation, when a Coefficient is specified.
|
||||
IsoparametricTransformation *Tpr = NULL;
|
||||
if (coeff1 || coeff0)
|
||||
if (coeff1 || coeff0 || zeta)
|
||||
{
|
||||
Tpr = new IsoparametricTransformation;
|
||||
Tpr->SetFE(&el);
|
||||
@@ -1773,14 +1846,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
Tpr->GetPointMat().Transpose(PMatI);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
const DenseMatrix &Jtr_i = Jtr(i);
|
||||
metric->SetTargetJacobian(Jtr_i);
|
||||
CalcInverse(Jtr_i, Jrt);
|
||||
const double weight = ip.weight * Jtr_i.Det();
|
||||
double weight_m = weight * metric_normal;
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
const DenseMatrix &Jtr_q = Jtr(q);
|
||||
metric->SetTargetJacobian(Jtr_q);
|
||||
CalcInverse(Jtr_q, Jrt);
|
||||
weights(q) = ip.weight * Jtr_q.Det();
|
||||
double weight_m = weights(q) * metric_normal;
|
||||
|
||||
el.CalcDShape(ip, DSh);
|
||||
Mult(DSh, Jrt, DS);
|
||||
@@ -1792,13 +1865,14 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
|
||||
// TODO: derivatives of adaptivity-based targets.
|
||||
|
||||
// TODO optimize by symmetry.
|
||||
if (coeff0)
|
||||
{
|
||||
el.CalcShape(ip, shape);
|
||||
PMatI.MultTranspose(shape, p);
|
||||
pos0.MultTranspose(shape, p0);
|
||||
weight_m = weight * lim_normal * coeff0->Eval(*Tpr, ip);
|
||||
lim_func->Eval_d2(p, p0, d_vals(i), grad_grad);
|
||||
weight_m = weights(q) * lim_normal * coeff0->Eval(*Tpr, ip);
|
||||
lim_func->Eval_d2(p, p0, d_vals(q), grad_grad);
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const double w_shape_i = weight_m * shape(i);
|
||||
@@ -1816,9 +1890,115 @@ void TMOP_Integrator::AssembleElementGradExact(const FiniteElement &el,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zeta) { AssembleElemGradAdaptLim(el, weights, *Tpr, *ir, elmat); }
|
||||
|
||||
delete Tpr;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleElemVecAdaptLim(const FiniteElement &el,
|
||||
const Vector &weights,
|
||||
IsoparametricTransformation &Tpr,
|
||||
const IntegrationRule &ir,
|
||||
DenseMatrix &mat)
|
||||
{
|
||||
if (zeta == NULL) { return; }
|
||||
|
||||
const int dof = el.GetDof(), dim = el.GetDim();
|
||||
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
|
||||
|
||||
Array<int> dofs;
|
||||
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
|
||||
zeta->GetSubVector(dofs, zeta_e);
|
||||
zeta->GetValues(Tpr.ElementNo, ir, zeta_q);
|
||||
zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q);
|
||||
|
||||
// Project the gradient of zeta in the same space.
|
||||
// The FE coefficients of the gradient go in zeta_grad_e.
|
||||
DenseMatrix zeta_grad_e(dof, dim);
|
||||
DenseMatrix grad_phys; // This will be (dof x dim, dof).
|
||||
el.ProjectGrad(el, Tpr, grad_phys);
|
||||
Vector grad_ptr(zeta_grad_e.GetData(), dof*dim);
|
||||
grad_phys.Mult(zeta_e, grad_ptr);
|
||||
|
||||
Vector zeta_grad_q(dim);
|
||||
|
||||
const int nqp = weights.Size();
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
el.CalcShape(ip, shape);
|
||||
zeta_grad_e.MultTranspose(shape, zeta_grad_q);
|
||||
zeta_grad_q *= 2.0 * (zeta_q(q) - zeta0_q(q));
|
||||
zeta_grad_q *= weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip);
|
||||
AddMultVWt(shape, zeta_grad_q, mat);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleElemGradAdaptLim(const FiniteElement &el,
|
||||
const Vector &weights,
|
||||
IsoparametricTransformation &Tpr,
|
||||
const IntegrationRule &ir,
|
||||
DenseMatrix &mat)
|
||||
{
|
||||
if (zeta == NULL) { return; }
|
||||
|
||||
const int dof = el.GetDof(), dim = el.GetDim();
|
||||
Vector shape(dof), zeta_e, zeta_q, zeta0_q;
|
||||
|
||||
Array<int> dofs;
|
||||
zeta->FESpace()->GetElementDofs(Tpr.ElementNo, dofs);
|
||||
zeta->GetSubVector(dofs, zeta_e);
|
||||
zeta->GetValues(Tpr.ElementNo, ir, zeta_q);
|
||||
zeta_0->GetValues(Tpr.ElementNo, ir, zeta0_q);
|
||||
|
||||
// Project the gradient of zeta in the same space.
|
||||
// The FE coefficients of the gradient go in zeta_grad_e.
|
||||
DenseMatrix zeta_grad_e(dof, dim);
|
||||
DenseMatrix grad_phys; // This will be (dof x dim, dof).
|
||||
el.ProjectGrad(el, Tpr, grad_phys);
|
||||
Vector grad_ptr(zeta_grad_e.GetData(), dof*dim);
|
||||
grad_phys.Mult(zeta_e, grad_ptr);
|
||||
|
||||
// Project the gradient of each gradient of zeta in the same space.
|
||||
// The FE coefficients of the second derivatives go in zeta_grad_grad_e.
|
||||
DenseMatrix zeta_grad_grad_e(dof*dim, dim);
|
||||
Mult(grad_phys, zeta_grad_e, zeta_grad_grad_e);
|
||||
// Reshape to be more convenient later (no change in the data).
|
||||
zeta_grad_grad_e.SetSize(dof, dim*dim);
|
||||
|
||||
Vector zeta_grad_q(dim);
|
||||
DenseMatrix zeta_grad_grad_q(dim, dim);
|
||||
|
||||
const int nqp = weights.Size();
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(q);
|
||||
el.CalcShape(ip, shape);
|
||||
|
||||
zeta_grad_e.MultTranspose(shape, zeta_grad_q);
|
||||
Vector gg_ptr(zeta_grad_grad_q.GetData(), dim*dim);
|
||||
zeta_grad_grad_e.MultTranspose(shape, gg_ptr);
|
||||
|
||||
const double w = weights(q) * lim_normal * coeff_zeta->Eval(Tpr, ip);
|
||||
for (int i = 0; i < dof * dim; i++)
|
||||
{
|
||||
const int idof = i % dof, idim = i / dof;
|
||||
for (int j = 0; j <= i; j++)
|
||||
{
|
||||
const int jdof = j % dof, jdim = j / dof;
|
||||
const double entry =
|
||||
w * ( 2.0 * zeta_grad_q(idim) * shape(idof) *
|
||||
/* */ zeta_grad_q(jdim) * shape(jdof) +
|
||||
2.0 * (zeta_q(q) - zeta0_q(q)) *
|
||||
zeta_grad_grad_q(idim, jdim) * shape(idof) * shape(jdof));
|
||||
mat(i, j) += entry;
|
||||
if (i != j) { mat(j, i) += entry; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double TMOP_Integrator::GetFDDerivative(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
Vector &elfun, const int dofidx,
|
||||
@@ -1858,8 +2038,11 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
|
||||
elvect.SetSize(dof*dim);
|
||||
Vector elfunmod(elfun);
|
||||
|
||||
// Energy for unperturbed configuration
|
||||
double e_fx = GetElementEnergy(el, T, elfun);
|
||||
// In GetElementEnergy(), skip terms that have exact derivative calculations.
|
||||
fd_call_flag = true;
|
||||
|
||||
// Energy for unperturbed configuration.
|
||||
const double e_fx = GetElementEnergy(el, T, elfun);
|
||||
|
||||
for (int j = 0; j < dim; j++)
|
||||
{
|
||||
@@ -1874,6 +2057,32 @@ void TMOP_Integrator::AssembleElementVectorFD(const FiniteElement &el,
|
||||
if (discr_tc) { discr_tc->RestoreTargetSpecificationAtNode(T, i); }
|
||||
}
|
||||
}
|
||||
fd_call_flag = false;
|
||||
|
||||
// Contributions from adaptive limiting (exact derivatives).
|
||||
if (zeta)
|
||||
{
|
||||
const IntegrationRule *ir = ActionIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
|
||||
IsoparametricTransformation Tpr;
|
||||
Tpr.SetFE(&el);
|
||||
Tpr.ElementNo = T.ElementNo;
|
||||
Tpr.Attribute = T.Attribute;
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
|
||||
|
||||
Vector weights(nqp);
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
|
||||
}
|
||||
|
||||
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
||||
AssembleElemVecAdaptLim(el, weights, Tpr, *ir, PMatO);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
|
||||
@@ -1889,6 +2098,8 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
|
||||
const Vector &ElemDerLoc = *(ElemDer[T.ElementNo]);
|
||||
const Vector &ElemPertLoc = *(ElemPertEnergy[T.ElementNo]);
|
||||
|
||||
// In GetElementEnergy(), skip terms that have exact derivative calculations.
|
||||
fd_call_flag = true;
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
for (int j = 0; j < i+1; j++)
|
||||
@@ -1942,6 +2153,31 @@ void TMOP_Integrator::AssembleElementGradFD(const FiniteElement &el,
|
||||
}
|
||||
}
|
||||
}
|
||||
fd_call_flag = false;
|
||||
|
||||
// Contributions from adaptive limiting.
|
||||
if (zeta)
|
||||
{
|
||||
const IntegrationRule *ir = GradientIntegrationRule(el);
|
||||
const int nqp = ir->GetNPoints();
|
||||
DenseTensor Jtr(dim, dim, nqp);
|
||||
targetC->ComputeElementTargets(T.ElementNo, el, *ir, elfun, Jtr);
|
||||
|
||||
IsoparametricTransformation Tpr;
|
||||
Tpr.SetFE(&el);
|
||||
Tpr.ElementNo = T.ElementNo;
|
||||
Tpr.Attribute = T.Attribute;
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
Tpr.GetPointMat().Transpose(PMatI); // PointMat = PMatI^T
|
||||
|
||||
Vector weights(nqp);
|
||||
for (int q = 0; q < nqp; q++)
|
||||
{
|
||||
weights(q) = ir->IntPoint(q).weight * Jtr(q).Det();
|
||||
}
|
||||
|
||||
AssembleElemGradAdaptLim(el, weights, Tpr, *ir, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::EnableNormalization(const GridFunction &x)
|
||||
@@ -1958,7 +2194,8 @@ void TMOP_Integrator::ParEnableNormalization(const ParGridFunction &x)
|
||||
ComputeNormalizationEnergies(x, loc[0], loc[1]);
|
||||
double rdc[2];
|
||||
MPI_Allreduce(loc, rdc, 2, MPI_DOUBLE, MPI_SUM, x.ParFESpace()->GetComm());
|
||||
metric_normal = 1.0 / rdc[0]; lim_normal = 1.0 / rdc[1];
|
||||
metric_normal = 1.0 / rdc[0];
|
||||
lim_normal = 1.0 / rdc[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1978,12 +2215,7 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
|
||||
Jpr.SetSize(dim);
|
||||
Jpt.SetSize(dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), 2*fe->GetOrder() + 3)); // <---
|
||||
}
|
||||
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
|
||||
DenseTensor Jtr(dim, dim, ir->GetNPoints());
|
||||
|
||||
metric_energy = 0.0;
|
||||
@@ -2012,19 +2244,20 @@ void TMOP_Integrator::ComputeNormalizationEnergies(const GridFunction &x,
|
||||
lim_energy += weight;
|
||||
}
|
||||
}
|
||||
if (targetC->ContainsVolumeInfo() == false)
|
||||
{
|
||||
// Special case when the targets don't contain volumetric information.
|
||||
lim_energy = fes->GetNE();
|
||||
}
|
||||
}
|
||||
|
||||
void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
const FiniteElementSpace &fes)
|
||||
{
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(fes.GetFE(0)->GetGeomType(),
|
||||
2*fes.GetFE(0)->GetOrder() + 3)); // <---
|
||||
}
|
||||
const int NE = fes.GetMesh()->GetNE(), dim = fes.GetFE(0)->GetDim(),
|
||||
dof = fes.GetFE(0)->GetDof(), nsp = ir->GetNPoints();
|
||||
const FiniteElement *fe = fes.GetFE(0);
|
||||
const IntegrationRule *ir = EnergyIntegrationRule(*fe);
|
||||
const int NE = fes.GetMesh()->GetNE(), dim = fe->GetDim(),
|
||||
dof = fe->GetDof(), nsp = ir->GetNPoints();
|
||||
|
||||
Array<int> xdofs(dof * dim);
|
||||
DenseMatrix Jpr(dim), dshape(dof, dim), pos(dof, dim);
|
||||
@@ -2051,6 +2284,12 @@ void TMOP_Integrator::ComputeMinJac(const Vector &x,
|
||||
dx = detv_avg_min / dxscale;
|
||||
}
|
||||
|
||||
void TMOP_Integrator::UpdateAfterMeshChange(const Vector &new_x)
|
||||
{
|
||||
// Update zeta if adaptive limiting is enabled.
|
||||
if (zeta) { adapt_eval->ComputeAtNewPosition(new_x, *zeta); }
|
||||
}
|
||||
|
||||
void TMOP_Integrator::ComputeFDh(const Vector &x, const FiniteElementSpace &fes)
|
||||
{
|
||||
if (!fdflag) { return; }
|
||||
|
||||
+73
-23
@@ -598,7 +598,8 @@ public:
|
||||
supports a set of algorithms chosen by the #TargetType enumeration.
|
||||
|
||||
New target-matrix construction algorithms can be defined by deriving new
|
||||
classes and overriding the method ComputeElementTargets(). */
|
||||
classes and overriding the methods ComputeElementTargets() and
|
||||
ContainsVolumeInfo(). */
|
||||
class TargetConstructor
|
||||
{
|
||||
public:
|
||||
@@ -666,6 +667,9 @@ public:
|
||||
/// Used by target type IDEAL_SHAPE_EQUAL_SIZE. The default volume scale is 1.
|
||||
void SetVolumeScale(double vol_scale) { volume_scale = vol_scale; }
|
||||
|
||||
/// Checks if the target matrices contain non-trivial size specification.
|
||||
virtual bool ContainsVolumeInfo() const;
|
||||
|
||||
/** @brief Given an element and quadrature rule, computes ref->target
|
||||
transformation Jacobians for each quadrature point in the element.
|
||||
The physical positions of the element's nodes are given by @a elfun. */
|
||||
@@ -870,12 +874,21 @@ protected:
|
||||
// Normalization factor for the limiting term.
|
||||
double lim_normal;
|
||||
|
||||
// Adaptive limiting.
|
||||
const GridFunction *zeta_0; // Not owned.
|
||||
GridFunction *zeta; // Owned. Updated by adapt_eval.
|
||||
Coefficient *coeff_zeta; // Not owned.
|
||||
AdaptivityEvaluator *adapt_eval; // Not owned.
|
||||
|
||||
DiscreteAdaptTC *discr_tc;
|
||||
|
||||
// Parameters for FD-based Gradient & Hessian calculation.
|
||||
bool fdflag;
|
||||
bool fdflag;
|
||||
double dx;
|
||||
double dxscale;
|
||||
// Specifies that ComputeElementTargets is being called by a FD function.
|
||||
// It's used to skip terms that have exact derivative calculations.
|
||||
bool fd_call_flag;
|
||||
|
||||
Array <Vector *> ElemDer; //f'(x)
|
||||
Array <Vector *> ElemPertEnergy; //f(x+h)
|
||||
@@ -908,11 +921,18 @@ protected:
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun, Vector &elvect);
|
||||
|
||||
/** Assumes that AssembleElementVectorFD has been called. */
|
||||
// Assumes that AssembleElementVectorFD has been called.
|
||||
void AssembleElementGradFD(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
const Vector &elfun, DenseMatrix &elmat);
|
||||
|
||||
void AssembleElemVecAdaptLim(const FiniteElement &el, const Vector &weights,
|
||||
IsoparametricTransformation &Tpr,
|
||||
const IntegrationRule &ir, DenseMatrix &m);
|
||||
void AssembleElemGradAdaptLim(const FiniteElement &el, const Vector &weights,
|
||||
IsoparametricTransformation &Tpr,
|
||||
const IntegrationRule &ir, DenseMatrix &m);
|
||||
|
||||
double GetFDDerivative(const FiniteElement &el,
|
||||
ElementTransformation &T,
|
||||
Vector &elfun, const int nodenum,const int idir,
|
||||
@@ -925,11 +945,29 @@ protected:
|
||||
#endif
|
||||
void ComputeMinJac(const Vector &x, const FiniteElementSpace &fes);
|
||||
|
||||
void UpdateAfterMeshChange(const Vector &new_x);
|
||||
|
||||
void DisableLimiting()
|
||||
{
|
||||
nodes0 = NULL; coeff0 = NULL; lim_dist = NULL; lim_func = NULL;
|
||||
}
|
||||
|
||||
const IntegrationRule *EnergyIntegrationRule(const FiniteElement &el) const
|
||||
{
|
||||
return (IntRule) ? IntRule
|
||||
/* */ : &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3));
|
||||
}
|
||||
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
|
||||
{
|
||||
// TODO the action and energy most likely need less integration points.
|
||||
return EnergyIntegrationRule(el);
|
||||
}
|
||||
|
||||
public:
|
||||
/** @param[in] m TMOP_QualityMetric that will be integrated (not owned).
|
||||
@param[in] tc Target-matrix construction algorithm to use (not owned). */
|
||||
@@ -938,19 +976,12 @@ public:
|
||||
coeff1(NULL), metric_normal(1.0),
|
||||
nodes0(NULL), coeff0(NULL),
|
||||
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
|
||||
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
|
||||
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
|
||||
fdflag(false), dxscale(1.0e3)
|
||||
fdflag(false), dxscale(1.0e3), fd_call_flag(false)
|
||||
{ }
|
||||
|
||||
~TMOP_Integrator()
|
||||
{
|
||||
delete lim_func;
|
||||
for (int i = 0; i < ElemDer.Size(); i++)
|
||||
{
|
||||
delete ElemDer[i];
|
||||
delete ElemPertEnergy[i];
|
||||
}
|
||||
}
|
||||
~TMOP_Integrator();
|
||||
|
||||
/// Sets a scaling Coefficient for the quality metric term of the integrator.
|
||||
/** With this addition, the integrator becomes
|
||||
@@ -960,15 +991,15 @@ public:
|
||||
not in the target configuration which may be undefined. */
|
||||
void SetCoefficient(Coefficient &w1) { coeff1 = &w1; }
|
||||
|
||||
/// Adds a limiting term to the integrator (general version).
|
||||
/** With this addition, the integrator becomes
|
||||
@f$ \int w1 W(Jpt) + w0 f(x, x_0, d) dx @f$,
|
||||
where the second term measures the change with respect to the original
|
||||
physical positions, @a n0.
|
||||
@param[in] n0 Original mesh node coordinates.
|
||||
@param[in] dist Limiting physical distances.
|
||||
@param[in] w0 Coefficient scaling the limiting term.
|
||||
@param[in] lfunc TMOP_LimiterFunction defining the limiting term f. If
|
||||
/** @brief Limiting of the mesh displacements (general version).
|
||||
|
||||
Adds the term @f$ \int w_0 f(x, x_0, d) dx @f$, where f is a measure of
|
||||
the displacement between x and x_0, given the max allowed displacement d.
|
||||
|
||||
@param[in] n0 Original mesh node coordinates (x0 above).
|
||||
@param[in] dist Allowed displacement in physical space (d above).
|
||||
@param[in] w0 Coefficient scaling the limiting integral.
|
||||
@param[in] lfunc TMOP_LimiterFunction defining the function f. If
|
||||
NULL, a TMOP_QuadraticLimiter will be used. The
|
||||
TMOP_Integrator assumes ownership of this pointer. */
|
||||
void EnableLimiting(const GridFunction &n0, const GridFunction &dist,
|
||||
@@ -979,6 +1010,25 @@ public:
|
||||
void EnableLimiting(const GridFunction &n0, Coefficient &w0,
|
||||
TMOP_LimiterFunction *lfunc = NULL);
|
||||
|
||||
/** @brief Restriction of the node positions to certain regions.
|
||||
|
||||
Adds the term @f$ \int c (z(x) - z_0(x_0))^2 @f$, where z0(x0) is a given
|
||||
function on the starting mesh, and z(x) is its image on the new mesh.
|
||||
Minimizing this, means that a node at x0 is allowed to move to a
|
||||
position x(x0) only if z(x) ~ z0(x0).
|
||||
Such term can be used for tangential mesh relaxation.
|
||||
|
||||
@param[in] z0 Function z0 that controls the adaptive limiting.
|
||||
@param[in] coeff Coefficient c for the above integral.
|
||||
@param[in] ae AdaptivityEvaluator to compute z(x) from z0(x0). */
|
||||
void EnableAdaptiveLimiting(const GridFunction &z0, Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae);
|
||||
#ifdef MFEM_USE_MPI
|
||||
/// Parallel support for adaptive limiting.
|
||||
void EnableAdaptiveLimiting(const ParGridFunction &z0, Coefficient &coeff,
|
||||
AdaptivityEvaluator &ae);
|
||||
#endif
|
||||
|
||||
/// Update the original/reference nodes used for limiting.
|
||||
void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; }
|
||||
|
||||
@@ -1035,7 +1085,7 @@ public:
|
||||
/// Adds a new TMOP_Integrator to the combination.
|
||||
void AddTMOPIntegrator(TMOP_Integrator *ti) { tmopi.Append(ti); }
|
||||
|
||||
Array<TMOP_Integrator *> GetTMOPIntegrators() const { return tmopi; }
|
||||
const Array<TMOP_Integrator *> &GetTMOPIntegrators() const { return tmopi; }
|
||||
|
||||
/// Adds the limiting term to the first integrator. Disables it for the rest.
|
||||
void EnableLimiting(const GridFunction &n0, const GridFunction &dist,
|
||||
|
||||
+7
-2
@@ -33,10 +33,11 @@ void AdvectorCG::ComputeAtNewPosition(const Vector &new_nodes,
|
||||
const int pnt_cnt = new_field.Size()/ncomp;
|
||||
|
||||
new_field = field0;
|
||||
|
||||
new_field.HostReadWrite();
|
||||
Vector new_field_temp;
|
||||
for (int i = 0; i < ncomp; i++)
|
||||
{
|
||||
Vector new_field_temp(new_field.GetData()+i*pnt_cnt, pnt_cnt);
|
||||
new_field_temp.MakeRef(new_field, i*pnt_cnt, pnt_cnt);
|
||||
ComputeAtNewPositionScalar(new_nodes, new_field_temp);
|
||||
}
|
||||
|
||||
@@ -94,6 +95,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
double v_max = 0.0;
|
||||
const int s = new_field.Size();
|
||||
|
||||
u.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
double vel = 0.;
|
||||
@@ -149,6 +151,7 @@ void AdvectorCG::ComputeAtNewPositionScalar(const Vector &new_nodes,
|
||||
#endif
|
||||
|
||||
// Trim the overshoots and undershoots.
|
||||
new_field.HostReadWrite();
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
if (new_field(i) < glob_minv) { new_field(i) = glob_minv; }
|
||||
@@ -499,6 +502,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
|
||||
if (ti)
|
||||
{
|
||||
ti->UpdateAfterMeshChange(x_loc);
|
||||
ti->ComputeFDh(x_loc, *pfesc);
|
||||
UpdateDiscreteTC(*ti, x_loc);
|
||||
}
|
||||
@@ -534,6 +538,7 @@ void TMOPNewtonSolver::ProcessNewState(const Vector &x) const
|
||||
ti = dynamic_cast<TMOP_Integrator *>(integs[i]);
|
||||
if (ti)
|
||||
{
|
||||
ti->UpdateAfterMeshChange(x_loc);
|
||||
ti->ComputeFDh(x_loc, *fesc);
|
||||
UpdateDiscreteTC(*ti, x_loc);
|
||||
}
|
||||
|
||||
+51
-34
@@ -60,31 +60,31 @@ public:
|
||||
/// Creates an empty array with a given MemoryType
|
||||
inline Array(MemoryType mt) : size(0) { data.Reset(mt); }
|
||||
|
||||
/// Creates array of asize elements
|
||||
/// Creates array of @a asize elements
|
||||
explicit inline Array(int asize)
|
||||
: size(asize) { asize > 0 ? data.New(asize) : data.Reset(); }
|
||||
|
||||
/** Creates array using an existing c-array of asize elements;
|
||||
/** @brief Creates array using an existing c-array of asize elements;
|
||||
allocsize is set to -asize to indicate that the data will not
|
||||
be deleted. */
|
||||
inline Array(T *_data, int asize)
|
||||
{ data.Wrap(_data, asize, false); size = asize; }
|
||||
|
||||
/// Copy constructor: deep copy
|
||||
/// Copy constructor: deep copy from @a src
|
||||
/** This method supports source arrays using any MemoryType. */
|
||||
inline Array(const Array &src);
|
||||
|
||||
/// Copy constructor (deep copy) from an Array of convertable type
|
||||
/// Copy constructor (deep copy) from 'src', an Array of convertible type.
|
||||
template <typename CT>
|
||||
inline Array(const Array<CT> &src);
|
||||
|
||||
/// Destructor
|
||||
inline ~Array() { data.Delete(); }
|
||||
|
||||
/// Assignment operator: deep copy
|
||||
/// Assignment operator: deep copy from 'src'.
|
||||
Array<T> &operator=(const Array<T> &src) { src.Copy(*this); return *this; }
|
||||
|
||||
/// Assignment operator (deep copy) from an Array of convertable type
|
||||
/// Assignment operator (deep copy) from @a src, an Array of convertible type.
|
||||
template <typename CT>
|
||||
inline Array &operator=(const Array<CT> &src);
|
||||
|
||||
@@ -120,13 +120,13 @@ public:
|
||||
/// Make the Array own the data
|
||||
void MakeDataOwner() const { data.SetHostPtrOwner(true); }
|
||||
|
||||
/// Logical size of the array
|
||||
/// Return the logical size of the array.
|
||||
inline int Size() const { return size; }
|
||||
|
||||
/// Change logical size of the array, keep existing entries
|
||||
/// Change the logical size of the array, keep existing entries.
|
||||
inline void SetSize(int nsize);
|
||||
|
||||
/// Same as SetSize(int) plus initialize new entries with 'initval'
|
||||
/// Same as SetSize(int) plus initialize new entries with 'initval'.
|
||||
inline void SetSize(int nsize, const T &initval);
|
||||
|
||||
/** @brief Resize the array to size @a nsize using MemoryType @a mt. Note
|
||||
@@ -142,58 +142,63 @@ public:
|
||||
inline void Reserve(int capacity)
|
||||
{ if (capacity > Capacity()) { GrowSize(capacity); } }
|
||||
|
||||
/// Access element
|
||||
/// Reference access to the ith element.
|
||||
inline T & operator[](int i);
|
||||
|
||||
/// Access const element
|
||||
/// Const reference access to the ith element.
|
||||
inline const T &operator[](int i) const;
|
||||
|
||||
/// Append element to array, resize if necessary
|
||||
/// Append element 'el' to array, resize if necessary.
|
||||
inline int Append(const T & el);
|
||||
|
||||
/// Append another array to this array, resize if necessary
|
||||
/// Append another array to this array, resize if necessary.
|
||||
inline int Append(const T *els, int nels);
|
||||
|
||||
/// Append another array to this array, resize if necessary
|
||||
/// Append another array to this array, resize if necessary.
|
||||
inline int Append(const Array<T> &els) { return Append(els, els.Size()); }
|
||||
|
||||
/// Prepend an element to the array, resize if necessary
|
||||
/// Prepend an 'el' to the array, resize if necessary.
|
||||
inline int Prepend(const T &el);
|
||||
|
||||
/// Return the last element in the array
|
||||
/// Return the last element in the array.
|
||||
inline T &Last();
|
||||
|
||||
/// Return the last element in the array.
|
||||
inline const T &Last() const;
|
||||
|
||||
/// Append element when it is not yet in the array, return index
|
||||
/// Append element when it is not yet in the array, return index.
|
||||
inline int Union(const T & el);
|
||||
|
||||
/// Return the first index where 'el' is found; return -1 if not found
|
||||
/// Return the first index where 'el' is found; return -1 if not found.
|
||||
inline int Find(const T &el) const;
|
||||
|
||||
/// Do bisection search for 'el' in a sorted array; return -1 if not found.
|
||||
inline int FindSorted(const T &el) const;
|
||||
|
||||
/// Delete the last entry
|
||||
/// Delete the last entry of the array.
|
||||
inline void DeleteLast() { if (size > 0) { size--; } }
|
||||
|
||||
/// Delete the first 'el' entry
|
||||
/// Delete the first entry with value == 'el'.
|
||||
inline void DeleteFirst(const T &el);
|
||||
|
||||
/// Delete whole array
|
||||
/// Delete the whole array.
|
||||
inline void DeleteAll();
|
||||
|
||||
/// Create a copy of the current array
|
||||
|
||||
/// Create a copy of the internal array to the provided @a copy.
|
||||
inline void Copy(Array ©) const;
|
||||
|
||||
/// Make this Array a reference to a pointer
|
||||
/// Make this Array a reference to a pointer.
|
||||
inline void MakeRef(T *, int);
|
||||
|
||||
/// Make this Array a reference to 'master'
|
||||
/// Make this Array a reference to 'master'.
|
||||
inline void MakeRef(const Array &master);
|
||||
|
||||
|
||||
/// Copy sub array starting from @a offset out to the provided @a sa.
|
||||
inline void GetSubArray(int offset, int sa_size, Array<T> &sa) const;
|
||||
|
||||
/// Prints array to stream with width elements per row
|
||||
/// Prints array to stream with width elements per row.
|
||||
void Print(std::ostream &out = mfem::out, int width = 4) const;
|
||||
|
||||
/** @brief Save the Array to the stream @a out using the format @a fmt.
|
||||
@@ -225,48 +230,60 @@ public:
|
||||
operator `<` for class T. */
|
||||
T Min() const;
|
||||
|
||||
/// Sorts the array. This requires operator< to be defined for T.
|
||||
/// Sorts the array in ascending order. This requires operator< to be defined for T.
|
||||
void Sort() { std::sort((T*)data, data + size); }
|
||||
|
||||
/// Sorts the array using the supplied comparison function object.
|
||||
/// Sorts the array in ascending order using the supplied comparison function object.
|
||||
template<class Compare>
|
||||
void Sort(Compare cmp) { std::sort((T*)data, data + size, cmp); }
|
||||
|
||||
/** Removes duplicities from a sorted array. This requires operator== to be
|
||||
defined for T. */
|
||||
/** @brief Removes duplicities from a sorted array. This requires
|
||||
operator== to be defined for T. */
|
||||
void Unique()
|
||||
{
|
||||
T* end = std::unique((T*)data, data + size);
|
||||
SetSize(end - data);
|
||||
}
|
||||
|
||||
/// return true if the array is sorted.
|
||||
/// Return 1 if the array is sorted from lowest to highest. Otherwise return 0.
|
||||
int IsSorted();
|
||||
|
||||
/// Partial Sum
|
||||
/// Fill the entries of the array with the cumulative sum of the entries.
|
||||
void PartialSum();
|
||||
|
||||
/// Sum all entries
|
||||
/// Return the sum of all the array entries using the '+'' operator for class 'T'.
|
||||
T Sum();
|
||||
|
||||
/// Set all entries of the array to the provided constant.
|
||||
inline void operator=(const T &a);
|
||||
|
||||
/// Copy data from a pointer. Size() elements are copied.
|
||||
/// Copy data from a pointer. 'Size()' elements are copied.
|
||||
inline void Assign(const T *);
|
||||
|
||||
/// STL-like copyTo @a dest from begin to end.
|
||||
template <typename U>
|
||||
inline void CopyTo(U *dest) { std::copy(begin(), end(), dest); }
|
||||
|
||||
/** @brief Copy from @a src into this array. Copies enough entries to
|
||||
fill the Capacity size of this array. Careful this does not update
|
||||
the Size to match this Capacity after this.*/
|
||||
template <typename U>
|
||||
inline void CopyFrom(const U *src)
|
||||
{ std::memcpy(begin(), src, MemoryUsage()); }
|
||||
|
||||
// STL-like begin/end
|
||||
/// STL-like begin. Returns pointer to the first element of the array.
|
||||
inline T* begin() { return data; }
|
||||
|
||||
/// STL-like end. Returns pointer after the last element of the array.
|
||||
inline T* end() { return data + size; }
|
||||
|
||||
/// STL-like begin. Returns const pointer to the first element of the array.
|
||||
inline const T* begin() const { return data; }
|
||||
|
||||
/// STL-like end. Returns const pointer after the last element of the array.
|
||||
inline const T* end() const { return data + size; }
|
||||
|
||||
/// Returns the number of bytes allocated for the array including any reserve.
|
||||
long MemoryUsage() const { return Capacity() * sizeof(T); }
|
||||
|
||||
/// Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
|
||||
|
||||
@@ -25,12 +25,14 @@ namespace mfem
|
||||
namespace bin_io
|
||||
{
|
||||
|
||||
/// Write 'value' to stream.
|
||||
template<typename T>
|
||||
inline void write(std::ostream& os, T value)
|
||||
{
|
||||
os.write((char*) &value, sizeof(T));
|
||||
}
|
||||
|
||||
/// Read a value from the stream and return it.
|
||||
template<typename T>
|
||||
inline T read(std::istream& is)
|
||||
{
|
||||
|
||||
+61
-36
@@ -47,69 +47,91 @@ public:
|
||||
bool Root() const { return world_rank == 0; }
|
||||
};
|
||||
|
||||
|
||||
/** The shared entities (e.g. vertices, faces and edges) are split into groups,
|
||||
each group determined by the set of participating processors. They are
|
||||
numbered locally in lproc. Assumptions:
|
||||
- group 0 is the 'local' group
|
||||
- groupmaster_lproc[0] = 0
|
||||
- lproc_proc[0] = MyRank */
|
||||
class GroupTopology
|
||||
{
|
||||
private:
|
||||
MPI_Comm MyComm;
|
||||
|
||||
/* The shared entities (e.g. vertices, faces and edges) are split into
|
||||
groups, each group determined by the set of participating processors.
|
||||
They are numbered locally in lproc. Assumptions:
|
||||
- group 0 is the 'local' group
|
||||
- groupmaster_lproc[0] = 0
|
||||
- lproc_proc[0] = MyRank */
|
||||
|
||||
// Neighbor ids (lproc) in each group.
|
||||
/// Neighbor ids (lproc) in each group.
|
||||
Table group_lproc;
|
||||
// Master neighbor id for each group.
|
||||
/// Master neighbor id for each group.
|
||||
Array<int> groupmaster_lproc;
|
||||
// MPI rank of each neighbor.
|
||||
/// MPI rank of each neighbor.
|
||||
Array<int> lproc_proc;
|
||||
// Group --> Group number in the master.
|
||||
/// Group --> Group number in the master.
|
||||
Array<int> group_mgroup;
|
||||
|
||||
void ProcToLProc();
|
||||
|
||||
public:
|
||||
/// Constructor with the MPI communicator = 0.
|
||||
GroupTopology() : MyComm(0) {}
|
||||
|
||||
/// Constructor given the MPI communicator 'comm'.
|
||||
GroupTopology(MPI_Comm comm) { MyComm = comm; }
|
||||
|
||||
/// Copy constructor
|
||||
GroupTopology(const GroupTopology >);
|
||||
|
||||
/// Set the MPI communicator to 'comm'.
|
||||
void SetComm(MPI_Comm comm) { MyComm = comm; }
|
||||
|
||||
/// Return the MPI communicator.
|
||||
MPI_Comm GetComm() const { return MyComm; }
|
||||
|
||||
/// Return the MPI rank within this object's communicator.
|
||||
int MyRank() const { int r; MPI_Comm_rank(MyComm, &r); return r; }
|
||||
|
||||
/// Return the number of MPI ranks within this object's communicator.
|
||||
int NRanks() const { int s; MPI_Comm_size(MyComm, &s); return s; }
|
||||
|
||||
/// Set up the group topology given the list of sets of shared entities.
|
||||
void Create(ListOfIntegerSets &groups, int mpitag);
|
||||
|
||||
/// Return the number of groups.
|
||||
int NGroups() const { return group_lproc.Size(); }
|
||||
// return the number of neighbors including the local processor
|
||||
|
||||
/// Return the number of neighbors including the local processor.
|
||||
int GetNumNeighbors() const { return lproc_proc.Size(); }
|
||||
|
||||
/// Return the MPI rank of neighbor 'i'.
|
||||
int GetNeighborRank(int i) const { return lproc_proc[i]; }
|
||||
// am I master for group 'g'?
|
||||
|
||||
/// Return true if I am master for group 'g'.
|
||||
bool IAmMaster(int g) const { return (groupmaster_lproc[g] == 0); }
|
||||
// return the neighbor index of the group master for a given group.
|
||||
// neighbor 0 is the local processor
|
||||
|
||||
/** @brief Return the neighbor index of the group master for a given group.
|
||||
Neighbor 0 is the local processor. */
|
||||
int GetGroupMaster(int g) const { return groupmaster_lproc[g]; }
|
||||
// return the rank of the group master for a given group
|
||||
|
||||
/// Return the rank of the group master for group 'g'.
|
||||
int GetGroupMasterRank(int g) const
|
||||
{ return lproc_proc[groupmaster_lproc[g]]; }
|
||||
// for a given group return the group number in the master
|
||||
|
||||
/// Return the group number in the master for group 'g'.
|
||||
int GetGroupMasterGroup(int g) const { return group_mgroup[g]; }
|
||||
// get the number of processors in a group
|
||||
|
||||
/// Get the number of processors in a group
|
||||
int GetGroupSize(int g) const { return group_lproc.RowSize(g); }
|
||||
// return a pointer to a list of neighbors for a given group.
|
||||
// neighbor 0 is the local processor
|
||||
|
||||
/** @brief Return a pointer to a list of neighbors for a given group.
|
||||
Neighbor 0 is the local processor */
|
||||
const int *GetGroup(int g) const { return group_lproc.GetRow(g); }
|
||||
|
||||
/// Save the data in a stream.
|
||||
void Save(std::ostream &out) const;
|
||||
|
||||
/// Load the data from a stream.
|
||||
void Load(std::istream &in);
|
||||
|
||||
/// Copy
|
||||
/// Copy the internal data to the external 'copy'.
|
||||
void Copy(GroupTopology & copy) const;
|
||||
|
||||
virtual ~GroupTopology() {}
|
||||
@@ -186,9 +208,8 @@ public:
|
||||
void GetNeighborLDofTable(Table &nbr_ldof) const;
|
||||
|
||||
/** @brief Data structure on which we define reduce operations.
|
||||
|
||||
The data is associated with (and the operation is performed on) one group
|
||||
at a time. */
|
||||
The data is associated with (and the operation is performed on) one
|
||||
group at a time. */
|
||||
template <class T> struct OpData
|
||||
{
|
||||
int nldofs, nb;
|
||||
@@ -322,9 +343,10 @@ struct VarMessage
|
||||
std::string data;
|
||||
MPI_Request send_request;
|
||||
|
||||
/** Non-blocking send to processor 'rank'. Returns immediately. Completion
|
||||
(as tested by MPI_Wait/Test) does not mean the message was received --
|
||||
it may be on its way or just buffered locally. */
|
||||
/** @brief Non-blocking send to processor 'rank'.
|
||||
Returns immediately. Completion (as tested by MPI_Wait/Test) does not
|
||||
mean the message was received -- it may be on its way or just buffered
|
||||
locally. */
|
||||
void Isend(int rank, MPI_Comm comm)
|
||||
{
|
||||
Encode(rank);
|
||||
@@ -332,8 +354,9 @@ struct VarMessage
|
||||
&send_request);
|
||||
}
|
||||
|
||||
/** Non-blocking synchronous send to processor 'rank'. Returns immediately.
|
||||
Completion (MPI_Wait/Test) means that the message was received. */
|
||||
/** @brief Non-blocking synchronous send to processor 'rank'.
|
||||
Returns immediately. Completion (MPI_Wait/Test) means that the message
|
||||
was received. */
|
||||
void Issend(int rank, MPI_Comm comm)
|
||||
{
|
||||
Encode(rank);
|
||||
@@ -362,8 +385,8 @@ struct VarMessage
|
||||
}
|
||||
}
|
||||
|
||||
/** Return true if all messages in the map container were sent, otherwise
|
||||
return false, without waiting. */
|
||||
/** @brief Return true if all messages in the map container were sent,
|
||||
otherwise return false, without waiting. */
|
||||
template<typename MapT>
|
||||
static bool TestAllSent(MapT& rank_msg)
|
||||
{
|
||||
@@ -381,7 +404,7 @@ struct VarMessage
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Blocking probe for incoming message of this type from any rank.
|
||||
/** @brief Blocking probe for incoming message of this type from any rank.
|
||||
Returns the rank and message size. */
|
||||
static void Probe(int &rank, int &size, MPI_Comm comm)
|
||||
{
|
||||
@@ -391,9 +414,9 @@ struct VarMessage
|
||||
MPI_Get_count(&status, MPI_BYTE, &size);
|
||||
}
|
||||
|
||||
/** Non-blocking probe for incoming message of this type from any rank.
|
||||
If there is an incoming message, returns true and sets 'rank' and 'size'.
|
||||
Otherwise returns false. */
|
||||
/** @brief Non-blocking probe for incoming message of this type from any
|
||||
rank. If there is an incoming message, returns true and sets 'rank' and
|
||||
'size'. Otherwise returns false. */
|
||||
static bool IProbe(int &rank, int &size, MPI_Comm comm)
|
||||
{
|
||||
int flag;
|
||||
@@ -421,7 +444,7 @@ struct VarMessage
|
||||
Decode(rank);
|
||||
}
|
||||
|
||||
/// Like Recv(), but throw away the messsage.
|
||||
/// Like Recv(), but throw away the message.
|
||||
void RecvDrop(int rank, int size, MPI_Comm comm)
|
||||
{
|
||||
data.resize(size);
|
||||
@@ -448,6 +471,8 @@ struct VarMessage
|
||||
}
|
||||
|
||||
VarMessage() : send_request(MPI_REQUEST_NULL) {}
|
||||
|
||||
/// Clear the message and associated request.
|
||||
void Clear() { data.clear(); send_request = MPI_REQUEST_NULL; }
|
||||
|
||||
virtual ~VarMessage()
|
||||
|
||||
+4
-4
@@ -77,19 +77,19 @@ void mfem_cuda_error(cudaError_t err, const char *expr, const char *func,
|
||||
const char *file, int line);
|
||||
#endif
|
||||
|
||||
/// Allocates device memory
|
||||
/// Allocates device memory and returns destination ptr.
|
||||
void* CuMemAlloc(void **d_ptr, size_t bytes);
|
||||
|
||||
/// Allocates managed device memory
|
||||
void* CuMallocManaged(void **d_ptr, size_t bytes);
|
||||
|
||||
/// Frees device memory
|
||||
/// Frees device memory and returns destination ptr.
|
||||
void* CuMemFree(void *d_ptr);
|
||||
|
||||
/// Copies memory from Host to Device
|
||||
/// Copies memory from Host to Device and returns destination ptr.
|
||||
void* CuMemcpyHtoD(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Host to Device
|
||||
/// Copies memory from Host to Device and returns destination ptr.
|
||||
void* CuMemcpyHtoDAsync(void *d_dst, const void *h_src, size_t bytes);
|
||||
|
||||
/// Copies memory from Device to Device
|
||||
|
||||
+35
-15
@@ -61,15 +61,11 @@ Device Device::device_singleton;
|
||||
bool Device::device_env = false;
|
||||
bool Device::mem_host_env = false;
|
||||
bool Device::mem_device_env = false;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
bool Device::use_umpire = true;
|
||||
#endif
|
||||
|
||||
Device::Device() : mode(Device::SEQUENTIAL),
|
||||
backends(Backend::CPU),
|
||||
destroy_mm(false),
|
||||
mpi_gpu_aware(false),
|
||||
host_mem_type(MemoryType::HOST),
|
||||
host_mem_class(MemoryClass::HOST),
|
||||
device_mem_type(MemoryType::HOST),
|
||||
device_mem_class(MemoryClass::HOST)
|
||||
Device::Device()
|
||||
{
|
||||
if (getenv("MFEM_MEMORY") && !mem_host_env && !mem_device_env)
|
||||
{
|
||||
@@ -135,7 +131,7 @@ Device::Device() : mode(Device::SEQUENTIAL),
|
||||
{
|
||||
MFEM_ABORT("Unknown memory backend!");
|
||||
}
|
||||
mm.Configure(host_mem_type, device_mem_type);
|
||||
mm.Configure(host_mem_type, device_mem_type, device_mem_type);
|
||||
}
|
||||
|
||||
if (getenv("MFEM_DEVICE"))
|
||||
@@ -165,6 +161,8 @@ Device::~Device()
|
||||
Get().host_mem_class = MemoryClass::HOST;
|
||||
Get().device_mem_type = MemoryType::HOST;
|
||||
Get().device_mem_class = MemoryClass::HOST;
|
||||
Get().device_temp_mem_type = MemoryType::HOST;
|
||||
Get().device_temp_mem_class = MemoryClass::HOST;
|
||||
}
|
||||
|
||||
void Device::Configure(const std::string &device, const int dev)
|
||||
@@ -260,6 +258,10 @@ void Device::Print(std::ostream &out)
|
||||
if (Device::Allows(Backend::DEVICE_MASK))
|
||||
{
|
||||
out << ',' << MemoryTypeName[static_cast<int>(device_mem_type)];
|
||||
if (device_temp_mem_type != device_mem_type)
|
||||
{
|
||||
out << ',' << MemoryTypeName[static_cast<int>(device_temp_mem_type)];
|
||||
}
|
||||
}
|
||||
out << std::endl;
|
||||
}
|
||||
@@ -272,7 +274,8 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
// If MFEM has been compiled with Umpire support, use it as the default
|
||||
if (!mem_host_env) { host_mem_type = MemoryType::HOST_UMPIRE; }
|
||||
// TODO TMS: temporary
|
||||
//if (!mem_host_env && use_umpire) { host_mem_type = MemoryType::HOST_UMPIRE; }
|
||||
#endif
|
||||
|
||||
// Enable the device memory type
|
||||
@@ -296,11 +299,16 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef MFEM_USE_UMPIRE
|
||||
device_mem_type = MemoryType::DEVICE;
|
||||
#else
|
||||
device_mem_type = MemoryType::DEVICE_UMPIRE;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
if (use_umpire)
|
||||
{
|
||||
device_mem_type = MemoryType::DEVICE_UMPIRE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
device_mem_type = MemoryType::DEVICE;
|
||||
}
|
||||
}
|
||||
}
|
||||
device_mem_class = MemoryClass::DEVICE;
|
||||
@@ -320,8 +328,20 @@ void Device::UpdateMemoryTypeAndClass()
|
||||
device_mem_type = MemoryType::DEVICE_DEBUG;
|
||||
}
|
||||
|
||||
// Setup device_temp_mem_{type,class}
|
||||
switch (device_mem_type)
|
||||
{
|
||||
case MemoryType::DEVICE_UMPIRE:
|
||||
device_temp_mem_type = MemoryType::DEVICE_TEMP_UMPIRE;
|
||||
break;
|
||||
default:
|
||||
device_temp_mem_type = device_mem_type;
|
||||
break;
|
||||
}
|
||||
device_temp_mem_class = device_mem_class;
|
||||
|
||||
// Update the memory manager with the new settings
|
||||
mm.Configure(host_mem_type, device_mem_type);
|
||||
mm.Configure(host_mem_type, device_mem_type, device_temp_mem_type);
|
||||
}
|
||||
|
||||
void Device::Enable()
|
||||
|
||||
+28
-16
@@ -119,20 +119,26 @@ private:
|
||||
|
||||
static bool device_env, mem_host_env, mem_device_env;
|
||||
static Device device_singleton;
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
static bool use_umpire;
|
||||
#endif
|
||||
|
||||
MODES mode;
|
||||
MODES mode{Device::SEQUENTIAL};
|
||||
int dev = 0; ///< Device ID of the configured device.
|
||||
int ngpu = -1; ///< Number of detected devices; -1: not initialized.
|
||||
unsigned long backends; ///< Bitwise-OR of all configured backends.
|
||||
unsigned long backends{Backend::CPU}; ///< Bitwise-OR of all configured backends.
|
||||
/// Set to true during configuration, except in 'device_singleton'.
|
||||
bool destroy_mm;
|
||||
bool mpi_gpu_aware;
|
||||
bool destroy_mm{false};
|
||||
bool mpi_gpu_aware{false};
|
||||
|
||||
MemoryType host_mem_type; ///< Current Host MemoryType
|
||||
MemoryClass host_mem_class; ///< Current Host MemoryClass
|
||||
MemoryType host_mem_type{MemoryType::HOST}; ///< Current Host MemoryType
|
||||
MemoryClass host_mem_class{MemoryClass::HOST}; ///< Current Host MemoryClass
|
||||
|
||||
MemoryType device_mem_type; ///< Current Device MemoryType
|
||||
MemoryClass device_mem_class; ///< Current Device MemoryClass
|
||||
MemoryType device_mem_type{MemoryType::HOST}; ///< Current Device MemoryType
|
||||
MemoryClass device_mem_class{MemoryClass::HOST}; ///< Current Device MemoryClass
|
||||
|
||||
MemoryType device_temp_mem_type{MemoryType::HOST}; ///< Current Device MemoryType
|
||||
MemoryClass device_temp_mem_class{MemoryClass::HOST}; ///< Current Device MemoryClass
|
||||
|
||||
char *device_option = NULL;
|
||||
Device(Device const&);
|
||||
@@ -173,14 +179,6 @@ public:
|
||||
@note This object should be destroyed after all other MFEM objects that
|
||||
use the Device are destroyed. */
|
||||
Device(const std::string &device, const int dev = 0)
|
||||
: mode(Device::SEQUENTIAL),
|
||||
backends(Backend::CPU),
|
||||
destroy_mm(false),
|
||||
mpi_gpu_aware(false),
|
||||
host_mem_type(MemoryType::HOST),
|
||||
host_mem_class(MemoryClass::HOST),
|
||||
device_mem_type(MemoryType::HOST),
|
||||
device_mem_class(MemoryClass::HOST)
|
||||
{ Configure(device, dev); }
|
||||
|
||||
/// Destructor.
|
||||
@@ -260,10 +258,24 @@ public:
|
||||
/** @deprecated Use GetDeviceMemoryClass() instead. */
|
||||
static inline MemoryClass GetMemoryClass() { return Get().device_mem_class; }
|
||||
|
||||
/** @brief Get the current Device Temporary MemoryType. This is the MemoryType used by
|
||||
MFEM classes when allocating temporary memory to be used with device kernels.
|
||||
*/
|
||||
static inline MemoryType GetDeviceTempMemoryType() { return Get().device_temp_mem_type; }
|
||||
|
||||
/** @brief Get the current Device Temporary MemoryClass. This is the MemoryClass used
|
||||
by MFEM device kernels when they need to access temporary Memory objects. */
|
||||
static inline MemoryClass GetDeviceTempMemoryClass() { return Get().device_temp_mem_class; }
|
||||
|
||||
static void SetGPUAwareMPI(const bool force = true)
|
||||
{ Get().mpi_gpu_aware = force; }
|
||||
|
||||
static bool GetGPUAwareMPI() { return Get().mpi_gpu_aware; }
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
static bool UseUmpire() { return Get().use_umpire; }
|
||||
static void UseUmpire(bool use) { Get().use_umpire = use; }
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -77,7 +77,7 @@ public:
|
||||
HashTable(const HashTable& other); // deep copy
|
||||
~HashTable();
|
||||
|
||||
/// Get item whose parents are p1, p2... Create it if it doesn't exist.
|
||||
/// Get item whose parents are 'p1', 'p2'... Create it if it doesn't exist.
|
||||
T* Get(int p1, int p2);
|
||||
T* Get(int p1, int p2, int p3, int p4 = -1 /* p4 optional */);
|
||||
|
||||
@@ -123,6 +123,7 @@ public:
|
||||
/// Return total size of allocated memory (tables plus items), in bytes.
|
||||
long MemoryUsage() const;
|
||||
|
||||
/// Write details of the memory usage to the mfem output stream.
|
||||
void PrintMemoryDetail() const;
|
||||
|
||||
class iterator : public Base::iterator
|
||||
|
||||
@@ -33,12 +33,21 @@ private:
|
||||
StackPart <Elem, Num> *TopPart, *TopFreePart;
|
||||
int UsedInTop, SSize;
|
||||
public:
|
||||
/// Construct an empty stack.
|
||||
Stack() { TopPart = TopFreePart = NULL; UsedInTop = Num; SSize = 0; }
|
||||
/// Return the number of elements on the stack.
|
||||
int Size() const { return SSize; }
|
||||
/// Push element 'E' on the stack.
|
||||
void Push (Elem E);
|
||||
/// Pop an element off the stack and return it.
|
||||
Elem Pop();
|
||||
/// Clear the elements off the stack.
|
||||
void Clear();
|
||||
|
||||
/// Swap the data in this stack with the data in @a other.
|
||||
void Swap(Stack<Elem, Num> &other);
|
||||
|
||||
/// Return the number of bytes used by the stack.
|
||||
size_t MemoryUsage() const;
|
||||
~Stack() { Clear(); }
|
||||
};
|
||||
|
||||
+118
-44
@@ -67,15 +67,19 @@ MemoryType MemoryManager::GetDualMemoryType_(MemoryType mt)
|
||||
{
|
||||
switch (mt)
|
||||
{
|
||||
case MemoryType::HOST: return MemoryType::DEVICE;
|
||||
// TODO TMS: temporary
|
||||
case MemoryType::HOST: return MemoryType::DEVICE_UMPIRE;
|
||||
case MemoryType::HOST_32: return MemoryType::DEVICE;
|
||||
case MemoryType::HOST_64: return MemoryType::DEVICE;
|
||||
case MemoryType::HOST_DEBUG: return MemoryType::DEVICE_DEBUG;
|
||||
case MemoryType::HOST_UMPIRE: return MemoryType::DEVICE_UMPIRE;
|
||||
//case MemoryType::HOST_UMPIRE: return MemoryType::DEVICE_UMPIRE;
|
||||
case MemoryType::MANAGED: return MemoryType::MANAGED;
|
||||
case MemoryType::DEVICE: return MemoryType::HOST;
|
||||
case MemoryType::DEVICE_DEBUG: return MemoryType::HOST_DEBUG;
|
||||
case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST_UMPIRE;
|
||||
//case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST_UMPIRE;
|
||||
case MemoryType::DEVICE_UMPIRE: return MemoryType::HOST;
|
||||
//case MemoryType::DEVICE_TEMP_UMPIRE: return MemoryType::HOST_UMPIRE;
|
||||
case MemoryType::DEVICE_TEMP_UMPIRE: return MemoryType::HOST;
|
||||
default: mfem_error("Unknown memory type!");
|
||||
}
|
||||
MFEM_VERIFY(false,"");
|
||||
@@ -88,6 +92,9 @@ static void MFEM_VERIFY_TYPES(const MemoryType h_mt, const MemoryType d_mt)
|
||||
MFEM_ASSERT(IsDeviceMemory(d_mt),"");
|
||||
const bool sync =
|
||||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST_UMPIRE && d_mt == MemoryType::DEVICE_TEMP_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST && d_mt == MemoryType::DEVICE_TEMP_UMPIRE) ||
|
||||
(h_mt == MemoryType::HOST_DEBUG && d_mt == MemoryType::DEVICE_DEBUG) ||
|
||||
(h_mt == MemoryType::MANAGED && d_mt == MemoryType::MANAGED) ||
|
||||
(h_mt == MemoryType::HOST_64 && d_mt == MemoryType::DEVICE) ||
|
||||
@@ -461,48 +468,96 @@ public:
|
||||
#ifndef MFEM_USE_UMPIRE
|
||||
class UmpireHostMemorySpace : public NoHostMemorySpace { };
|
||||
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
|
||||
class UmpireDeviceTempMemorySpace : public NoDeviceMemorySpace { };
|
||||
#else
|
||||
|
||||
// TODO TMS: replace with um.hasAllocatorId(int) when it exists
|
||||
bool UmpireHasId(const umpire::ResourceManager & rm, int id)
|
||||
{
|
||||
const auto & ids = rm.getAllocatorIds();
|
||||
return std::find(ids.begin(), ids.end(), id) != ids.end();
|
||||
}
|
||||
|
||||
/// The Umpire host memory space
|
||||
class UmpireHostMemorySpace : public HostMemorySpace
|
||||
{
|
||||
private:
|
||||
const char *name;
|
||||
umpire::ResourceManager &rm;
|
||||
umpire::Allocator h_allocator;
|
||||
umpire::strategy::AllocationStrategy *strat;
|
||||
bool owns_allocator{false};
|
||||
public:
|
||||
~UmpireHostMemorySpace() { h_allocator.release(); }
|
||||
UmpireHostMemorySpace():
|
||||
HostMemorySpace(),
|
||||
name(mm.GetUmpireAllocatorHostName()),
|
||||
rm(umpire::ResourceManager::getInstance()),
|
||||
h_allocator(rm.isAllocator(name)? rm.getAllocator(name):
|
||||
rm.makeAllocator<umpire::strategy::DynamicPool>
|
||||
(name, rm.getAllocator("HOST"))),
|
||||
strat(h_allocator.getAllocationStrategy()) { }
|
||||
// TODO: this only releases unused memory
|
||||
~UmpireHostMemorySpace() { if (owns_allocator) { h_allocator.release(); } }
|
||||
UmpireHostMemorySpace(): HostMemorySpace(),
|
||||
rm(umpire::ResourceManager::getInstance())
|
||||
{
|
||||
const int id = MemoryManager::GetUmpireHostAllocatorId();
|
||||
if (!UmpireHasId(rm, id))
|
||||
{
|
||||
h_allocator = rm.makeAllocator<umpire::strategy::DynamicPool>("MFEM_HOST",
|
||||
rm.getAllocator("HOST"));
|
||||
owns_allocator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
h_allocator = rm.getAllocator(id);
|
||||
}
|
||||
MemoryManager::SetUmpireHostAllocatorId(id);
|
||||
}
|
||||
void Alloc(void **ptr, size_t bytes) { *ptr = h_allocator.allocate(bytes); }
|
||||
void Dealloc(void *ptr) { h_allocator.deallocate(ptr); }
|
||||
void Insert(void *ptr, size_t bytes)
|
||||
{ rm.registerAllocation(ptr, {ptr, bytes, strat}); }
|
||||
{ mfem_error("UmpireHostMemorySpace::Insert is unsupported"); }
|
||||
};
|
||||
|
||||
/// The Umpire device memory space
|
||||
#ifdef MFEM_USE_CUDA
|
||||
class UmpireDeviceMemorySpace : public DeviceMemorySpace
|
||||
class UmpireDeviceMemorySpaceImpl : public DeviceMemorySpace
|
||||
{
|
||||
public:
|
||||
enum class AllocatorType { TEMPORARY, PERMANENT };
|
||||
private:
|
||||
const char *name;
|
||||
umpire::ResourceManager &rm;
|
||||
umpire::Allocator d_allocator;
|
||||
bool owns_allocator{false};
|
||||
|
||||
int SetupAllocator(int possible_id, const char * allocator_name)
|
||||
{
|
||||
if (!UmpireHasId(rm, possible_id))
|
||||
{
|
||||
d_allocator = rm.makeAllocator<umpire::strategy::DynamicPool>(allocator_name,
|
||||
rm.getAllocator("DEVICE"));
|
||||
owns_allocator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d_allocator = rm.getAllocator(possible_id);
|
||||
}
|
||||
|
||||
return d_allocator.getId();
|
||||
}
|
||||
public:
|
||||
~UmpireDeviceMemorySpace() { d_allocator.release(); }
|
||||
UmpireDeviceMemorySpace():
|
||||
DeviceMemorySpace(),
|
||||
name(mm.GetUmpireAllocatorDeviceName()),
|
||||
rm(umpire::ResourceManager::getInstance()),
|
||||
d_allocator(rm.isAllocator(name)? rm.getAllocator(name):
|
||||
rm.makeAllocator<umpire::strategy::DynamicPool>
|
||||
(name, rm.getAllocator("DEVICE"))) { }
|
||||
// TODO: this only releases unused memory
|
||||
~UmpireDeviceMemorySpaceImpl() { if (owns_allocator) { d_allocator.release(); } }
|
||||
UmpireDeviceMemorySpaceImpl(AllocatorType t): DeviceMemorySpace(),
|
||||
rm(umpire::ResourceManager::getInstance())
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case AllocatorType::PERMANENT:
|
||||
MemoryManager::SetUmpireDeviceAllocatorId(SetupAllocator(
|
||||
MemoryManager::GetUmpireDeviceAllocatorId(),
|
||||
"MFEM_DEVICE"));
|
||||
break;
|
||||
case AllocatorType::TEMPORARY:
|
||||
MemoryManager::SetUmpireDeviceTempAllocatorId(SetupAllocator(
|
||||
MemoryManager::GetUmpireDeviceTempAllocatorId(),
|
||||
"MFEM_DEVICE_TEMPORARY"));
|
||||
break;
|
||||
default:
|
||||
mfem_error("Unknown Umpire AllocatorType");
|
||||
}
|
||||
}
|
||||
void Alloc(Memory &base) { base.d_ptr = d_allocator.allocate(base.bytes); }
|
||||
void Dealloc(Memory &base) { d_allocator.deallocate(base.d_ptr); }
|
||||
void *HtoD(void *dst, const void *src, size_t bytes)
|
||||
@@ -536,8 +591,23 @@ public:
|
||||
//rm.copy(dst, const_cast<void*>(src), bytes); return dst;
|
||||
}
|
||||
};
|
||||
|
||||
class UmpireDeviceMemorySpace : public UmpireDeviceMemorySpaceImpl
|
||||
{
|
||||
public:
|
||||
UmpireDeviceMemorySpace() : UmpireDeviceMemorySpaceImpl(
|
||||
AllocatorType::PERMANENT) {}
|
||||
};
|
||||
|
||||
class UmpireDeviceTempMemorySpace : public UmpireDeviceMemorySpaceImpl
|
||||
{
|
||||
public:
|
||||
UmpireDeviceTempMemorySpace() : UmpireDeviceMemorySpaceImpl(
|
||||
AllocatorType::TEMPORARY) {}
|
||||
};
|
||||
#else
|
||||
class UmpireDeviceMemorySpace : public NoDeviceMemorySpace { };
|
||||
class UmpireDeviceTempMemorySpace : public NoDeviceMemorySpace { };
|
||||
#endif // MFEM_USE_CUDA
|
||||
#endif // MFEM_USE_UMPIRE
|
||||
|
||||
@@ -568,7 +638,7 @@ public:
|
||||
host[static_cast<int>(MT::HOST_64)] = new Aligned64HostMemorySpace();
|
||||
// HOST_DEBUG is delayed, as it reroutes signals
|
||||
host[static_cast<int>(MT::HOST_DEBUG)] = nullptr;
|
||||
host[static_cast<int>(MT::HOST_UMPIRE)] = new UmpireHostMemorySpace();
|
||||
host[static_cast<int>(MT::HOST_UMPIRE)] = nullptr;
|
||||
host[static_cast<int>(MT::MANAGED)] = new UvmHostMemorySpace();
|
||||
|
||||
// Filling the device memory backends, shifting with the device size
|
||||
@@ -610,8 +680,12 @@ public:
|
||||
private:
|
||||
HostMemorySpace* NewHostCtrl(const MemoryType mt)
|
||||
{
|
||||
if (mt == MT::HOST_DEBUG) { return new MmuHostMemorySpace(); }
|
||||
MFEM_ABORT("Unknown host memory controller!");
|
||||
switch (mt)
|
||||
{
|
||||
case MT::HOST_DEBUG: return new MmuHostMemorySpace();
|
||||
case MT::HOST_UMPIRE: return new UmpireHostMemorySpace();
|
||||
default: MFEM_ABORT("Unknown host memory controller!");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -620,6 +694,7 @@ private:
|
||||
switch (mt)
|
||||
{
|
||||
case MT::DEVICE_UMPIRE: return new UmpireDeviceMemorySpace();
|
||||
case MT::DEVICE_TEMP_UMPIRE: return new UmpireDeviceTempMemorySpace();
|
||||
case MT::DEVICE_DEBUG: return new MmuDeviceMemorySpace();
|
||||
case MT::DEVICE:
|
||||
{
|
||||
@@ -760,7 +835,7 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
const bool known = mm.IsKnown(h_ptr);
|
||||
const bool alias = mm.IsAlias(h_ptr);
|
||||
const bool check = known || ((flags & Mem::ALIAS) && alias);
|
||||
MFEM_VERIFY(check,"");
|
||||
MFEM_VERIFY(check,"Unknown host pointer: " << h_ptr);
|
||||
const internal::Memory &mem =
|
||||
(flags & Mem::ALIAS) ?
|
||||
*maps->aliases.at(h_ptr).mem : maps->memories.at(h_ptr);
|
||||
@@ -783,6 +858,7 @@ bool MemoryManager::MemoryClassCheck_(MemoryClass mc, void *h_ptr,
|
||||
MFEM_VERIFY(d_mt == MemoryType::DEVICE ||
|
||||
d_mt == MemoryType::DEVICE_DEBUG ||
|
||||
d_mt == MemoryType::DEVICE_UMPIRE ||
|
||||
d_mt == MemoryType::DEVICE_TEMP_UMPIRE ||
|
||||
d_mt == MemoryType::MANAGED,"");
|
||||
return true;
|
||||
}
|
||||
@@ -1262,22 +1338,15 @@ MemoryManager::MemoryManager() { Init(); }
|
||||
MemoryManager::~MemoryManager() { if (exists) { Destroy(); } }
|
||||
|
||||
void MemoryManager::Configure(const MemoryType host_mt,
|
||||
const MemoryType device_mt)
|
||||
const MemoryType device_mt,
|
||||
const MemoryType device_tmt)
|
||||
{
|
||||
Init();
|
||||
host_mem_type = host_mt;
|
||||
device_mem_type = device_mt;
|
||||
device_temp_mem_type = device_tmt;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
void MemoryManager::SetUmpireAllocatorNames(const char *h_name,
|
||||
const char *d_name)
|
||||
{
|
||||
h_umpire_name = h_name;
|
||||
d_umpire_name = d_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MemoryManager::Destroy()
|
||||
{
|
||||
MFEM_VERIFY(exists, "MemoryManager has already been destroyed!");
|
||||
@@ -1381,12 +1450,14 @@ MemoryManager mm;
|
||||
bool MemoryManager::exists = false;
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
const char* MemoryManager::h_umpire_name = "HOST";
|
||||
const char* MemoryManager::d_umpire_name = "DEVICE";
|
||||
int MemoryManager::h_umpire_id = -1;
|
||||
int MemoryManager::d_umpire_id = -1;
|
||||
int MemoryManager::d_umpire_temp_id = -1;
|
||||
#endif
|
||||
|
||||
MemoryType MemoryManager::host_mem_type = MemoryType::HOST;
|
||||
MemoryType MemoryManager::device_mem_type = MemoryType::HOST;
|
||||
MemoryType MemoryManager::device_temp_mem_type = MemoryType::HOST;
|
||||
|
||||
const char *MemoryTypeName[MemoryTypeSize] =
|
||||
{
|
||||
@@ -1403,11 +1474,14 @@ const char *MemoryTypeName[MemoryTypeSize] =
|
||||
#endif
|
||||
"device-debug",
|
||||
#if defined(MFEM_USE_CUDA)
|
||||
"cuda-umpire"
|
||||
"cuda-umpire",
|
||||
"cuda-umpire-temp"
|
||||
#elif defined(MFEM_USE_HIP)
|
||||
"hip-umpire"
|
||||
"hip-umpire",
|
||||
"hip-umpire-temp"
|
||||
#else
|
||||
"device-umpire"
|
||||
"device-umpire",
|
||||
"device-umpire-temp"
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
+42
-27
@@ -27,18 +27,19 @@ namespace mfem
|
||||
/// Memory types supported by MFEM.
|
||||
enum class MemoryType
|
||||
{
|
||||
HOST, ///< Host memory; using new[] and delete[]
|
||||
HOST_32, ///< Host memory; aligned at 32 bytes
|
||||
HOST_64, ///< Host memory; aligned at 64 bytes
|
||||
HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
|
||||
HOST_UMPIRE, ///< Host memory; using Umpire
|
||||
MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
|
||||
and *Free */
|
||||
DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
|
||||
DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
|
||||
"device-debug" pool */
|
||||
DEVICE_UMPIRE, ///< Device memory; using Umpire
|
||||
SIZE ///< Number of host and device memory types
|
||||
HOST, ///< Host memory; using new[] and delete[]
|
||||
HOST_32, ///< Host memory; aligned at 32 bytes
|
||||
HOST_64, ///< Host memory; aligned at 64 bytes
|
||||
HOST_DEBUG, ///< Host memory; allocated from a "host-debug" pool
|
||||
HOST_UMPIRE, ///< Host memory; using Umpire
|
||||
MANAGED, /**< Managed memory; using CUDA or HIP *MallocManaged
|
||||
and *Free */
|
||||
DEVICE, ///< Device memory; using CUDA or HIP *Malloc and *Free
|
||||
DEVICE_DEBUG, /**< Pseudo-device memory; allocated on host from a
|
||||
"device-debug" pool */
|
||||
DEVICE_UMPIRE, ///< Device memory; using Umpire
|
||||
DEVICE_TEMP_UMPIRE, ///< Temporary Device memory; using Umpire
|
||||
SIZE ///< Number of host and device memory types
|
||||
};
|
||||
|
||||
/// Static casts to 'int' and sizes of some useful memory types.
|
||||
@@ -61,7 +62,7 @@ enum class MemoryClass
|
||||
HOST_UMPIRE, MANAGED } */
|
||||
HOST_32, ///< Memory types: { HOST_32, HOST_64, HOST_DEBUG }
|
||||
HOST_64, ///< Memory types: { HOST_64, HOST_DEBUG }
|
||||
DEVICE, ///< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE, MANAGED }
|
||||
DEVICE, ///< Memory types: { DEVICE, DEVICE_DEBUG, DEVICE_UMPIRE, DEVICE_TEMP_UMPIRE, MANAGED }
|
||||
MANAGED ///< Memory types: { MANAGED }
|
||||
};
|
||||
|
||||
@@ -450,16 +451,16 @@ private:
|
||||
|
||||
template <std::size_t align_bytes, bool dummy = true> struct Alloc
|
||||
{
|
||||
#if __cplusplus < 201703L
|
||||
static inline T *New(std::size_t)
|
||||
{
|
||||
#if __cplusplus < 201703L
|
||||
// Generate an error in debug mode
|
||||
MFEM_ASSERT(false, "overaligned type cannot use MemoryType::HOST");
|
||||
return nullptr;
|
||||
#else
|
||||
return new T[size];
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static inline T *New(std::size_t size) { return new T[size]; }
|
||||
#endif
|
||||
};
|
||||
|
||||
#if __cplusplus < 201703L
|
||||
@@ -471,7 +472,9 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/// The memory manager class
|
||||
/** The MFEM memory manager class. Host-side pointers are inserted into this
|
||||
manager which keeps track of the associated device pointer, and where the
|
||||
data currently resides. */
|
||||
class MemoryManager
|
||||
{
|
||||
private:
|
||||
@@ -487,6 +490,9 @@ private:
|
||||
/// Device memory type set during the Setup.
|
||||
static MemoryType device_mem_type;
|
||||
|
||||
/// Device temporary memory type set during the Setup.
|
||||
static MemoryType device_temp_mem_type;
|
||||
|
||||
/// Allow to detect if a global memory manager instance exists.
|
||||
static bool exists;
|
||||
|
||||
@@ -495,8 +501,9 @@ private:
|
||||
|
||||
/// Host and device allocator names for Umpire.
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
static const char *h_umpire_name;
|
||||
static const char *d_umpire_name;
|
||||
static int h_umpire_id;
|
||||
static int d_umpire_id;
|
||||
static int d_umpire_temp_id;
|
||||
#endif
|
||||
|
||||
private: // Static methods used by the Memory<T> class
|
||||
@@ -578,7 +585,8 @@ private: // Static methods used by the Memory<T> class
|
||||
|
||||
private:
|
||||
|
||||
/// Insert a host address in the memory map
|
||||
/// Insert a host address @a h_ptr and size *a bytes in the memory map to be
|
||||
/// managed.
|
||||
void Insert(void *h_ptr, size_t bytes, MemoryType h_mt, MemoryType d_mt);
|
||||
|
||||
/// Insert a device and the host addresses in the memory map
|
||||
@@ -618,15 +626,21 @@ public:
|
||||
/// Initialize the memory manager.
|
||||
void Init();
|
||||
|
||||
/// Configure the Memory manager with given default host and device types
|
||||
/// Configure the Memory manager with given default host, device, and device temporary types
|
||||
/// This method will be called when configuring a device.
|
||||
void Configure(const MemoryType h_mt, const MemoryType d_mt);
|
||||
void Configure(const MemoryType h_mt, const MemoryType d_mt,
|
||||
const MemoryType d_tmt);
|
||||
|
||||
#ifdef MFEM_USE_UMPIRE
|
||||
/// Set the host and device UMpire allocator names
|
||||
void SetUmpireAllocatorNames(const char *h_name, const char *d_name);
|
||||
const char *GetUmpireAllocatorHostName() { return h_umpire_name; }
|
||||
const char *GetUmpireAllocatorDeviceName() { return d_umpire_name; }
|
||||
/// Set the host and device Umpire allocator ids
|
||||
static void SetUmpireHostAllocatorId(int h_id) { h_umpire_id = h_id; }
|
||||
static void SetUmpireDeviceAllocatorId(int d_id) { d_umpire_id = d_id; }
|
||||
static void SetUmpireDeviceTempAllocatorId(int d_id) { d_umpire_temp_id = d_id; }
|
||||
|
||||
/// Get the host and device Umpire allocator ids
|
||||
static int GetUmpireHostAllocatorId() { return h_umpire_id; }
|
||||
static int GetUmpireDeviceAllocatorId() { return d_umpire_id; }
|
||||
static int GetUmpireDeviceTempAllocatorId() { return d_umpire_temp_id; }
|
||||
#endif
|
||||
|
||||
/// Free all the device memories
|
||||
@@ -651,6 +665,7 @@ public:
|
||||
|
||||
static MemoryType GetHostMemoryType() { return host_mem_type; }
|
||||
static MemoryType GetDeviceMemoryType() { return device_mem_type; }
|
||||
static MemoryType GetDeviceTempMemoryType() { return device_temp_mem_type; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
+34
-4
@@ -68,11 +68,17 @@ private:
|
||||
static void WriteValue(const Option &opt, std::ostream &out);
|
||||
|
||||
public:
|
||||
|
||||
/// Construct a command line option parser with '_argc' and '_argv'.
|
||||
OptionsParser(int _argc, char *_argv[])
|
||||
: argc(_argc), argv(_argv)
|
||||
{
|
||||
error_type = error_idx = 0;
|
||||
}
|
||||
|
||||
/** @brief Add a boolean option and set 'var' to receive the value.
|
||||
Enable/disable tags are used to set the bool to true/false
|
||||
respectively. */
|
||||
void AddOption(bool *var, const char *enable_short_name,
|
||||
const char *enable_long_name, const char *disable_short_name,
|
||||
const char *disable_long_name, const char *description,
|
||||
@@ -83,18 +89,24 @@ public:
|
||||
options.Append(Option(DISABLE, var, disable_short_name, disable_long_name,
|
||||
description, required));
|
||||
}
|
||||
|
||||
/// Add an integer option and set 'var' to receive the value.
|
||||
void AddOption(int *var, const char *short_name, const char *long_name,
|
||||
const char *description, bool required = false)
|
||||
{
|
||||
options.Append(Option(INT, var, short_name, long_name, description,
|
||||
required));
|
||||
}
|
||||
|
||||
/// Add a double option and set 'var' to receive the value.
|
||||
void AddOption(double *var, const char *short_name, const char *long_name,
|
||||
const char *description, bool required = false)
|
||||
{
|
||||
options.Append(Option(DOUBLE, var, short_name, long_name, description,
|
||||
required));
|
||||
}
|
||||
|
||||
/// Add a string (char*) option and set 'var' to receive the value.
|
||||
void AddOption(const char **var, const char *short_name,
|
||||
const char *long_name, const char *description,
|
||||
bool required = false)
|
||||
@@ -102,6 +114,9 @@ public:
|
||||
options.Append(Option(STRING, var, short_name, long_name, description,
|
||||
required));
|
||||
}
|
||||
|
||||
/** Add an integer array (separated by spaces) option and set 'var' to
|
||||
receive the values. */
|
||||
void AddOption(Array<int> * var, const char *short_name,
|
||||
const char *long_name, const char *description,
|
||||
bool required = false)
|
||||
@@ -109,6 +124,9 @@ public:
|
||||
options.Append(Option(ARRAY, var, short_name, long_name, description,
|
||||
required));
|
||||
}
|
||||
|
||||
/** Add a vector (doubles separated by spaces) option and set 'var' to
|
||||
receive the values. */
|
||||
void AddOption(Vector * var, const char *short_name,
|
||||
const char *long_name, const char *description,
|
||||
bool required = false)
|
||||
@@ -117,16 +135,28 @@ public:
|
||||
required));
|
||||
}
|
||||
|
||||
/** Parse the command-line options. Note that this function expects all the
|
||||
options provided through the command line to have a corresponding
|
||||
AddOption. In particular, this function cannot be used for partial
|
||||
parsing. */
|
||||
/** @brief Parse the command-line options.
|
||||
Note that this function expects all the options provided through the
|
||||
command line to have a corresponding AddOption. In particular, this
|
||||
function cannot be used for partial parsing. */
|
||||
void Parse();
|
||||
|
||||
/// Return true if the command line options were parsed successfully.
|
||||
bool Good() const { return (error_type == 0); }
|
||||
|
||||
/// Return true if we are flagged to print the help message.
|
||||
bool Help() const { return (error_type == 1); }
|
||||
|
||||
/// Print the options
|
||||
void PrintOptions(std::ostream &out) const;
|
||||
|
||||
/// Print the error message
|
||||
void PrintError(std::ostream &out) const;
|
||||
|
||||
/// Print the help message
|
||||
void PrintHelp(std::ostream &out) const;
|
||||
|
||||
/// Print the usage message
|
||||
void PrintUsage(std::ostream &out) const;
|
||||
};
|
||||
|
||||
|
||||
+19
-5
@@ -26,27 +26,32 @@ private:
|
||||
Array<int> me;
|
||||
|
||||
public:
|
||||
/// Create an empty set.
|
||||
IntegerSet() { }
|
||||
|
||||
/// Create a copy of set 's'.
|
||||
IntegerSet(IntegerSet &s);
|
||||
|
||||
/// Create an integer set from a block of memory containing integer values
|
||||
/// ( like an array ).
|
||||
///
|
||||
/// n - length ( number of integers )
|
||||
/// p - pointer to block of memory containing the integer values
|
||||
/// Create an integer set from C-array 'p' of 'n' integers.
|
||||
IntegerSet(const int n, const int *p) { Recreate(n, p); }
|
||||
|
||||
/// Return the size of the set.
|
||||
int Size() { return me.Size(); }
|
||||
|
||||
/// Return a reference to the sorted array of all the set entries.
|
||||
operator Array<int>& () { return me; }
|
||||
|
||||
/// Return the value of the lowest element of the set.
|
||||
int PickElement() { return me[0]; }
|
||||
|
||||
/// Return the value of a random element of the set.
|
||||
int PickRandomElement();
|
||||
|
||||
/// Return 1 if the sets are equal and 0 otherwise.
|
||||
int operator==(IntegerSet &s);
|
||||
|
||||
/** @brief Create an integer set from C-array 'p' of 'n' integers.
|
||||
Overwrites any existing set data. */
|
||||
void Recreate(const int n, const int *p);
|
||||
};
|
||||
|
||||
@@ -58,16 +63,25 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
/// Return the number of integer sets in the list.
|
||||
int Size() { return TheList.Size(); }
|
||||
|
||||
/// Return the value of the first element of the ith set.
|
||||
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
|
||||
|
||||
/// Return a random value from the ith set in the list.
|
||||
int PickRandomElementInSet(int i) { return TheList[i]->PickRandomElement(); }
|
||||
|
||||
/** @brief Check to see if set 's' is in the list. If not append it to the
|
||||
end of the list. Returns the index of the list where set 's' can be
|
||||
found. */
|
||||
int Insert(IntegerSet &s);
|
||||
|
||||
/** Return the index of the list where set 's' can be found. Returns -1 if
|
||||
not found. */
|
||||
int Lookup(IntegerSet &s);
|
||||
|
||||
/// Write the list of sets into table 't'.
|
||||
void AsTable(Table &t);
|
||||
|
||||
~ListOfIntegerSets();
|
||||
|
||||
@@ -53,18 +53,25 @@ public:
|
||||
open(hostname, port);
|
||||
}
|
||||
|
||||
/** Attach a new socket descriptor to the socketbuf.
|
||||
Returns the old socket descriptor which is NOT closed. */
|
||||
/** @brief Attach a new socket descriptor to the socketbuf. Returns the old
|
||||
socket descriptor which is NOT closed. */
|
||||
virtual int attach(int sd);
|
||||
|
||||
/// Detach the current socket descriptor from the socketbuf.
|
||||
int detach() { return attach(-1); }
|
||||
|
||||
/** @brief Open a socket on the 'port' at 'hostname' and store the socket
|
||||
descriptor. Returns 0 if there is no error, otherwise returns -1. */
|
||||
virtual int open(const char hostname[], int port);
|
||||
|
||||
/// Close the current socket descriptor.
|
||||
virtual int close();
|
||||
|
||||
/// Returns the attached socket descriptor.
|
||||
int getsocketdescriptor() { return socket_descriptor; }
|
||||
|
||||
/** @brief Returns true if the socket is open and has a valid socket
|
||||
descriptor. Otherwise returns false. */
|
||||
bool is_open() { return (socket_descriptor >= 0); }
|
||||
|
||||
virtual ~socketbuf() { close(); }
|
||||
@@ -177,8 +184,8 @@ public:
|
||||
|
||||
bool gnutls_good() const { return status.good(); }
|
||||
|
||||
/** Attach a new socket descriptor to the socketbuf.
|
||||
Returns the old socket descriptor which is NOT closed. */
|
||||
/** Attach a new socket descriptor to the socketbuf. Returns the old socket
|
||||
descriptor which is NOT closed. */
|
||||
virtual int attach(int sd);
|
||||
|
||||
virtual int open(const char hostname[], int port);
|
||||
@@ -255,10 +262,13 @@ public:
|
||||
|
||||
socketbuf *rdbuf() { return buf__; }
|
||||
|
||||
/// Open the socket stream on 'port' at 'hostname'.
|
||||
int open(const char hostname[], int port);
|
||||
|
||||
/// Close the socketstream.
|
||||
int close() { return buf__->close(); }
|
||||
|
||||
/// True if the socketstream is open, false otherwise.
|
||||
bool is_open() { return buf__->is_open(); }
|
||||
|
||||
virtual ~socketstream();
|
||||
|
||||
@@ -52,7 +52,7 @@ void SortPairs (Pair<A, B> *pairs, int size)
|
||||
std::sort(pairs, pairs + size);
|
||||
}
|
||||
|
||||
|
||||
/// A triple of objects
|
||||
template <class A, class B, class C>
|
||||
class Triple
|
||||
{
|
||||
|
||||
+20
-1
@@ -25,7 +25,12 @@ public:
|
||||
int Column, Floor, Number;
|
||||
};
|
||||
|
||||
/// Symmetric 3D Table
|
||||
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
|
||||
stack of column, floor, number nodes. The number of the node is assigned by
|
||||
counting the nodes from zero as they are pushed into the table. Diagonals of
|
||||
any kind are not allowed so the row, column and floor must all be different
|
||||
for each node. Only one node is stored for all 6 symmetric entries that are
|
||||
indexable by unique triplets of row, column, and floor. */
|
||||
class STable3D
|
||||
{
|
||||
private:
|
||||
@@ -37,20 +42,34 @@ private:
|
||||
#endif
|
||||
|
||||
public:
|
||||
/// Construct the table with a total of 'nr' rows.
|
||||
explicit STable3D (int nr);
|
||||
|
||||
/** @brief Check to see if this entry is in the table and add it to the table
|
||||
if it is not there. Returns the number assigned to the table entry. */
|
||||
int Push (int r, int c, int f);
|
||||
|
||||
/// Return the number assigned to the table entry. Abort if it's not there.
|
||||
int operator() (int r, int c, int f) const;
|
||||
|
||||
/** Return the number assigned to the table entry. Return -1 if it's not
|
||||
there. */
|
||||
int Index (int r, int c, int f) const;
|
||||
|
||||
/** @brief Check to see if this entry is in the table and add it to the table
|
||||
if it is not there. The entry is addressed by the three smallest values
|
||||
of (r,c,f,t). Returns the number assigned to the table entry. */
|
||||
int Push4 (int r, int c, int f, int t);
|
||||
|
||||
/** @brief Return the number assigned to the table entry. The entry is
|
||||
addressed by the three smallest values of (r,c,f,t). Return -1 if it is
|
||||
not there. */
|
||||
int operator() (int r, int c, int f, int t) const;
|
||||
|
||||
/// Return the number of elements added to the table.
|
||||
int NumberOfElements() { return NElem; }
|
||||
|
||||
/// Print out all of the table elements.
|
||||
void Print(std::ostream &out = mfem::out) const;
|
||||
|
||||
~STable3D ();
|
||||
|
||||
@@ -192,7 +192,6 @@ Table * Mult (const Table &A, const Table &B);
|
||||
/** Data type STable. STable is similar to Table, but it's for symmetric
|
||||
connectivity, i.e. TYPE I is equivalent to TYPE II. In the first
|
||||
dimension we put the elements with smaller index. */
|
||||
|
||||
class STable : public Table
|
||||
{
|
||||
public:
|
||||
|
||||
+5
-4
@@ -24,6 +24,7 @@ namespace mfem
|
||||
|
||||
// Utilities for text parsing
|
||||
|
||||
/// Check if the stream starts with @a comment_char. If so skip it.
|
||||
inline void skip_comment_lines(std::istream &is, const char comment_char)
|
||||
{
|
||||
while (1)
|
||||
@@ -37,7 +38,7 @@ inline void skip_comment_lines(std::istream &is, const char comment_char)
|
||||
}
|
||||
}
|
||||
|
||||
// Check for, and remove, a trailing '\r'.
|
||||
/// Check for, and remove, a trailing '\\r' from and std::string.
|
||||
inline void filter_dos(std::string &line)
|
||||
{
|
||||
if (!line.empty() && *line.rbegin() == '\r')
|
||||
@@ -46,7 +47,7 @@ inline void filter_dos(std::string &line)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert an integer to a string
|
||||
/// Convert an integer to an std::string.
|
||||
inline std::string to_string(int i)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@@ -58,7 +59,7 @@ inline std::string to_string(int i)
|
||||
return out_str;
|
||||
}
|
||||
|
||||
// Convert an integer to a 0-padded string with the given number of 'digits'
|
||||
/// Convert an integer to a 0-padded string with the given number of @a digits
|
||||
inline std::string to_padded_string(int i, int digits)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@@ -66,7 +67,7 @@ inline std::string to_padded_string(int i, int digits)
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// Convert a string to an int
|
||||
/// Convert a string to an int
|
||||
inline int to_int(const std::string& str)
|
||||
{
|
||||
int i;
|
||||
|
||||
+19
-2
@@ -38,12 +38,29 @@ private:
|
||||
|
||||
public:
|
||||
StopWatch();
|
||||
|
||||
/// Clear the elapsed time on the stopwatch and restart it if it's running.
|
||||
void Clear();
|
||||
|
||||
/// Clear the elapsed time and start the stopwatch.
|
||||
void Start();
|
||||
|
||||
/// Stop the stopwatch.
|
||||
void Stop();
|
||||
|
||||
/// Return the time resolution available to the stopwatch.
|
||||
double Resolution();
|
||||
|
||||
/** Return the number of real seconds elapsed since the stopwatch was
|
||||
started. */
|
||||
double RealTime();
|
||||
|
||||
/** Return the number of user seconds elapsed since the stopwatch was
|
||||
started. */
|
||||
double UserTime();
|
||||
|
||||
/** Return the number of system seconds elapsed since the stopwatch was
|
||||
started. */
|
||||
double SystTime();
|
||||
~StopWatch();
|
||||
};
|
||||
@@ -51,10 +68,10 @@ public:
|
||||
|
||||
extern StopWatch tic_toc;
|
||||
|
||||
/// Start timing
|
||||
/// Start the tic_toc timer
|
||||
extern void tic();
|
||||
|
||||
/// End timing
|
||||
/// End timing and return the time from tic() to toc() in seconds.
|
||||
extern double toc();
|
||||
|
||||
}
|
||||
|
||||
@@ -15,13 +15,25 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Return the MFEM version number as a single integer.
|
||||
int GetVersion();
|
||||
|
||||
/// Return the MFEM major version number as an integer.
|
||||
int GetVersionMajor();
|
||||
|
||||
/// Return the MFEM minor version number as an integer.
|
||||
int GetVersionMinor();
|
||||
|
||||
/// Return the MFEM version patch number as an integer.
|
||||
int GetVersionPatch();
|
||||
|
||||
/// Return the MFEM version number as a string.
|
||||
const char *GetVersionStr();
|
||||
|
||||
/// Return the MFEM Git hash as a string.
|
||||
const char *GetGitStr();
|
||||
|
||||
/// Return the MFEM configuration as a string.
|
||||
const char *GetConfigStr();
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+10
-8
@@ -203,10 +203,10 @@ public:
|
||||
{
|
||||
mode |= std::ios_base::in;
|
||||
exceptions(std::ios_base::badbit);
|
||||
detail::static_method_holder::check_mode(filename, mode);
|
||||
// detail::static_method_holder::check_mode(filename, mode);
|
||||
std::ifstream::open(filename, mode);
|
||||
detail::static_method_holder::check_open(this, filename, mode);
|
||||
detail::static_method_holder::check_peek(this, filename, mode);
|
||||
// detail::static_method_holder::check_open(this, filename, mode);
|
||||
// detail::static_method_holder::check_peek(this, filename, mode);
|
||||
}
|
||||
}; // class ifstream
|
||||
|
||||
@@ -225,9 +225,9 @@ public:
|
||||
{
|
||||
mode |= std::ios_base::out;
|
||||
exceptions(std::ios_base::badbit);
|
||||
detail::static_method_holder::check_mode(filename, mode);
|
||||
// detail::static_method_holder::check_mode(filename, mode);
|
||||
std::ofstream::open(filename, mode);
|
||||
detail::static_method_holder::check_open(this, filename, mode);
|
||||
// detail::static_method_holder::check_open(this, filename, mode);
|
||||
}
|
||||
}; // class ofstream
|
||||
|
||||
@@ -246,10 +246,10 @@ public:
|
||||
{
|
||||
if (! (mode & std::ios_base::out)) { mode |= std::ios_base::in; }
|
||||
exceptions(std::ios_base::badbit);
|
||||
detail::static_method_holder::check_mode(filename, mode);
|
||||
// detail::static_method_holder::check_mode(filename, mode);
|
||||
std::fstream::open(filename, mode);
|
||||
detail::static_method_holder::check_open(this, filename, mode);
|
||||
detail::static_method_holder::check_peek(this, filename, mode);
|
||||
// detail::static_method_holder::check_open(this, filename, mode);
|
||||
// detail::static_method_holder::check_peek(this, filename, mode);
|
||||
}
|
||||
}; // class fstream
|
||||
|
||||
@@ -754,6 +754,7 @@ public:
|
||||
{
|
||||
rdbuf(_fs.rdbuf());
|
||||
}
|
||||
setstate(_fs.rdstate());
|
||||
exceptions(std::ios_base::badbit);
|
||||
}
|
||||
|
||||
@@ -781,6 +782,7 @@ public:
|
||||
#else
|
||||
rdbuf(_fs.rdbuf());
|
||||
#endif
|
||||
setstate(_fs.rdstate());
|
||||
exceptions(std::ios_base::badbit);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@ void BlockOperator::SetDiagonalBlock(int iblock, Operator *op, double c)
|
||||
|
||||
void BlockOperator::SetBlock(int iRow, int iCol, Operator *opt, double c)
|
||||
{
|
||||
if (owns_blocks && op(iRow, iCol))
|
||||
{
|
||||
delete op(iRow, iCol);
|
||||
}
|
||||
op(iRow, iCol) = opt;
|
||||
coef(iRow, iCol) = c;
|
||||
|
||||
@@ -148,6 +152,10 @@ void BlockDiagonalPreconditioner::SetDiagonalBlock(int iblock, Operator *opt)
|
||||
offsets[iblock+1] - offsets[iblock] == opt->Width(),
|
||||
"incompatible Operator dimensions");
|
||||
|
||||
if (owns_blocks && op[iblock])
|
||||
{
|
||||
delete op[iblock];
|
||||
}
|
||||
op[iblock] = opt;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,9 @@ public:
|
||||
//! Return a reference to block i,j
|
||||
Operator & GetBlock(int i, int j)
|
||||
{ MFEM_VERIFY(op(i,j), ""); return *op(i,j); }
|
||||
//! Return a reference to block i,j (const version)
|
||||
const Operator & GetBlock(int i, int j) const
|
||||
{ MFEM_VERIFY(op(i,j), ""); return *op(i,j); }
|
||||
//! Return the coefficient for block i,j
|
||||
double GetBlockCoef(int i, int j) const
|
||||
{ MFEM_VERIFY(op(i,j), ""); return coef(i,j); }
|
||||
@@ -85,8 +88,12 @@ public:
|
||||
|
||||
//! Return the row offsets for block starts
|
||||
Array<int> & RowOffsets() { return row_offsets; }
|
||||
//! Read only access to the row offsets for block starts
|
||||
const Array<int> & RowOffsets() const { return row_offsets; }
|
||||
//! Return the columns offsets for block starts
|
||||
Array<int> & ColOffsets() { return col_offsets; }
|
||||
//! Read only access to the columns offsets for block starts
|
||||
const Array<int> & ColOffsets() const { return col_offsets; }
|
||||
|
||||
/// Operator application
|
||||
virtual void Mult (const Vector & x, Vector & y) const;
|
||||
@@ -153,9 +160,16 @@ public:
|
||||
Operator & GetDiagonalBlock(int iblock)
|
||||
{ MFEM_VERIFY(op[iblock], ""); return *op[iblock]; }
|
||||
|
||||
//! Return a reference to block i,i (const version).
|
||||
const Operator & GetDiagonalBlock(int iblock) const
|
||||
{ MFEM_VERIFY(op[iblock], ""); return *op[iblock]; }
|
||||
|
||||
//! Return the offsets for block starts
|
||||
Array<int> & Offsets() { return offsets; }
|
||||
|
||||
//! Read only access to the offsets for block starts
|
||||
const Array<int> & Offsets() const { return offsets; }
|
||||
|
||||
/// Operator application
|
||||
virtual void Mult (const Vector & x, Vector & y) const;
|
||||
|
||||
|
||||
@@ -72,6 +72,9 @@ public:
|
||||
*/
|
||||
BlockVector(double *data, const Array<int> & bOffsets);
|
||||
|
||||
//! Return the number of blocks
|
||||
int NumBlocks() const { return numBlocks; }
|
||||
|
||||
//! Assignment operator. this and original must have the same block structure.
|
||||
BlockVector & operator=(const BlockVector & original);
|
||||
//! Set each entry of this equal to val
|
||||
|
||||
@@ -13,26 +13,6 @@
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
// Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree:
|
||||
// mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively.
|
||||
// Note: the same macros are defined in hypre.cpp and hypre_parser.cpp.
|
||||
#if MFEM_HYPRE_VERSION < 21400
|
||||
|
||||
#define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size)
|
||||
#define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size)
|
||||
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr)
|
||||
|
||||
#else // MFEM_HYPRE_VERSION >= 21400
|
||||
|
||||
// See the notes about hypre 2.14.0 in hypre.cpp
|
||||
#define mfem_hypre_TAlloc(type, size) \
|
||||
hypre_TAlloc(type, size, HYPRE_MEMORY_HOST)
|
||||
#define mfem_hypre_CTAlloc(type, size) \
|
||||
hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST)
|
||||
#define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST)
|
||||
|
||||
#endif // #if MFEM_HYPRE_VERSION < 21400
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include "vector.hpp"
|
||||
#include "matrix.hpp"
|
||||
#include "densemat.hpp"
|
||||
#include "kernels.hpp"
|
||||
#include "../general/forall.hpp"
|
||||
#include "../general/table.hpp"
|
||||
#include "../general/globals.hpp"
|
||||
|
||||
@@ -3272,6 +3274,15 @@ void DenseMatrixInverse::SetOperator(const Operator &op)
|
||||
Factor(*p);
|
||||
}
|
||||
|
||||
void DenseMatrixInverse::Mult(const double *x, double *y) const
|
||||
{
|
||||
for (int row = 0; row < height; row++)
|
||||
{
|
||||
y[row] = x[row];
|
||||
}
|
||||
lu.Solve(width, 1, y);
|
||||
}
|
||||
|
||||
void DenseMatrixInverse::Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
y = x;
|
||||
@@ -3500,4 +3511,198 @@ DenseTensor &DenseTensor::operator=(double c)
|
||||
return *this;
|
||||
}
|
||||
|
||||
void BatchLUFactor(DenseTensor &Mlu, Array<int> &P, const double TOL)
|
||||
{
|
||||
const int m = Mlu.SizeI();
|
||||
const int NE = Mlu.SizeK();
|
||||
P.SetSize(m*NE);
|
||||
|
||||
auto data_all = mfem::Reshape(Mlu.ReadWrite(), m, m, NE);
|
||||
auto ipiv_all = mfem::Reshape(P.Write(), m, NE);
|
||||
Array<bool> pivot_flag(1);
|
||||
pivot_flag[0] = true;
|
||||
bool *d_pivot_flag = pivot_flag.ReadWrite();
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
// pivoting
|
||||
{
|
||||
int piv = i;
|
||||
double a = fabs(data_all(piv,i,e));
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
const double b = fabs(data_all(j,i,e));
|
||||
if (b > a)
|
||||
{
|
||||
a = b;
|
||||
piv = j;
|
||||
}
|
||||
}
|
||||
ipiv_all(i,e) = piv;
|
||||
if (piv != i)
|
||||
{
|
||||
// swap rows i and piv in both L and U parts
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<double>(data_all(i,j,e), data_all(piv,j,e));
|
||||
}
|
||||
}
|
||||
} // pivot end
|
||||
|
||||
if (abs(data_all(i,i,e)) <= TOL)
|
||||
{
|
||||
d_pivot_flag[0] = false;
|
||||
}
|
||||
|
||||
const double a_ii_inv = 1.0 / data_all(i,i,e);
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data_all(j,i,e) *= a_ii_inv;
|
||||
}
|
||||
|
||||
for (int k = i+1; k < m; k++)
|
||||
{
|
||||
const double a_ik = data_all(i,k,e);
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data_all(j,k,e) -= a_ik * data_all(j,i,e);
|
||||
}
|
||||
}
|
||||
|
||||
} // m loop
|
||||
|
||||
});
|
||||
|
||||
MFEM_ASSERT(pivot_flag.HostRead()[0], "Batch LU factorization failed \n");
|
||||
}
|
||||
|
||||
void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X)
|
||||
{
|
||||
|
||||
const int m = Mlu.SizeI();
|
||||
const int NE = Mlu.SizeK();
|
||||
|
||||
auto data_all = mfem::Reshape(Mlu.Read(), m, m, NE);
|
||||
auto piv_all = mfem::Reshape(P.Read(), m, NE);
|
||||
auto x_all = mfem::Reshape(X.ReadWrite(), m, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
kernels::LUSolve(&data_all(0, 0,e), m, &piv_all(0, e), &x_all(0,e));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void BatchLUFactor(Vector &Minv,const int m,const int NE, Array<int> &P)
|
||||
{
|
||||
P.SetSize(m*NE);
|
||||
auto data_all = mfem::Reshape(Minv.ReadWrite(), m, m, NE);
|
||||
auto piv_all = mfem::Reshape(P.Write(), m, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
|
||||
double *data = &data_all(0,0,e);
|
||||
int *ipiv = &piv_all(0,e);
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
|
||||
// pivoting
|
||||
{
|
||||
int piv = i;
|
||||
double a = fabs(data[piv+i*m]);
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
const double b = fabs(data[j+i*m]);
|
||||
if (b > a)
|
||||
{
|
||||
a = b;
|
||||
piv = j;
|
||||
}
|
||||
}
|
||||
ipiv[i] = piv;
|
||||
if (piv != i)
|
||||
{
|
||||
// swap rows i and piv in both L and U parts
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<double>(data[i+j*m], data[piv+j*m]);
|
||||
}
|
||||
}
|
||||
}//pivot end
|
||||
|
||||
//Q: How to check for errors?
|
||||
//if (abs(data[i + i*m]) <= TOL)
|
||||
//{
|
||||
//return false; // failed
|
||||
//}
|
||||
|
||||
const double a_ii_inv = 1.0 / data[i+i*m];
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data[j+i*m] *= a_ii_inv;
|
||||
}
|
||||
|
||||
for (int k = i+1; k < m; k++)
|
||||
{
|
||||
const double a_ik = data[i+k*m];
|
||||
for (int j = i+1; j < m; j++)
|
||||
{
|
||||
data[j+k*m] -= a_ik * data[j+i*m];
|
||||
}
|
||||
}
|
||||
|
||||
}//m loop
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
void BatchLUSolve(Vector &Minv, int m, int NE,
|
||||
Array<int> &P, Vector &X)
|
||||
{
|
||||
|
||||
auto data_all = mfem::Reshape(Minv.Read(), m, m, NE);
|
||||
auto piv_all = mfem::Reshape(P.Read(), m, NE);
|
||||
auto x_all = mfem::Reshape(X.ReadWrite(), m, NE);
|
||||
|
||||
MFEM_FORALL(e, NE,
|
||||
{
|
||||
|
||||
const double *data = &data_all(0,0,e);
|
||||
const int *ipiv = &piv_all(0,e);
|
||||
double *x = &x_all(0,e);
|
||||
|
||||
// X <- P X
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
mfem::kernels::internal::Swap<double>(x[i], x[ipiv[i]]);
|
||||
}
|
||||
|
||||
// X <- L^{-1} X
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
const double x_j = x[j];
|
||||
for (int i = j+1; i < m; i++)
|
||||
{
|
||||
x[i] -= data[i+j*m] * x_j;
|
||||
}
|
||||
}
|
||||
|
||||
// X <- U^{-1} X
|
||||
for (int j = m-1; j >= 0; j--)
|
||||
{
|
||||
const double x_j = ( x[j] /= data[j+j*m] );
|
||||
for (int i = 0; i < j; i++)
|
||||
{
|
||||
x[i] -= data[i+j*m] * x_j;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
@@ -643,6 +643,9 @@ public:
|
||||
|
||||
virtual void SetOperator(const Operator &op);
|
||||
|
||||
/// Matrix vector multiplication with the inverse of dense matrix.
|
||||
void Mult(const double *x, double *y) const;
|
||||
|
||||
/// Matrix vector multiplication with the inverse of dense matrix.
|
||||
virtual void Mult(const Vector &x, Vector &y) const;
|
||||
|
||||
@@ -859,6 +862,32 @@ public:
|
||||
~DenseTensor() { tdata.Delete(); }
|
||||
};
|
||||
|
||||
/** @brief Compute the LU factorization of a batch of matrices
|
||||
|
||||
Factorize n matrices of size (m x m) stored in a dense tensor overwriting it
|
||||
with the LU factors. The factorization is such that L.U = Piv.A, where A is
|
||||
the original matrix and Piv is a permutation matrix represented by P.
|
||||
|
||||
@param [in, out] Mlu batch of square matrices - dimension m x m x n.
|
||||
@param [out] P array storing pivot information - dimension m x n.
|
||||
@param [in] TOL optional fuzzy comparison tolerance. Defaults to 0.0. */
|
||||
void BatchLUFactor(DenseTensor &Mlu, Array<int> &P, const double TOL = 0.0);
|
||||
|
||||
/** @brief Solve batch linear systems
|
||||
|
||||
Assuming L.U = P.A for n factored matrices (m x m), compute x <- A x, for n
|
||||
companion vectors.
|
||||
|
||||
@param [in] Mlu batch of LU factors for matrix M - dimension m x m x n.
|
||||
@param [in] P array storing pivot information - dimension m x n.
|
||||
@param [in, out] X vector storing right-hand side and then solution -
|
||||
dimension m x n. */
|
||||
void BatchLUSolve(const DenseTensor &Mlu, const Array<int> &P, Vector &X);
|
||||
|
||||
void BatchLUFactor(Vector &Minv,int m,int NE, Array<int> &P);
|
||||
|
||||
void BatchLUSolve(Vector &Minv, int m, int NE,
|
||||
Array<int> &P, Vector &X);
|
||||
|
||||
// Inline methods
|
||||
|
||||
|
||||
+1
-1
@@ -2719,7 +2719,7 @@ HypreGMRES::HypreGMRES(MPI_Comm comm) : precond(NULL)
|
||||
SetDefaultOptions();
|
||||
}
|
||||
|
||||
HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A)
|
||||
HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A), precond(NULL)
|
||||
{
|
||||
MPI_Comm comm;
|
||||
|
||||
|
||||
@@ -593,7 +593,8 @@ protected:
|
||||
if (dont(HAVE_I3b_p))
|
||||
{
|
||||
eval_state |= HAVE_I3b_p;
|
||||
I3b_p = sign_detJ*scalar_ops::pow(Get_I3b(), -2, 3);
|
||||
const scalar_t i3b = Get_I3b();
|
||||
I3b_p = sign_detJ*scalar_ops::pow(i3b, -2, 3);
|
||||
}
|
||||
return I3b_p;
|
||||
}
|
||||
|
||||
@@ -1376,6 +1376,45 @@ have_aa:
|
||||
return sqrt(fabs(aa))*mult; // take abs before we sort?
|
||||
}
|
||||
|
||||
|
||||
/// Assuming L.U = P.A for a factored matrix (m x m),
|
||||
// compute x <- A x
|
||||
//
|
||||
// @param [in] data LU factorization of A
|
||||
// @param [in] m square matrix height
|
||||
// @param [in] ipiv array storing pivot information
|
||||
// @param [in, out] x vector storing right-hand side and then solution
|
||||
MFEM_HOST_DEVICE
|
||||
inline void LUSolve(const double *data, const int m, const int *ipiv,
|
||||
double *x)
|
||||
{
|
||||
// X <- P X
|
||||
for (int i = 0; i < m; i++)
|
||||
{
|
||||
internal::Swap<double>(x[i], x[ipiv[i]]);
|
||||
}
|
||||
|
||||
// X <- L^{-1} X
|
||||
for (int j = 0; j < m; j++)
|
||||
{
|
||||
const double x_j = x[j];
|
||||
for (int i = j + 1; i < m; i++)
|
||||
{
|
||||
x[i] -= data[i + j * m] * x_j;
|
||||
}
|
||||
}
|
||||
|
||||
// X <- U^{-1} X
|
||||
for (int j = m - 1; j >= 0; j--)
|
||||
{
|
||||
const double x_j = (x[j] /= data[j + j * m]);
|
||||
for (int i = 0; i < j; i++)
|
||||
{
|
||||
x[i] -= data[i + j * m] * x_j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kernels
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ class Matrix : public Operator
|
||||
{
|
||||
friend class MatrixInverse;
|
||||
public:
|
||||
//// Defines matrix diagonal policy upon elimination of rows and/or columns.
|
||||
/// Defines matrix diagonal policy upon elimination of rows and/or columns.
|
||||
enum DiagonalPolicy
|
||||
{
|
||||
DIAG_ZERO, ///< Set the diagonal value to zero
|
||||
|
||||
+3
-3
@@ -492,7 +492,7 @@ protected:
|
||||
mutable Vector dq_;
|
||||
};
|
||||
|
||||
// First Order Symplectic Integration Algorithm
|
||||
/// First Order Symplectic Integration Algorithm
|
||||
class SIA1Solver : public SIASolver
|
||||
{
|
||||
public:
|
||||
@@ -500,7 +500,7 @@ public:
|
||||
void Step(Vector &q, Vector &p, double &t, double &dt);
|
||||
};
|
||||
|
||||
// Second Order Symplectic Integration Algorithm
|
||||
/// Second Order Symplectic Integration Algorithm
|
||||
class SIA2Solver : public SIASolver
|
||||
{
|
||||
public:
|
||||
@@ -508,7 +508,7 @@ public:
|
||||
void Step(Vector &q, Vector &p, double &t, double &dt);
|
||||
};
|
||||
|
||||
// Variable order Symplectic Integration Algorithm (orders 1-4)
|
||||
/// Variable order Symplectic Integration Algorithm (orders 1-4)
|
||||
class SIAVSolver : public SIASolver
|
||||
{
|
||||
public:
|
||||
|
||||
+162
-31
@@ -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,9 +144,11 @@ SparseMatrix::SparseMatrix(int nrows, int ncols, int rowsize)
|
||||
{
|
||||
I[i] = i * rowsize;
|
||||
}
|
||||
|
||||
InitCuSparse();
|
||||
}
|
||||
|
||||
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph, MemoryType mt)
|
||||
: AbstractSparseMatrix(mat.Height(), mat.Width())
|
||||
{
|
||||
if (mat.Finalized())
|
||||
@@ -129,8 +156,8 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
const int nnz = mat.I[height];
|
||||
if (copy_graph)
|
||||
{
|
||||
I.New(height+1, mat.I.GetMemoryType());
|
||||
J.New(nnz, mat.J.GetMemoryType());
|
||||
I.New(height+1, mt == MemoryType::SIZE ? mat.I.GetMemoryType() : mt);
|
||||
J.New(nnz, mt == MemoryType::SIZE ? mat.J.GetMemoryType() : mt);
|
||||
I.CopyFrom(mat.I, height+1);
|
||||
J.CopyFrom(mat.J, nnz);
|
||||
}
|
||||
@@ -141,7 +168,7 @@ SparseMatrix::SparseMatrix(const SparseMatrix &mat, bool copy_graph)
|
||||
I.ClearOwnerFlags();
|
||||
J.ClearOwnerFlags();
|
||||
}
|
||||
A.New(nnz, mat.A.GetMemoryType());
|
||||
A.New(nnz, mt == MemoryType::SIZE ? mat.A.GetMemoryType() : mt);
|
||||
A.CopyFrom(mat.A, nnz);
|
||||
|
||||
Rows = NULL;
|
||||
@@ -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
|
||||
@@ -494,24 +535,29 @@ void SparseMatrix::GetDiag(Vector & d) const
|
||||
|
||||
d.SetSize(height);
|
||||
|
||||
int j, end;
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
auto I = this->ReadI();
|
||||
auto J = this->ReadJ();
|
||||
auto A = this->ReadData();
|
||||
auto dd = d.Write();
|
||||
|
||||
end = I[i+1];
|
||||
for (j = I[i]; j < end; j++)
|
||||
MFEM_FORALL(i, height,
|
||||
{
|
||||
const int begin = I[i];
|
||||
const int end = I[i+1];
|
||||
int j;
|
||||
for (j = begin; j < end; j++)
|
||||
{
|
||||
if (J[j] == i)
|
||||
{
|
||||
d[i] = A[j];
|
||||
dd[i] = A[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == end)
|
||||
{
|
||||
d[i] = 0.;
|
||||
dd[i] = 0.;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Produces a DenseMatrix from a SparseMatrix
|
||||
@@ -587,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 space for kernel. 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 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();
|
||||
@@ -2145,31 +2247,46 @@ void SparseMatrix::DiagScale(const Vector &b, Vector &x, double sc) const
|
||||
{
|
||||
MFEM_VERIFY(Finalized(), "Matrix must be finalized.");
|
||||
|
||||
const int nnz = J.Capacity();
|
||||
|
||||
const bool use_dev = b.UseDevice() || x.UseDevice();
|
||||
|
||||
auto bp = b.Read(use_dev);
|
||||
auto xp = x.Write(use_dev);
|
||||
|
||||
auto Ap = Read(A, nnz);
|
||||
auto Ip = Read(I, height+1);
|
||||
auto Jp = Read(J, nnz);
|
||||
|
||||
bool scale = (sc != 1.0);
|
||||
for (int i = 0, j = 0; i < height; i++)
|
||||
MFEM_FORALL(i, height,
|
||||
{
|
||||
int end = I[i+1];
|
||||
for ( ; true; j++)
|
||||
int end = Ip[i+1];
|
||||
for (int j = Ip[i]; true; j++)
|
||||
{
|
||||
MFEM_VERIFY(j != end, "Couldn't find diagonal in row. i = " << i
|
||||
<< ", j = " << j
|
||||
<< ", I[i+1] = " << end );
|
||||
if (J[j] == i)
|
||||
if (j == end)
|
||||
{
|
||||
MFEM_VERIFY(std::abs(A[j]) > 0.0, "Diagonal " << j << " must be nonzero");
|
||||
//MFEM_ABORT_KERNEL("Diagonal not found in SparseMatrix::DiagScale");
|
||||
}
|
||||
if (Jp[j] == i)
|
||||
{
|
||||
if (!(std::abs(Ap[j]) > 0.0))
|
||||
{
|
||||
//MFEM_ABORT_KERNEL("Zero diagonal in SparseMatrix::DiagScale");
|
||||
}
|
||||
|
||||
if (scale)
|
||||
{
|
||||
x(i) = sc * b(i) / A[j];
|
||||
xp[i] = sc * bp[i] / Ap[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
x(i) = b(i) / A[j];
|
||||
xp[i] = bp[i] / Ap[j];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
j = end;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2749,6 +2866,10 @@ void SparseMatrix::Print(std::ostream & out, int _width) const
|
||||
return;
|
||||
}
|
||||
|
||||
// HostRead forces synchronization
|
||||
HostReadI();
|
||||
HostReadJ();
|
||||
HostReadData();
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
out << "[row " << i << "]\n";
|
||||
@@ -2938,6 +3059,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
|
||||
|
||||
+53
-3
@@ -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,33 @@ 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;
|
||||
#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. */
|
||||
@@ -113,11 +143,14 @@ public:
|
||||
/** If @a mat is finalized and @a copy_graph is false, the #I and #J arrays
|
||||
will use a shallow copy (copy the pointers only) without transferring
|
||||
ownership. */
|
||||
SparseMatrix(const SparseMatrix &mat, bool copy_graph = true);
|
||||
SparseMatrix(const SparseMatrix &mat, bool copy_graph = true, MemoryType mt = MemoryType::SIZE);
|
||||
|
||||
/// 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);
|
||||
@@ -573,11 +606,28 @@ public:
|
||||
void Swap(SparseMatrix &other);
|
||||
|
||||
/// 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; }
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, SparseMatrix const& mat)
|
||||
{
|
||||
mat.Print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
/// Applies f() to each element of the matrix (after it is finalized).
|
||||
void SparseMatrixFunction(SparseMatrix &S, double (*f)(double));
|
||||
|
||||
|
||||
@@ -24,6 +24,18 @@
|
||||
#error "SuperLUDist has been built with 64bit integers. This is not supported"
|
||||
#endif
|
||||
|
||||
#if SUPERLU_DIST_MAJOR_VERSION > 6 || \
|
||||
(SUPERLU_DIST_MAJOR_VERSION == 6 && SUPERLU_DIST_MINOR_VERSION > 2)
|
||||
#define ScalePermstruct_t dScalePermstruct_t
|
||||
#define LUstruct_t dLUstruct_t
|
||||
#define SOLVEstruct_t dSOLVEstruct_t
|
||||
#define ScalePermstructFree dScalePermstructFree
|
||||
#define Destroy_LU dDestroy_LU
|
||||
#define LUstructFree dLUstructFree
|
||||
#define LUstructInit dLUstructInit
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace mfem
|
||||
|
||||
+30
-3
@@ -281,21 +281,48 @@ public:
|
||||
/// v = median(v,lo,hi) entrywise. Implementation assumes lo <= hi.
|
||||
void median(const Vector &lo, const Vector &hi);
|
||||
|
||||
/// Extract entries listed in @a dofs to the output Vector @a elemvect.
|
||||
/** Negative dof values cause the -dof-1 position in @a elemvect to receive
|
||||
the -val in from this Vector. */
|
||||
void GetSubVector(const Array<int> &dofs, Vector &elemvect) const;
|
||||
|
||||
/// Extract entries listed in @a dofs to the output array @a elem_data.
|
||||
/** Negative dof values cause the -dof-1 position in @a elem_data to receive
|
||||
the -val in from this Vector. */
|
||||
void GetSubVector(const Array<int> &dofs, double *elem_data) const;
|
||||
|
||||
/// Set the entries listed in `dofs` to the given `value`.
|
||||
/// Set the entries listed in @a dofs to the given @a value.
|
||||
/** Negative dof values cause the -dof-1 position in this Vector to receive
|
||||
the -value. */
|
||||
void SetSubVector(const Array<int> &dofs, const double value);
|
||||
|
||||
/** @brief Set the entries listed in @a dofs to the values given in the @a
|
||||
elemvect Vector. Negative dof values cause the -dof-1 position in this
|
||||
Vector to receive the -val from @a elemvect. */
|
||||
void SetSubVector(const Array<int> &dofs, const Vector &elemvect);
|
||||
|
||||
/** @brief Set the entries listed in @a dofs to the values given the @a ,
|
||||
elem_data array. Negative dof values cause the -dof-1 position in this
|
||||
Vector to receive the -val from @a elem_data. */
|
||||
void SetSubVector(const Array<int> &dofs, double *elem_data);
|
||||
|
||||
/// Add (element) subvector to the vector.
|
||||
/** @brief Add elements of the @a elemvect Vector to the entries listed in @a
|
||||
dofs. Negative dof values cause the -dof-1 position in this Vector to add
|
||||
the -val from @a elemvect. */
|
||||
void AddElementVector(const Array<int> & dofs, const Vector & elemvect);
|
||||
|
||||
/** @brief Add elements of the @a elem_data array to the entries listed in @a
|
||||
dofs. Negative dof values cause the -dof-1 position in this Vector to add
|
||||
the -val from @a elem_data. */
|
||||
void AddElementVector(const Array<int> & dofs, double *elem_data);
|
||||
|
||||
/** @brief Add @a times the elements of the @a elemvect Vector to the entries
|
||||
listed in @a dofs. Negative dof values cause the -dof-1 position in this
|
||||
Vector to add the -a*val from @a elemvect. */
|
||||
void AddElementVector(const Array<int> & dofs, const double a,
|
||||
const Vector & elemvect);
|
||||
|
||||
/// Set all vector entries NOT in the 'dofs' array to the given 'val'.
|
||||
/// Set all vector entries NOT in the @a dofs Array to the given @a val.
|
||||
void SetSubVectorComplement(const Array<int> &dofs, const double val);
|
||||
|
||||
/// Prints vector to stream out.
|
||||
|
||||
@@ -120,7 +120,7 @@ EXAMPLE_TEST_DIRS := examples
|
||||
MINIAPP_SUBDIRS = common electromagnetics meshing navier performance tools toys nurbs gslib
|
||||
MINIAPP_DIRS := $(addprefix miniapps/,$(MINIAPP_SUBDIRS))
|
||||
MINIAPP_TEST_DIRS := $(filter-out %/common,$(MINIAPP_DIRS))
|
||||
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics tools toys)
|
||||
MINIAPP_USE_COMMON := $(addprefix miniapps/,electromagnetics meshing tools toys)
|
||||
|
||||
EM_DIRS = $(EXAMPLE_DIRS) $(MINIAPP_DIRS)
|
||||
|
||||
|
||||
+91
-22
@@ -911,20 +911,27 @@ FaceElementTransformations *Mesh::GetFaceElementTransformations(int FaceNo,
|
||||
// NC meshes: prepend slave edge/face transformation to Loc2
|
||||
if (Nonconforming() && IsSlaveFace(face_info))
|
||||
{
|
||||
ApplyLocalSlaveTransformation(FaceElemTr.Loc2.Transf, face_info);
|
||||
|
||||
if (face_type == Element::SEGMENT)
|
||||
{
|
||||
// flip Loc2 to match Loc1 and Face
|
||||
DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat();
|
||||
std::swap(pm(0,0), pm(0,1));
|
||||
std::swap(pm(1,0), pm(1,1));
|
||||
}
|
||||
ApplyLocalSlaveTransformation(FaceElemTr, face_info, false);
|
||||
}
|
||||
}
|
||||
|
||||
FaceElemTr.SetConfigurationMask(mask);
|
||||
|
||||
// This check can be useful for internal debugging, however it will fail on
|
||||
// periodic boundary faces, so we keep it disabled in general.
|
||||
#if 0
|
||||
#ifdef MFEM_DEBUG
|
||||
double dist = FaceElemTr.CheckConsistency();
|
||||
if (dist >= 1e-12)
|
||||
{
|
||||
mfem::out << "\nInternal error: face id = " << FaceNo
|
||||
<< ", dist = " << dist << '\n';
|
||||
FaceElemTr.CheckConsistency(1); // print coordinates
|
||||
MFEM_ABORT("internal error");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return &FaceElemTr;
|
||||
}
|
||||
|
||||
@@ -933,8 +940,8 @@ bool Mesh::IsSlaveFace(const FaceInfo &fi) const
|
||||
return fi.NCFace >= 0 && nc_faces_info[fi.NCFace].Slave;
|
||||
}
|
||||
|
||||
void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
|
||||
const FaceInfo &fi)
|
||||
void Mesh::ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
|
||||
const FaceInfo &fi, bool is_ghost)
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix composition;
|
||||
@@ -942,8 +949,34 @@ void Mesh::ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
|
||||
static DenseMatrix composition;
|
||||
#endif
|
||||
MFEM_ASSERT(fi.NCFace >= 0, "");
|
||||
transf.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
|
||||
transf.SetPointMat(composition);
|
||||
MFEM_ASSERT(nc_faces_info[fi.NCFace].Slave, "internal error");
|
||||
if (!is_ghost)
|
||||
{
|
||||
// side 1 -> child side, side 2 -> parent side
|
||||
IsoparametricTransformation < = FT.Loc2.Transf;
|
||||
LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
|
||||
// In 2D, we need to flip the point matrix since it is aligned with the
|
||||
// parent side.
|
||||
if (Dim == 2)
|
||||
{
|
||||
// swap points (columns) 0 and 1
|
||||
std::swap(composition(0,0), composition(0,1));
|
||||
std::swap(composition(1,0), composition(1,1));
|
||||
}
|
||||
LT.SetPointMat(composition);
|
||||
}
|
||||
else // is_ghost == true
|
||||
{
|
||||
// side 1 -> parent side, side 2 -> child side
|
||||
IsoparametricTransformation < = FT.Loc1.Transf;
|
||||
LT.Transform(*nc_faces_info[fi.NCFace].PointMatrix, composition);
|
||||
// In 2D, there is no need to flip the point matrix since it is already
|
||||
// aligned with the parent side, see also ParNCMesh::GetFaceNeighbors.
|
||||
// In 3D the point matrix was flipped during construction in
|
||||
// ParNCMesh::GetFaceNeighbors and due to that it is already aligned with
|
||||
// the parent side.
|
||||
LT.SetPointMat(composition);
|
||||
}
|
||||
}
|
||||
|
||||
FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
|
||||
@@ -988,7 +1021,21 @@ void Mesh::GetFaceInfos(int Face, int *Inf1, int *Inf2) const
|
||||
|
||||
Geometry::Type Mesh::GetFaceGeometryType(int Face) const
|
||||
{
|
||||
return (Dim == 1) ? Geometry::POINT : faces[Face]->GetGeometryType();
|
||||
switch (Dim)
|
||||
{
|
||||
case 1: return Geometry::POINT;
|
||||
case 2: return Geometry::SEGMENT;
|
||||
case 3:
|
||||
if (Face < NumOfFaces) // local (non-ghost) face
|
||||
{
|
||||
return faces[Face]->GetGeometryType();
|
||||
}
|
||||
// ghost face
|
||||
const int nc_face_id = faces_info[Face].NCFace;
|
||||
MFEM_ASSERT(nc_face_id >= 0, "parent ghost faces are not supported");
|
||||
return faces[nc_faces_info[nc_face_id].MasterFace]->GetGeometryType();
|
||||
}
|
||||
return Geometry::INVALID;
|
||||
}
|
||||
|
||||
Element::Type Mesh::GetFaceElementType(int Face) const
|
||||
@@ -3286,7 +3333,7 @@ void Mesh::Loader(std::istream &input, int generate_edges,
|
||||
}
|
||||
else if (mesh_type == "$MeshFormat") // Gmsh
|
||||
{
|
||||
ReadGmshMesh(input);
|
||||
ReadGmshMesh(input, curved, read_gf);
|
||||
}
|
||||
else if
|
||||
((mesh_type.size() > 2 &&
|
||||
@@ -5261,7 +5308,10 @@ void Mesh::GenerateNCFaceInfo()
|
||||
|
||||
slave_fi.Elem2No = master_fi.Elem1No;
|
||||
slave_fi.Elem2Inf = 64 * master_nc.MasterFace; // get lf no. stored above
|
||||
// NOTE: orientation part of Elem2Inf is encoded in the point matrix
|
||||
// NOTE: In 3D, the orientation part of Elem2Inf is encoded in the point
|
||||
// matrix. In 2D, the point matrix has the orientation of the parent
|
||||
// edge, so its columns need to be flipped when applying it, see
|
||||
// ApplyLocalSlaveTransformation.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5768,6 +5818,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
|
||||
// Check for empty partitionings (a "feature" in METIS)
|
||||
{
|
||||
Array< Pair<int,int> > psize(nparts);
|
||||
int empty_parts;
|
||||
for (i = 0; i < nparts; i++)
|
||||
{
|
||||
psize[i].one = 0;
|
||||
@@ -5779,7 +5830,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
|
||||
psize[partitioning[i]].one++;
|
||||
}
|
||||
|
||||
int empty_parts = 0;
|
||||
empty_parts = 0;
|
||||
for (i = 0; i < nparts; i++)
|
||||
{
|
||||
if (psize[i].one == 0) { empty_parts++; }
|
||||
@@ -5787,7 +5838,7 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
|
||||
|
||||
// This code just split the largest partitionings in two.
|
||||
// Do we need to replace it with something better?
|
||||
if (empty_parts)
|
||||
while (empty_parts)
|
||||
{
|
||||
if (print_messages)
|
||||
{
|
||||
@@ -5818,6 +5869,24 @@ int *Mesh::GeneratePartitioning(int nparts, int part_method)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for empty partitionings again
|
||||
for (i = 0; i < nparts; i++)
|
||||
{
|
||||
psize[i].one = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < NumOfElements; i++)
|
||||
{
|
||||
psize[partitioning[i]].one++;
|
||||
}
|
||||
|
||||
empty_parts = 0;
|
||||
for (i = 0; i < nparts; i++)
|
||||
{
|
||||
if (psize[i].one == 0) { empty_parts++; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10455,17 +10524,17 @@ GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
|
||||
unsigned eval_flags = 0;
|
||||
if (flags & GeometricFactors::COORDINATES)
|
||||
{
|
||||
X.SetSize(vdim*NQ*NE);
|
||||
X.SetSize(vdim*NQ*NE, Device::GetDeviceTempMemoryType());
|
||||
eval_flags |= QuadratureInterpolator::VALUES;
|
||||
}
|
||||
if (flags & GeometricFactors::JACOBIANS)
|
||||
{
|
||||
J.SetSize(dim*vdim*NQ*NE);
|
||||
J.SetSize(dim*vdim*NQ*NE, Device::GetDeviceTempMemoryType());
|
||||
eval_flags |= QuadratureInterpolator::DERIVATIVES;
|
||||
}
|
||||
if (flags & GeometricFactors::DETERMINANTS)
|
||||
{
|
||||
detJ.SetSize(NQ*NE);
|
||||
detJ.SetSize(NQ*NE, Device::GetDeviceTempMemoryType());
|
||||
eval_flags |= QuadratureInterpolator::DETERMINANTS;
|
||||
}
|
||||
|
||||
@@ -10475,7 +10544,7 @@ GeometricFactors::GeometricFactors(const Mesh *mesh, const IntegrationRule &ir,
|
||||
qi->SetOutputLayout(QVectorLayout::byNODES);
|
||||
if (elem_restr)
|
||||
{
|
||||
Vector Enodes(vdim*ND*NE);
|
||||
Vector Enodes(vdim*ND*NE, Device::GetDeviceTempMemoryType());
|
||||
elem_restr->Mult(*nodes, Enodes);
|
||||
qi->Mult(Enodes, eval_flags, X, J, detJ);
|
||||
}
|
||||
|
||||
+9
-3
@@ -131,11 +131,16 @@ protected:
|
||||
// face. Elem2No is < 0 and -1-Elem2No is the index of the ghost
|
||||
// face-neighbor element that generated this slave ghost face. In this
|
||||
// case, Elem2Inf >= 0.
|
||||
// Relevant methods: GenerateFaces(), GenerateNCFaceInfo(),
|
||||
// ParNCMesh::GetFaceNeighbors(),
|
||||
// ParMesh::ExchangeFaceNbrData()
|
||||
|
||||
struct NCFaceInfo
|
||||
{
|
||||
bool Slave; // true if this is a slave face, false if master face
|
||||
int MasterFace; // if Slave, this is the index of the master face
|
||||
// If not Slave, 'MasterFace' is the local face index of this master face
|
||||
// as a face in the unique adjacent element.
|
||||
const DenseMatrix* PointMatrix; // if Slave, position within master face
|
||||
// (NOTE: PointMatrix points to a matrix owned by NCMesh.)
|
||||
|
||||
@@ -235,7 +240,7 @@ protected:
|
||||
bool &finalize_topo);
|
||||
void ReadNURBSMesh(std::istream &input, int &curved, int &read_gf);
|
||||
void ReadInlineMesh(std::istream &input, bool generate_edges = false);
|
||||
void ReadGmshMesh(std::istream &input);
|
||||
void ReadGmshMesh(std::istream &input, int &curved, int &read_gf);
|
||||
/* Note NetCDF (optional library) is used for reading cubit files */
|
||||
#ifdef MFEM_USE_NETCDF
|
||||
void ReadCubit(const char *filename, int &curved, int &read_gf);
|
||||
@@ -363,8 +368,9 @@ protected:
|
||||
|
||||
/** Used in GetFaceElementTransformations to account for the fact that a
|
||||
slave face occupies only a portion of its master face. */
|
||||
void ApplyLocalSlaveTransformation(IsoparametricTransformation &transf,
|
||||
const FaceInfo &fi);
|
||||
void ApplyLocalSlaveTransformation(FaceElementTransformations &FT,
|
||||
const FaceInfo &fi, bool is_ghost);
|
||||
|
||||
bool IsSlaveFace(const FaceInfo &fi) const;
|
||||
|
||||
/// Returns the orientation of "test" relative to "base"
|
||||
|
||||
+81
-2
@@ -887,7 +887,7 @@ void Mesh::ReadInlineMesh(std::istream &input, bool generate_edges)
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::ReadGmshMesh(std::istream &input)
|
||||
void Mesh::ReadGmshMesh(std::istream &input, int &curved, int &read_gf)
|
||||
{
|
||||
string buff;
|
||||
double version;
|
||||
@@ -1110,8 +1110,14 @@ void Mesh::ReadGmshMesh(std::istream &input)
|
||||
}
|
||||
case 4: // 4-node tetrahedron
|
||||
{
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
elements_3D.push_back(TetMemory.Alloc());
|
||||
elements_3D.back()->SetVertices(&vert_indices[0]);
|
||||
elements_3D.back()->SetAttribute(phys_domain);
|
||||
#else
|
||||
elements_3D.push_back(
|
||||
new Tetrahedron(&vert_indices[0], phys_domain));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 5: // 8-node hexahedron
|
||||
@@ -1195,8 +1201,14 @@ void Mesh::ReadGmshMesh(std::istream &input)
|
||||
}
|
||||
case 4: // 4-node tetrahedron
|
||||
{
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
elements_3D.push_back(TetMemory.Alloc());
|
||||
elements_3D.back()->SetVertices(&vert_indices[0]);
|
||||
elements_3D.back()->SetAttribute(phys_domain);
|
||||
#else
|
||||
elements_3D.push_back(
|
||||
new Tetrahedron(&vert_indices[0], phys_domain));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 5: // 8-node hexahedron
|
||||
@@ -1291,6 +1303,66 @@ void Mesh::ReadGmshMesh(std::istream &input)
|
||||
MFEM_CONTRACT_VAR(elem_domain);
|
||||
|
||||
} // section '$Elements'
|
||||
else if (buff == "$Periodic") // Reading master/slave node pairs
|
||||
{
|
||||
curved = 1;
|
||||
read_gf = 0;
|
||||
spaceDim = 3;
|
||||
|
||||
Array<int> v2v(NumOfVertices);
|
||||
for (int i = 0; i < v2v.Size(); i++)
|
||||
{
|
||||
v2v[i] = i;
|
||||
}
|
||||
int num_per_ent;
|
||||
int num_nodes;
|
||||
int slave, master;
|
||||
input >> num_per_ent;
|
||||
getline(input, buff); // Read end-of-line
|
||||
for (int i = 0; i < num_per_ent; i++)
|
||||
{
|
||||
getline(input, buff); // Read and ignore entity dimension and tags
|
||||
getline(input, buff); // Read and ignore affine mapping
|
||||
// Read master/slave vertex pairs
|
||||
input >> num_nodes;
|
||||
for (int j=0; j<num_nodes; j++)
|
||||
{
|
||||
input >> slave >> master;
|
||||
v2v[slave - 1] = master - 1;
|
||||
}
|
||||
getline(input, buff); // Read end-of-line
|
||||
}
|
||||
|
||||
// Convert nodes to discontinuous GridFunction
|
||||
this->SetCurvature(1, true, Dim, Ordering::byVDIM);
|
||||
|
||||
// Replace "slave" vertex indices in the element connectivity
|
||||
// with their corresponding "master" vertex indices.
|
||||
for (int i = 0; i < this->GetNE(); i++)
|
||||
{
|
||||
Element *el = this->GetElement(i);
|
||||
int *v = el->GetVertices();
|
||||
int nv = el->GetNVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
v[j] = v2v[v[j]];
|
||||
}
|
||||
}
|
||||
// Replace "slave" vertex indices in the boundary element connectivity
|
||||
// with their corresponding "master" vertex indices.
|
||||
for (int i = 0; i < this->GetNBE(); i++)
|
||||
{
|
||||
Element *el = this->GetBdrElement(i);
|
||||
int *v = el->GetVertices();
|
||||
int nv = el->GetNVertices();
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
v[j] = v2v[v[j]];
|
||||
}
|
||||
}
|
||||
this->RemoveUnusedVertices();
|
||||
this->RemoveInternalBoundaries();
|
||||
}
|
||||
} // we reach the end of the file
|
||||
}
|
||||
|
||||
@@ -1878,7 +1950,14 @@ void Mesh::ReadCubit(const char *filename, int &curved, int &read_gf)
|
||||
case (ELEMENT_TET4):
|
||||
case (ELEMENT_TET10):
|
||||
{
|
||||
elements[elcount] = new Tetrahedron(renumberedVertID,ebprop[iblk]);
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
elements[elcount] = TetMemory.Alloc();
|
||||
elements[elcount]->SetVertices(renumberedVertID);
|
||||
elements[elcount]->SetAttribute(ebprop[iblk]);
|
||||
#else
|
||||
elements[elcount] = new Tetrahedron(renumberedVertID,
|
||||
ebprop[iblk]);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case (ELEMENT_HEX8):
|
||||
|
||||
+72
-23
@@ -34,6 +34,8 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
|
||||
group_sedge(pmesh.group_sedge),
|
||||
group_stria(pmesh.group_stria),
|
||||
group_squad(pmesh.group_squad),
|
||||
glob_elem_offset(-1),
|
||||
glob_offset_sequence(-1),
|
||||
gtopo(pmesh.gtopo)
|
||||
{
|
||||
MyComm = pmesh.MyComm;
|
||||
@@ -92,7 +94,9 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
|
||||
int part_method)
|
||||
: gtopo(comm)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
{
|
||||
int *partitioning = NULL;
|
||||
Array<bool> activeBdrElem;
|
||||
@@ -833,6 +837,8 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
|
||||
: MyComm(pncmesh.MyComm)
|
||||
, NRanks(pncmesh.NRanks)
|
||||
, MyRank(pncmesh.MyRank)
|
||||
, glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(MyComm)
|
||||
, pncmesh(NULL)
|
||||
{
|
||||
@@ -841,6 +847,18 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
|
||||
have_face_nbr_data = false;
|
||||
}
|
||||
|
||||
void ParMesh::ComputeGlobalElementOffset() const
|
||||
{
|
||||
if (glob_offset_sequence != sequence) // mesh has changed
|
||||
{
|
||||
long local_elems = NumOfElements;
|
||||
MPI_Scan(&local_elems, &glob_elem_offset, 1, MPI_LONG, MPI_SUM, MyComm);
|
||||
glob_elem_offset -= local_elems;
|
||||
|
||||
glob_offset_sequence = sequence; // don't recalculate until refinement etc.
|
||||
}
|
||||
}
|
||||
|
||||
void ParMesh::ReduceMeshGen()
|
||||
{
|
||||
int loc_meshgen = meshgen;
|
||||
@@ -885,7 +903,9 @@ void ParMesh::FinalizeParTopo()
|
||||
}
|
||||
|
||||
ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
|
||||
: gtopo(comm)
|
||||
: glob_elem_offset(-1)
|
||||
, glob_offset_sequence(-1)
|
||||
, gtopo(comm)
|
||||
{
|
||||
MyComm = comm;
|
||||
MPI_Comm_size(MyComm, &NRanks);
|
||||
@@ -1062,6 +1082,8 @@ ParMesh::ParMesh(ParMesh *orig_mesh, int ref_factor, int ref_type)
|
||||
MyComm(orig_mesh->GetComm()),
|
||||
NRanks(orig_mesh->GetNRanks()),
|
||||
MyRank(orig_mesh->GetMyRank()),
|
||||
glob_elem_offset(-1),
|
||||
glob_offset_sequence(-1),
|
||||
gtopo(orig_mesh->gtopo),
|
||||
have_face_nbr_data(false),
|
||||
pncmesh(NULL)
|
||||
@@ -1299,6 +1321,20 @@ void ParMesh::Finalize(bool refine, bool fix_orientation)
|
||||
FinalizeParTopo();
|
||||
}
|
||||
|
||||
int ParMesh::GetLocalElementNum(long global_element_num) const
|
||||
{
|
||||
ComputeGlobalElementOffset();
|
||||
long local = global_element_num - glob_elem_offset;
|
||||
if (local < 0 || local >= NumOfElements) { return -1; }
|
||||
return local;
|
||||
}
|
||||
|
||||
long ParMesh::GetGlobalElementNum(int local_element_num) const
|
||||
{
|
||||
ComputeGlobalElementOffset();
|
||||
return glob_elem_offset + local_element_num;
|
||||
}
|
||||
|
||||
void ParMesh::DistributeAttributes(Array<int> &attr)
|
||||
{
|
||||
// Determine the largest attribute number across all processors
|
||||
@@ -2327,16 +2363,16 @@ Table *ParMesh::GetFaceToAllElementTable() const
|
||||
return face_elem;
|
||||
}
|
||||
|
||||
ElementTransformation* ParMesh::GetGhostFaceTransformation(
|
||||
void ParMesh::GetGhostFaceTransformation(
|
||||
FaceElementTransformations* FETr, Element::Type face_type,
|
||||
Geometry::Type face_geom)
|
||||
{
|
||||
// calculate composition of FETr->Loc1 and FETr->Elem1
|
||||
DenseMatrix &face_pm = FaceTransformation.GetPointMat();
|
||||
DenseMatrix &face_pm = FETr->GetPointMat();
|
||||
if (Nodes == NULL)
|
||||
{
|
||||
FETr->Elem1->Transform(FETr->Loc1.Transf.GetPointMat(), face_pm);
|
||||
FaceTransformation.SetFE(GetTransformationFEforElementType(face_type));
|
||||
FETr->SetFE(GetTransformationFEforElementType(face_type));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2352,15 +2388,23 @@ ElementTransformation* ParMesh::GetGhostFaceTransformation(
|
||||
FETr->Loc1.Transform(face_el->GetNodes(), eir);
|
||||
Nodes->GetVectorValues(*FETr->Elem1, eir, face_pm);
|
||||
#endif
|
||||
FaceTransformation.SetFE(face_el);
|
||||
FETr->SetFE(face_el);
|
||||
}
|
||||
return &FaceTransformation;
|
||||
}
|
||||
|
||||
FaceElementTransformations *ParMesh::
|
||||
GetSharedFaceTransformations(int sf, bool fill2)
|
||||
GetSharedFaceTransformations(int sf, bool fill2, bool direct)
|
||||
{
|
||||
int FaceNo = GetSharedFace(sf);
|
||||
//int FaceNo = GetSharedFace(sf);
|
||||
int FaceNo;
|
||||
if (direct)
|
||||
{
|
||||
FaceNo = sf;
|
||||
}
|
||||
else
|
||||
{
|
||||
FaceNo = GetSharedFace(sf);
|
||||
}
|
||||
|
||||
FaceInfo &face_info = faces_info[FaceNo];
|
||||
|
||||
@@ -2417,22 +2461,10 @@ GetSharedFaceTransformations(int sf, bool fill2)
|
||||
// adjust Loc1 or Loc2 of the master face if this is a slave face
|
||||
if (is_slave)
|
||||
{
|
||||
// is a ghost slave? -> master not a ghost -> choose Elem1 local transf
|
||||
// not a ghost slave? -> master is a ghost -> choose Elem2 local transf
|
||||
IsoparametricTransformation &loctr =
|
||||
is_ghost ? FaceElemTr.Loc1.Transf : FaceElemTr.Loc2.Transf;
|
||||
|
||||
if (is_ghost || fill2)
|
||||
{
|
||||
ApplyLocalSlaveTransformation(loctr, face_info);
|
||||
}
|
||||
|
||||
if (face_type == Element::SEGMENT && fill2)
|
||||
{
|
||||
// fix slave orientation in 2D: flip Loc2 to match Loc1 and Face
|
||||
DenseMatrix &pm = FaceElemTr.Loc2.Transf.GetPointMat();
|
||||
std::swap(pm(0,0), pm(0,1));
|
||||
std::swap(pm(1,0), pm(1,1));
|
||||
// is_ghost -> modify side 1, otherwise -> modify side 2:
|
||||
ApplyLocalSlaveTransformation(FaceElemTr, face_info, is_ghost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2442,6 +2474,23 @@ GetSharedFaceTransformations(int sf, bool fill2)
|
||||
GetGhostFaceTransformation(&FaceElemTr, face_type, face_geom);
|
||||
}
|
||||
|
||||
FaceElemTr.SetConfigurationMask(fill2 ? 31 : 21);
|
||||
|
||||
// This check can be useful for internal debugging, however it will fail on
|
||||
// periodic boundary faces, so we keep it disabled in general.
|
||||
#if 0
|
||||
#ifdef MFEM_DEBUG
|
||||
double dist = FaceElemTr.CheckConsistency();
|
||||
if (dist >= 1e-12)
|
||||
{
|
||||
mfem::out << "\nInternal error: face id = " << FaceNo
|
||||
<< ", dist = " << dist << ", rank = " << MyRank << '\n';
|
||||
FaceElemTr.CheckConsistency(1); // print coordinates
|
||||
MFEM_ABORT("internal error");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return &FaceElemTr;
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -78,6 +78,10 @@ protected:
|
||||
// sface ids: all triangles first, then all quads
|
||||
Array<int> sface_lface;
|
||||
|
||||
// glob_elem_offset + local element number defines a global element numbering
|
||||
mutable long glob_elem_offset, glob_offset_sequence;
|
||||
void ComputeGlobalElementOffset() const;
|
||||
|
||||
/// Create from a nonconforming mesh.
|
||||
ParMesh(const ParNCMesh &pncmesh);
|
||||
|
||||
@@ -103,7 +107,7 @@ protected:
|
||||
void GetFaceNbrElementTransformation(
|
||||
int i, IsoparametricTransformation *ElTr);
|
||||
|
||||
ElementTransformation* GetGhostFaceTransformation(
|
||||
void GetGhostFaceTransformation(
|
||||
FaceElementTransformations* FETr, Element::Type face_type,
|
||||
Geometry::Type face_geom);
|
||||
|
||||
@@ -231,6 +235,13 @@ public:
|
||||
int GetNRanks() const { return NRanks; }
|
||||
int GetMyRank() const { return MyRank; }
|
||||
|
||||
/** Map a global element number to a local element number. If the global
|
||||
element is not on this processor, return -1. */
|
||||
int GetLocalElementNum(long global_element_num) const;
|
||||
|
||||
/// Map a local element number to a global element number.
|
||||
long GetGlobalElementNum(int local_element_num) const;
|
||||
|
||||
GroupTopology gtopo;
|
||||
|
||||
// Face-neighbor elements and vertices
|
||||
@@ -280,9 +291,9 @@ public:
|
||||
|
||||
/** Get the FaceElementTransformations for the given shared face (edge 2D).
|
||||
In the returned object, 1 and 2 refer to the local and the neighbor
|
||||
elements, respectively. */
|
||||
elements, respectively. Use direct if sf is the face number */
|
||||
FaceElementTransformations *
|
||||
GetSharedFaceTransformations(int sf, bool fill2 = true);
|
||||
GetSharedFaceTransformations(int sf, bool fill2 = true, bool direct = false);
|
||||
|
||||
/// Return the number of shared faces (3D), edges (2D), vertices (1D)
|
||||
int GetNSharedFaces() const;
|
||||
|
||||
@@ -1263,6 +1263,8 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
|
||||
const DenseMatrix* pm = &sf.point_matrix;
|
||||
if (!sloc && Dim == 3)
|
||||
{
|
||||
// TODO: does this handle triangle faces correctly?
|
||||
|
||||
// ghost slave in 3D needs flipping orientation
|
||||
DenseMatrix* pm2 = new DenseMatrix(*pm);
|
||||
std::swap((*pm2)(0,1), (*pm2)(0,3));
|
||||
@@ -1282,6 +1284,14 @@ void ParNCMesh::GetFaceNeighbors(ParMesh &pmesh)
|
||||
// processor, but on the other it is the element containing the
|
||||
// master face. In the latter case we need to flip the pm.
|
||||
}
|
||||
else if (!sloc && Dim == 2)
|
||||
{
|
||||
fi.Elem2Inf ^= 1; // set orientation to 1
|
||||
// The point matrix (used to define "side 1" which is the same as
|
||||
// "parent side" in this case) does not require a flip since it
|
||||
// is aligned with the parent side, so NO flip is performed in
|
||||
// Mesh::ApplyLocalSlaveTransformation.
|
||||
}
|
||||
|
||||
MFEM_ASSERT(fi.NCFace < 0, "");
|
||||
fi.NCFace = pmesh.nc_faces_info.Size();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user